pax_global_header00006660000000000000000000000064141423130110014500gustar00rootroot0000000000000052 comment=45d8cd966c5e93880fbd10556215f3249aac28c0 minigalaxy-1.1.0/000077500000000000000000000000001414231301100136415ustar00rootroot00000000000000minigalaxy-1.1.0/.flake8000066400000000000000000000002021414231301100150060ustar00rootroot00000000000000[flake8] max-complexity = 10 max-line-length = 127 exclude = .git, build, data, debian, dist, *.egg-info minigalaxy-1.1.0/.flake8.soft000066400000000000000000000002501414231301100157630ustar00rootroot00000000000000[flake8] per-file-ignores = # Because of their nature, tests have a lot of long strings # Perhaps the situation can be improved in the future tests/*: E501 minigalaxy-1.1.0/.github/000077500000000000000000000000001414231301100152015ustar00rootroot00000000000000minigalaxy-1.1.0/.github/workflows/000077500000000000000000000000001414231301100172365ustar00rootroot00000000000000minigalaxy-1.1.0/.github/workflows/pythontests.yml000066400000000000000000000013031414231301100223620ustar00rootroot00000000000000name: Python tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: Set up Python 3.8 uses: actions/setup-python@v1 with: python-version: 3.8 - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements-testing.txt - name: Lint with flake8 run: | flake8 . --append-config=.flake8.soft --count --show-source --statistics - name: Lint with flake8 (strict, but non-fatal) run: | flake8 . --count --show-source --statistics --exit-zero - name: Run unit tests run: | python -m unittest tests/*.py minigalaxy-1.1.0/.gitignore000066400000000000000000000006571414231301100156410ustar00rootroot00000000000000venv/ __pycache__/ dist/ .idea/ *~ *.pyc *.egg-info/ *.swp .eggs/ data/mo/ data/po/minigalaxy.pot data/po/*.mo .project .pydevproject # Files generated when building the deb package .pybuild/ build/ debian/minigalaxy.6 debian/files debian/.debhelper/ debian/debhelper-build-stamp debian/minigalaxy/ debian/minigalaxy.substvars debian/minigalaxy.debhelper.log debian/minigalaxy.postinst.debhelper debian/minigalaxy.prerm.debhelper minigalaxy-1.1.0/CHANGELOG.md000066400000000000000000000177761414231301100154740ustar00rootroot00000000000000**1.1.0** - Improve integrity check after downloading (thanks to makson96) - Show an error showing Windows games cannot be enabled - Add properties menu for games where game specific actions can be made like setting launch options and opening the store page (thanks to Odelpasso and makson96) - Add a disk space check before downloading (thanks to SvdB-nonp and makson96) - Use a different color for the play button for installed games - Put installed games at the top of the list - Store saved installers in ``~/GOG Games/installer`` by default again (thanks to makson96) - Remember if the user had the installed filter enabled (thanks to makson96) - Extract Windows games in the background if Innoextract is available (thanks to makson96) - Extract Windows games in the background (thanks to Odelpasso) - Fix installing DLC for Windows games (thanks to makson96) - Fix an error showing if the user has no games (thanks to makson96) - Add option to hide games (thanks to TotalCaesar659) - Ask user if they are sure when logging out (thanks to TotalCaesar659) - Add a dark theme (thanks to TotalCaesar659) - Run post install script after installation. This fixes Full Throttle Remastered (thanks to makson96) - Fix games being shown twice - Fix crash when GOG is down (thanks to lmeunier) - Make the language configurable (thanks to TotalCaesar659 and zweif) - Add the following translations: - Czech (thanks to jakbuz23) - Finnish (thanks to heidiwenger and jonnelafin) - Italian (thanks to koraynilay) - Swedish (thanks to Newbytee) - Ukrainian (thanks to karaushu) - Update the following translations: - Dutch - German (thanks to zweif) - Norwegian Nynorsk (thanks to LordPilum) - Polish (thanks to ArturWroblewski) - Russian (thanks to TotalCaesar659) - Simplified Chinese (thanks to dummyx) - Spanish (thanks to LocalPinkRobin and advy99) - Turkish (thanks to fuzunspm) **1.0.2** - Fix updates sometimes not working - Fix some games always showing an update is available - Fix DLC not downloading (thanks to stephanlachnit) - Fix DLC update option not showing up (thanks to makson96) - Fix show store page button not showing anymore (thanks to makson96) - Fix missing thumbnails not being downloaded for already installed games (thanks to makson96) - Fix the login screen crashing in some cases (thanks to makson96) - Use the system's icon theme for icons used (thanks to stephanlachnit and makson96) **1.0.1** - Open maximized if the window was maximized when last closed (thanks to TotalCaesar659) - Kept installers are now stored in ~/.cache/minigalaxy/download - Fix about window displaying wrong version number - Fix show store page button not showing anymore (thanks to makson96) - Fix the download manager crashing when an installer has been damaged during downloading (thanks to makson96) - Fix games showing an update is available while the latest version is installed (thanks to makson96) - Fix loading the library taking a long time when many games are installed (thanks to makson96) - Fix Gex not launching - Add the following translations: - Swedish (thanks to Newbytee) - Update the following translations: - Polish (thanks to ArturWroblewski) - Russian (thanks to TotalCaesar659) **1.0.0** - Games can now be updated (thanks to mdgomes and makson96) - DLC can now be installed and updated (thanks to makson96) - The installed filter now also shows games which are downloading (thanks to makson96) - Fix crash on some systems where /usr/bin is linked to /bin (thanks to sgn) - Create new config file if old one is unreadable (thanks to SvdB-nonp) - Fix some Windows games not installing because of the directory name used (thanks to SvdB-nonp) - Fix some Windows games like Witcher 3 not launching because of the working directory not being set (thanks for kibun1) - Clean up installation files for cancelled downloads (thanks to SvdB-nonp) - Fix crash on flaky internet connection (thanks to makson96) - Use 755 permissions for all directories created by Minigalaxy - Remove cached files when cancelling a download (thanks to svdB-nonp) - Installed games should no longer be shown twice (thanks to makson96) - Add the following translations: - Simplified Chinese (thanks to dummyx) - Spanish (thanks to juanborda) - Update the following translations: - Brazilian Portuguese (thanks to EsdrasTarsis) - Dutch - French (thanks to Thomasb22) - German (thanks to BlindJerobine) - Norwegian Bokmål (thanks to kimmalmo) - Russian (thanks to protheory8) - Taiwanese Mandarin (thanks to s8321414) - Turkish (thanks to fuzunspm) **0.9.4** - Added the following translations: - Norwegian Nynorsk (thanks to LordPilum) - Russian (thanks to protheory8) - Updated the following translations: - Brazilian Portuguese (thanks to EsdrasTarsis) - French (thanks to Thomasb22) - German (thanks to BlindJerobine) - Norwegian Bokmål (thanks to kimmalmo) - Polish (thanks to ArturWroblewski) - Taiwanese Mandarin (thanks to s8321414) - Turkish (thanks to fuzunspm) - Added support for installing Windows games (with help from Odelpasso). - Added store page link to game menus (thanks to larslindq). - Fixed game directories being created without any spaces in the name (thanks to larslindq). - Fixed thumbnails not being downloaded for already installed games. - Fixed symlinks to libraries not being created correctly upon installation. - Made preparations for a Flathub package. - Added all contributors and translators to the about window. **0.9.3** - Added the following translations: - German (thanks to BlindJerobine) - Turkish (thanks to fuzunspm) - Brazilian Portuguese (thanks to EsdrasTarsis) - Norwegian Bokmål (thanks to kimmalmo) - Polish (thanks to ArturWroblewski) - French (thanks to thomansb22) - Added option to cancel downloads. - Changed the way games are downloaded to a queue instead of trying to download everything at once. - Added support option to game specific menus which open the GOG support page (thanks to BlindJerobine). - Ask for confirmation before uninstalling (thanks to Odelpasso). - Added option to display FPS in games (thanks to Odelpasso). - Downloads can now be resumed after having been cancelled before. - Installers are now verified before installing. - The active download is now resumed when restarting Minigalaxy. - Fixed issue with games not downloading. **0.9.2** - Added a button to installed games which allow you to: - Uninstall a game. - Open the directory in which the game is installed. - Added translation support. The following additional languages are now supported: - Dutch - Taiwanese Mandarin (thanks to s8321414) - German (thanks to BlindJerobine) - Added offline mode. - The system's Dosbox and Scummvm installations are now preferred over the ones bundled with games. - Improved game detection to check in all directories in the installation path. - Added the option to keep game installers (thanks to Odelpasso). - Added the option to disable staying logged in (thanks to Odelpasso). - The preferences menu now uses a file picker for setting the installation path (thanks to Odelpasso). - Startup time has been reduced. - Games which aren't installed are now grayed out. - Fixed FTL not being able to start. - Fixed issue with thumbnails sometimes not fully loading. - Fixed potential crash after logging in the first time. - Fixed close button on about window not working. **0.9.1** - Fixed crashes and freezes sometimes happening while downloading and installing games. - Fixed installation failing when the installation directory is not on same filesystem as ``/home``. - Fixed downloads crashing when the installation directory is changed or the refresh button is pressed. - Fixed changing installation directory not loading which games are installed in the new directory. - Fixed copyright file in deb package not being machine readable. - Moved binary to ``/usr/games`` in the deb package. - Add command line options ``--help``, ``--version`` and ``--reset``. The reset option will reset the cache and configuration. **0.9.0** - Initial release. minigalaxy-1.1.0/LICENSE000066400000000000000000001043741414231301100146570ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . minigalaxy-1.1.0/README.md000066400000000000000000000153231414231301100151240ustar00rootroot00000000000000# Minigalaxy A simple GOG client for Linux ![screenshot](screenshot.jpg?raw=true) ## Features The most important features of Minigalaxy: - Log in with your GOG account - Download the Linux games you own on GOG - Launch them In addition to that, Minigalaxy also allows you to: - Update your games - Install and update DLC - Select in which language you'd prefer to download your games - Change where games are installed - Search your GOG Linux library - Show all games or just the ones you've installed - View the error message if a game fails to launch - Enable displaying the FPS in games - Use the system's Scummvm or Dosbox installation - Install Windows games using Wine ## Supported languages Currently Minigalaxy can be displayed in the following languages: - Brazilian Portuguese - Czech - English - Dutch - French - Finnish - German - Italian - Norwegian Bokmål - Norwegian Nynorsk - Polish - Russian - Simplified Chinese - Spanish - Swedish - Taiwanese Mandarin - Turkish - Ukranian ## System requirements Minigalaxy should work on the following distributions: - Debian Buster (10.0) or newer - Ubuntu 18.10 or newer - Arch Linux - Manjaro - Fedora 31+ - openSUSE Tumbleweed - Gentoo - MX Linux 19 - Solus Minigalaxy does **not** ship for the following distributions because they do not contain the required version of PyGObject: - Ubuntu 18.04 - Linux Mint 19.3 - openSUSE 15.1 Other Linux distributions may work as well. Minigalaxy requires the following dependencies: - GTK+ - Python 3 - PyGObject 3.29.1+ - Webkit2gtk with API version 4.0 support - Python Requests ## Installation Packaging status
Ubuntu/Debian Download the latest deb package from the releases page and install it.
Arch/Manjaro Available the AUR. You can use an AUR helper or use the following set of commands to install Minigalaxy on Arch:
git clone https://aur.archlinux.org/minigalaxy.git
cd minigalaxy
makepkg -si
Fedora Available in official repos (F31+)
sudo dnf install minigalaxy
openSUSE Available in official repos for openSUSE Tumbleweed. You can use the following set of commands to install Minigalaxy on openSUSE from the devel project on OBS:
sudo zypper ar -f obs://games:tools gamestools
sudo zypper ref
sudo zypper in minigalaxy
Gentoo Available in the in the Metahax overlay. Follow the instructions in the link to install Minigalaxy on Gentoo.
MX Linux Currently available in the official repository. Please use MX Package Installer or Synaptic instead of manually installing the .deb from the repo.
Solus Available in the official repositories. You can use the following command to install Minigalaxy on Solus:
sudo eopkg it minigalaxy
Other distributions On other distributions Minigalaxy can be downloaded and started with the following commands:
git clone https://github.com/sharkwouter/minigalaxy.git
cd minigalaxy
scripts/compile-translations.sh
bin/minigalaxy
This will be the development version. Alternatively a tarball of a specific release can be downloaded from the releases page.
## Support If you need any help using Minigalaxy, feel free to join the [Minigalaxy Discord server](https://discord.gg/RC4cXVD). Bugs reports and feature requests can also be made [here](https://github.com/sharkwouter/minigalaxy/issues). ## Contribute Currently help is needed with the following: - Reporting bugs in the [issue tracker](https://github.com/sharkwouter/minigalaxy/issues). - Translating to different languages. Instructions [here](https://github.com/sharkwouter/minigalaxy/wiki/Translating-Minigalaxy). - Testing issues with the ["needs testing"](https://github.com/sharkwouter/minigalaxy/issues?q=is%3Aissue+is%3Aopen+label%3A%22needs+testing%22) tag. - Working on or giving input on issues with the ["help wanted"](https://github.com/sharkwouter/minigalaxy/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) or ["good first issue"](https://github.com/sharkwouter/minigalaxy/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) tag. Also check out the [the wiki](https://github.com/sharkwouter/minigalaxy/wiki/Developer-information) for developer information. Feel free to join the [Minigalaxy Discord](https://discord.gg/RC4cXVD) if you would like to help out. ## Special thanks Special thanks goes out to all contributors: - makson96 for multiple code contributions - Odelpasso for multiple code contributions - TotalCaesar659 for multiple code contributions - SvdB-nonp for multiple code contributions - tim77 for packaging Minigalaxy for Fedora, Flathub and multiple code contributions - larslindq for multiple code contributions - graag for multiple code contributions - lmeunier for multiple code contributions - BlindJerobine for translating to German and adding the support option - zweif contributions to code and the German translation - JoshuaFern for packaging Minigalaxy for NixOS and for contributing code - stephanlachnit for upstreaming to Debian and multiple code contributions - sgn for fixing a bug - s8321414 for translating to Taiwanese Mandarin - fuzunspm for translating to Turkish - thomansb22 for translating to French - ArturWroblewski for translating to Polish - kimmalmo for translating to Norwegian Bokmål - EsdrasTarsis for translating to Brazilian Portuguese - protheory8 for translating to Russian - LordPilum for translating to Norwegian Nynorsk - dummyx for translating to simplified Chinese - juanborda, advy99 and LocalPinkRobin for translating to Spanish - Newbytee for translating to Swedish - jubalh for packaging Minigalaxy for openSUSE - gasinvein for packaging Minigalaxy for flathub - metafarion for packaging Minigalaxy for Gentoo - SwampRabbit and Steven Pusser for packaging Minigalaxy for MX Linux - karaushu for translating to Ukrainian - koraynilay for translating to Italian - heidiwenger and jonnelafin for translating to Finish - jakbuz23 for translating to Czech minigalaxy-1.1.0/THIRD-PARTY-LICENSES.md000066400000000000000000000012541414231301100171370ustar00rootroot00000000000000## Logo image (data/minigalaxy.png) **[Copyright 2014 Epic Runes](https://opengameart.org/users/epic-runes)** You are free to: Share :copy and redistribute the material in any medium or format Adapt :remix, transform, and build upon the material for any purpose, even commercially. The licensor cannot revoke these freedoms as long as you follow the license terms. Under the following terms: Attribution :You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. Full license text: https://creativecommons.org/licenses/by/3.0/ minigalaxy-1.1.0/_config.yml000066400000000000000000000002151414231301100157660ustar00rootroot00000000000000theme: jekyll-theme-primer title: Minigalaxy description: A simple GOG client for Linux that lets you download and play your GOG Linux games minigalaxy-1.1.0/bin/000077500000000000000000000000001414231301100144115ustar00rootroot00000000000000minigalaxy-1.1.0/bin/minigalaxy000077500000000000000000000033371414231301100165070ustar00rootroot00000000000000#!/usr/bin/env python3 import sys import os import getopt import shutil from os.path import realpath, dirname, normpath APPLICATION_NAME = "Minigalaxy" LAUNCH_PATH = dirname(realpath(__file__)) if os.path.isdir(os.path.join(LAUNCH_PATH, "../minigalaxy")): SOURCE_PATH = normpath(os.path.join(LAUNCH_PATH, '..')) sys.path.insert(0, SOURCE_PATH) os.chdir(SOURCE_PATH) from minigalaxy.version import VERSION from minigalaxy.paths import CONFIG_DIR, CACHE_DIR def usage(): print("Usage:\t{} [OPTION]".format(sys.argv[0])) print("\nA simple GOG Linux client\n") print("Options:") print("\t-h, --help\t\tDisplay this help and exit") print("\t-v, --version\t\tDisplay version information and exit") print("\t--reset\t\t\tReset the configuration of Minigalaxy") def parse_args(): try: opts, args = getopt.getopt(sys.argv[1:], "hv", ["help", "version", "reset"]) except getopt.GetoptError as err: # print help information and exit: print(err) # will print something like "option -a not recognized" usage() sys.exit(2) for o, a in opts: if o in ("-v", "--version"): print(VERSION) sys.exit() elif o in ("-h", "--help"): usage() sys.exit() elif o == "--reset": shutil.rmtree(CONFIG_DIR, ignore_errors=True) shutil.rmtree(CACHE_DIR, ignore_errors=True) def main(): parse_args() # Import the gi module after parsing arguments from minigalaxy.ui.gtk import Gtk from minigalaxy.ui import Window # Start the application window = Window(APPLICATION_NAME) window.connect("destroy", Gtk.main_quit) Gtk.main() if __name__ == "__main__": main() minigalaxy-1.1.0/data/000077500000000000000000000000001414231301100145525ustar00rootroot00000000000000minigalaxy-1.1.0/data/icons/000077500000000000000000000000001414231301100156655ustar00rootroot00000000000000minigalaxy-1.1.0/data/icons/128x128/000077500000000000000000000000001414231301100166225ustar00rootroot00000000000000minigalaxy-1.1.0/data/icons/128x128/io.github.sharkwouter.Minigalaxy.png000066400000000000000000000437001414231301100257020ustar00rootroot00000000000000PNG  IHDR>agAMA a cHRMz&u0`:pQ<bKGD pHYs+tIME GH+IDATx}yeY;oή,ɒw{.ZH<06 J)#a*v.Dؽ{l]!)0sEE-$2i~8}0Ғy^."+ CGJ\7 fl~̺ @ɖb?_B 8n/7(mHpojݻwctttCwMpijMH)O"1b"zQQq%ZVZ\\Nu-f6h)eWv?AJsZg|u\D"﯊ n{W(2!b:cvYE4=Rʟ&4oYև-:533Sj pR4\}(+kR~R9:kvm۞i_5V VM|)y*# !P(!>v8v!<\0ooZ]BӆaI>F.\^w:cCc~lRs3t6dco߮BDfZ~T%X{}8baM(3{;FX^@Ji2[D4`4?VAp#&"kP8jZX)66ؾ8RV?~3wn*hZصki%0cBax333Nvfm'XJ(ÝÉ 9.ĺcn͕ ˲Z|>@L)u]<>n8w<.fq|q V[k]/ryDeuTeDqF2aÛ m=_)04n&MZ ې q˲T*Fz~ 0GҾBq qApOmwϞ{p\s;d{g8p{L2wipj!H5w!hPx* ؠ TXhK 2Δbq:o3 ^0{N嶘3 ~\ѷκތִ nf~ ߢpҥf3)`ffHak S|β } u{BN>1kb,atIœ2\ZdC; v8FpGl>م\|L+["rA|:LNN֚ݮiv]7.˽WΓK lvN@1"$>z_[DjϮ_+gȁ{6wDHDʲg(z$ZcYq- mJsssHvOeYQ\J.]:Ml޽;w6MSfO';?|$u) E1) duX:y՛e֥XZl=Sϗw|{\)*Q}00`"@(m3saf{^055ٙߺcaK?TAB29R^uÔ# ZPG/Ρy-i|U Ժw9gK[G++n 4}0TJM8uHY^ږ*3 KD x:8ff3RUAGΕ`R~ވ{',~!4p(叡?zQ:_\9:ȩ q?|V`0 _`P/F=[y~a!̇ҷ/Qf~h?Ju֘|va軱w⽨aT@$%W^1j;c9nXg~Թ_{mWnM8M! HUGk۶V7CB/L/1$ACtt:̃\ Q^sp,c >Ob8vJ֘E$/Z"c,,,VKD<"";9<^{Y 0s>Ua@+dvh׺OCJR va"t:|ty(jR Ȅ!K "%5Ǔ].$%g@I'Dw5(FbVpYKDQS~*y+Iaz ay Bko@Bdk :kJ@R Ċ-9dO?RM>^#VкoJJ ۶vU3NvS{2PfH PF0^8ki`"JsXx*, [ @\J&OMZUߟd}F+D z.۾:4w066T*H9As(^O|F\%IlH@Vj(`6@λjݦQ͠N%1cbbr \W0 HF"fNM00nf H" (~ىA dQt0M;|>{###-8z( B*EKXo=**iT/sHlb zQG{9#ߎ/K9\8>9rw<;]ʤYi,9@j1"kM foo9(03J7;bÜ!wߍ7 1ScC&I!:J!c$/;HtA)),p%Qg gѣG7d03lƽދ^x g _nnaH[MDJ̜klF O V dxߍ7M}df(p$ b_1DDa0DPJA)DPa 3;mhN}1͈E4VIkLYM(A7 KP:JM?VI&2QVJH+(eYsHA&8 Y &@Z9"`z!*PeE`ht`2+YF'qN`fw@ZaY;W{dpZ%dhP.9KD`?3Oa0b;ECXy% f^IRR)5>lz1 q|i'-YuUJNs)0:>s 8Je}knkg9xb{} R 2ՙRSq51fƉ'0::t:W;S (3ls_^/G ŠA_I kZjrq;waspE_ZZZB׃icJ4"Jn8Q*^R CH))kY qMWHONN$}zISNR@q//=Qjm;*vuf+sssZB!D0 z~X6i!|߿!:\Wb0A`&"z˭Vs)aСCJ)`B q@D<\%Eh[0 v7͝hsq aYVF 0 xeq=W6YJ)G@EX?xv` 'I]ZXj&0MRJh6Ŋl6aJ2"vau/_8]p_fepԩLj~6J%+{Hq.. Q"B.ť%JukB5\(t1)đᦔT_.=R fJ)Tenl_hZ(6~UlT*0s8i6VFDJffUY>nhZjׄZ7Ba7vVcu]eY/aT*a8v!\>?mYֹ0 /m3mX̆DǁyʲJ)r>j7GGG8N1H+hRF̌|>Jl @рy( rtn(P(ZZmKiˬ"5L ;5[J)%ZZֲN#6Mܬ@J "l5FnBxe>5} IfVaqqIVxZVyhZ18`☙-D4$=fe^hZ˼taR #4 uzYf5fup-+nVq&b66%3RylBkJGHNFSFms]7|mBD(zh4}&ctt4{غ xXGWF~#0l>bɍfv^a&@yk`vvq[|z_6Yͥ+Az0SPTmKkDD f~IКXjd &:OLL|P(r*[YZw, @նZ;e "2ӲgWǁnnqy~wΝ3$5mLAԦtBlIѳ,*AEчM<t:R3u]yXCeYukRx00Mrr hZOk~o4D^" FXa_}SZg[VT,1>>(GVo0D.8F+$'rT.FfN9:D˲ (8ϽCB0{+QmH "dA&#&(}V\ #"ٳ>i =c6_oy| <lBRÞ=C:,|Z ezFfJ ȊR\BM,Pe!\`*J49r0MqhzD5wD[R^HNHH)0-8!WeYlFQLZ/2Y82ـPe":l6wru8_z$Qkl WuzLDe{(Bkqf~&c ###8q7993]geF@ݿ7fx¶ռ\Z J']R>-ܒM̌9J*v4?BgϞEeuJ5Am8Vaͦ>tЪM=h[qָٔ!"= '&ִׅ&jS~H6v"숓<*D$ZvGy>a}ض' *f[qW>pǕRNyczz:^DZ=EDL3H":lG.ݠ 7lO癹6hD)c'.7MY;Tȳ07!,So/XVzRJ(ZiyIDBf]k[2KV#1 &{~~q0  3y= \.VbE d1i¶d}qL75}<̟"[5n?d!_qNk[me8'h+d' Pna!j[4xxEo5M2?x\ Lf4նmZ_,`l0No5 ?NJ7f#u>L0::t3eF)TEݕ l4g;jaTB?~Ri6nE}3opE/زSBRV,nzE|>od(͟a.\X5Z<QZi^Df\.˲HJGQznTF;/X`JV= <"zXann̼hY.uqP23@@_\ܳ>' !~qhay$'p٩D#)Ɯ]s^ 0p `.!$Gkc^43&/2ٯ Lf0 a٢x/3=L92M3T*5;j5xb(R,H $cFR:m;;vl46f6mlc6mlc6mlcbd$)eXIfII*nt|(1 2&&GIMP 2.10.82019:12:29 00:29:49  JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(((((((((((((((((((((+|[W6wcqxemr)9PWw|[˦ [̺}ھ|?Q'O)p)RA*_+Kyk5}C0\S2.3M_ObbkC%v?gOht)%8K$&{?J3p>_~xͮ䰻KG(L מkZճ䴸hī%I >{9 T[[VH%C]OU?~ i G im")6cs:w_c}As m6ꦀ+QEQEQEQEQEQEQEQEQEQE{v1T s>n3Ǧ9mLmGwsD`[n0y9c#!:tG-X8Eր'ՠb< ͓YzU (jΖGBIc55I4;,R>?]yy:JԤ3+̭gvxϥr2jAl`xqw+L)0ŸE}t?y_^{ͧ:. b" 09ST.|w_c}Au m6ꧭV/>V0i_1pBpǥ|@Q@Q@Q@Q@Q@Q@Q@Q@/?D4n M$ pd6Z‘C4UQW| /u991q+pLSȶmBZF'kMJIKV6An0R Bu5IL&oFCRI|Lzp**GG?ªTk<)+ƯboI$%kpGr3[qx[#E8k+   YSi[xl #t%@"ڬ_Oe&_KM;VWDHH= fizZ$öz+RUaVUE_1}.(*͝mA:JZy5kKHDh>?Yboj3szR\j6G1B}ut XztMrY\o'55ō}kUvCbuʱ{nǧҪpդLgz|Vmv6ł\@W9Y}7"k2S"RV(4MT_|q\UOir 2u08a_m\6]T;X.嵺&U)$n2#&YIW t1;{ئ3>4*k [lU=jz}$im.ٷWoSץy0 ( ( ( ( ( ( (>>kQ% V^Z≊ZEckWP!Lēޒ+ AI%=ikVQ[̱wqjl@#l~b-6g-_2"Ǽ 5Ko\Cch%g}kAEP.R}5c=5m~xOĶ:/6RgҰN nqTQE|9xbi$'YGףW;ᩄzStWҾ,a~sP |?A`7.@AEPEPEPEPEPEPEPݖֲ"KSJ+Wúbǂd-n\N"C%p5 +&(444CZvhW%^]]A_M^Ks/P |חW|{o`9+k$(((((((#E#SyUO()l^vkeoqh@=3Uk3YdTaխ吡;N9{J}z(k{HdC/7o8X;r=hG]!ΩfO)M ci=]=xǠ`tQ{$&sE/q6Õ0ՁT(-G--.~a\Zw*lRkbQ\/:\Z4/GƷ副U7D>N{sy'UKAl!GXu֎\\$})Up >^!EPEPEPEPEPEPEP. }&PQF6 SVZkRgmݴ'i +cz!IR9 +m&ٿJHFa_3,4FPҠ;EuGC^ҟʓ _Ң9n._iqٷd~Tyڪu]a?zxSO&ˣ8?Un sIJ~uڍƆ?5t_pYug#m!VP`W@4H;Sl=M)ex+}'Q]:鶫,mOV*?I1C;RzݤRU`[@Wr\B4f(yTwF}2+T)*i=]ϙ(((((((4}Rҭ!sc;A~?4g,rZ̭|rQ8燴daAGu`w'jNРNI"(*z Җ1,eOzIcY*{`y2GB{k/X-Z* 7 : FJaր'(2NiUHȣi!?ݥ} O@ iJQ8J-!( o@aj <؃R4Q)-F Z(Heq *0'=:4"ƀ#˓MSrTG5eUa?ŏ“Cn4_)RWiKq#5֟awg|֗1`ھ8tkkwZMFD'HEPEPEPEPϾ:Xw' ?ð{쑉Pt5|:y))\(etN9Zټ~XRucOtYk M/h= bz.bnfv޸k^:~lG-W#I G;r3z>)_E54{y&w Tǎ~1Z( <ՊfR!܀uQ@Q@\@#QQ]_SV( z\e# ;#8)=>Zz w5̐^i . H ^/ vf0E&JuP$bŠK^>;ӖќAҭ 0 *^!¦h-wrAGn9==k/ CGREPFO9Ҁ<㿉VlT!LZZ2Cy0*_Z=eۈnbWh_3b9B x\oÍ"ֈ[%cjˈxu=EZe OCU20;BxlD7Gϐuu/N09)hvUj g@ v,I c!QC,}gxS:/u-Ua󍝳ۻj㧥MO/ kZL=E,|jWƣ6Ns%le1ڻ-O Gu*G/;I(##rH0z 1\Ha=vVoZn*NF#JܟDžRXEķ1a1p>\>\(ԫ>;tAssq)is֦2L{/*. & l8؏u5QEQEQEQEQEQEQEËhL`Kw a]Hx2=xgޛ I[o p9ݼ獾~|q,Y9#[fa{>ɓ 6Zg)U&8dU01eC mc*[}k q?[X-2>|N!=CĂ88ֽh>Q_Wۋsmu w6x捷+A(ay _uFGN/*(Cv[POM~RHg{t _ֺ; _5b/#xtѤy~\c#g9x]Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@O'!tEXtexif:DateTime2019:12:29 00:29:49PP>tEXtexif:ImageLength192BU`tEXtexif:ImageWidth192)tEXtexif:SoftwareGIMP 2.10.8IDMIENDB`minigalaxy-1.1.0/data/icons/192x192/000077500000000000000000000000001414231301100166245ustar00rootroot00000000000000minigalaxy-1.1.0/data/icons/192x192/io.github.sharkwouter.Minigalaxy.png000066400000000000000000000547201414231301100257100ustar00rootroot00000000000000PNG  IHDRRlzTXtRaw profile type exifxڭgEcx {v0˟Ն-"9d<]?ռ˥jzet|~߿uKg=_^~󷯻uؿNƷ&]9u?}7O_Ϗ_΍`Rt<߻di==&Cz='ع;?^O }E; ?7 Sy+롾=NBa2:&傅Hoan8 [WLﵞZ^R4l:Xd-r~/]V\y>'SFދUXq_Q5m(sΧHH_1-/T7&2X^;8bssg?:!څ R 5c 8v3rd wpܤTIN6Ǵ>K jjF!Y9N JvZZʨZj FK-jk7k{鵷޻aVZsl .:8'Ƙqgu٧ͱ(WYu՗Nu7=N8ɧzθM7rm_{־۬_2Y _YS\5^n)(gd,@ƛ2@AGsT3o(젌|B,7|ݏi\+o2町FRdm(%H]t6>p}O=_?ܩ-×Y uM"C^k0G{633';7r&C{ ~珶ݘ< \z'j=x۱O4 -a yv܇F2753G/5wcUaRnݜvdhPe\r#aes2zY Pҧ&=CqR[!g}s+?@ ph%CׯYiZk$][DM"o{c_p߼f;5/Y taWuTChsܚheR)ALxqZP `s\xgXR !m#|@2϶)EpvKbcg$+%s'xB5#'% `4>7rPtKD&!Aj=]ZPR8+Z~VO_/ٓZQUp;)U.::x$4d<~2CeG(̂{`DO%.uHޥ\hz'sntL ꪴz}v=Lh&( X8'M;$w̃0 DsUH7xrׯG hC4}BD zE)6 8 Tu=\hld./=>k}G #M`s dxQ%Y3|)ι;z,ߨmX^Cr͕EQB<E '5:!¼ zB H8_r.@00(OsQ7XE}PW}cjN.n7DG&?iمʞ٥ F֢݀Z;\$eZhD.j!<"Od*o~О< xJGIF&PC7mAڍ# a"2P5'r@UY^BH>$$I]@P*݇ڢSBux1&Tc,8.2L%$ʧ=#hԸCК `h(K`&H^ +N>ډAZ"@j[Gsha/ %@ I}8NkAwV-QմʅN5N(y@#xFRs$0A,CMworn+?"ZP^2@}]1w`H1Q-t+ܚO)*d5ŋDM"$+k$Ⳋy" DtUp]B7pzTwpy+M٤B%5° 'a)-40QN5MCD RF)hrVKBvÈDYPHv+YDE5c 9;N#? D,[Yji#bDP-01>` b~KM)Şwp8Am6Ϊ"i FJ6v}[8d]OUćS߫TabE'c'Քj(Tx偲z>tuTy`'SCS >2ƈ>*੠SU934Q29 DAȎ@*~8rgK:;NAQj \ԧؑaq.lt|6 v],6C/BC`qPF9{ZѠwC*srYv CGgiltjbD }Gh~GJ E`v<]n6.YiL,„Qh火6FMb╻b-bq\+s|m^P\t|~R>'pfғ+~0mM%#?ڒԲ)Syhk8CYSxdB>oÙe\ 4ϛh٠DE(p!ݚnbD2By׸a<4u0q=u'v(K)N7s]ؗZR0 @@hBkk)R}r yu5Pe ڨxNԁXRF! jOP .-N^~yls(Cpp(q4qxVehl SiۯO@Qk=&juJfL;,N:oە57Of*2y:eE& 7xm$fl9sY5+I>rl?nIK KiYkpp U=,P4dbYnLn͈wEމ`%ՂT*Mn[eMTR;36D<>RVp0*L^!C.V]L5\t [p#G+(0,IZl.M@"'VafBq[ܶ4K Qz4PAErGxGCjUK|Uh1~ZoÇh 5tȑ}X*V^^)huh«6m A/1e ᢳx- q,~IJHy [f:5X4`9hH5ĒO$')3X}* PT Ċ ->t5DV]n4{Qk`llA @39H;Ц>3b/lq(7X(*t_D]{2=T uQc;r|hؾݶ0{4褫"uAlhye?'-OQ @h ὴ!JkuU(9WuHCiӉYz\ >gT҈>+ᤧV_N 9&‘qDZMu_p1tQt&±m/rvj ?ͤ6MZO|Ii" z 22T}$1/zZAI|_[tAE)T<)#P<֠?`n@w{h#ϰĜ[ 蘙.EYUr:x"Q14'OP:o˄C q]>B WL/k~ni$ZH2jzhJFߏE<y,cMI:T"dZOedO ZI]UswNVI@"'\ iqQDNj#a_|"2*Y [id/EGi3\ @D"DkˀV9 "!z j"35 XGpAһvhdJ Ĭ䥦E{" @ @<c^GAvAyAd^P6UI>|JJwdҟV_cRbZzEO@VL\;9aF "ݬ +-QBViJ䁨m҆1 ؛AQ>5+>qo$k}4)0YblYY_mw&0P 6#kWN7YZ$oo.!>Ѳ-ό-kz /W{hջh1H]I{0!pQX( y@ym(921EB❴VIWODP޻>xNTbKGD pHYs+tIME 4D IDATxytdu'kCa}U$d4%'e򦱎{x/9v&9v29IrfqfflǶlcɖ%R,Rk$n"&htTW (~sP˫w] D!B"D!B"D!B"D!B"D!B"D!m `k°{ 8JDDXDefIDoJ)/xs޽G{dZ턪8 `aqfhD2sW ̒fv5f'׉EQ^&"7{333a 43ĈHۂu9"/!266vAl6Uޮ7SD]9DtNUuݻ E nܸW~"a)Q r hnXPPB \DD3_qC<`܊`5טkBOk,--ٶ^?ࡆ]o">9" Մ.UU}f4M <#A "tuM!~=|NH)2s?Q,_fOٳB׈`]6??30pdQB'Bt]/+Rcf0$\5 Hj C3OhKD:O={d`-CA u駄Ty!ĴeYyEQJ;5 pHh$\5]`qSRR0Ze槙o?|$vDv;PfYPxUQ/~VQy0򺮯KxgQRlg^dbQQTLg'62S jucOJ.Z[}O۷o)"@SU'=aS~^3_be\X,D$LtDw3xvǥ3}`@u1Jl_4ܐ õZTOJ)٦<DGM133W}Dn"}UӴ/Zu>Hql6;y^ZJRRJMJIu]_^>b}f#+\fVs睾an,d?5 ? ݸ[z7 3gԙEuf~"J]#EeY/麞urBu)[*D$ڀ=m-WG(Ixb~J"63_bB >(|/T<'yƮDpE#Jp ",[˲a ]kl6yڵ{j>AX[J9YcfM'0aT(t o=| p0 _JT%u*|?IDÍR<kff8.l\J ~N>3K!KeYb8tSMH)-w6`gūtNQU-[ a^2׻6m>VՂ iW uffk~~?~/"W}(O !i'˺Ws5==}8ϿMJ9]ax}Yz: `1Q{d&Kw'L.7JyGh7@D}_qƿ|9r@Ą?3!0t]D"x]ugjjjpvvqJ)nkb\ ?F1s_녁2VCZMjzx ǚۑٻA&",I)@SBD_i``϶RToI0Qj(Gmflˇ'~V ?beY_RUlߒ&'^jF~WUo-d2ydsssm>=" BrBHRÃ-ŊeuDF9Rip>gD.pՄOb?r9czzHV;kᯛ8L&3Y+"6[o׸r2('l NG͑fS~ O =DiN$Q_K=">⠪K)mCv s`I8Mӊe} QO'7oG}~uMD-} 41KKKrWJzm-:+eY g<( lŘg7 Ð,};:ǂIPD✪GDL|>p{#fvZc荗BSbRrU* [p*R룣 N:@Ijlxnbo ! T=ݮvܱ0K)? Bgu]˲Z?瓶m~<$ h 㼖\||ҰZ*1谘9{?#jΫjrF׆nč#3#㧶t{,+VR񹹹x>"m1# B|%_F[ up>RhqT0L|kWT[f%jQ,IM΋ ' [r֨vk3ϔEK]K{]MӼ8ηo2{{ճ#nǗB-/Z+2E  =s9!T@vԌ.ԷkPf!]e k^]UZnvnZվ=DӋuu g6^_LDR0a.jd2T*Uu=8:ܘ});,q0<@`BT4͑P2 ӂWǀ &9tdA]sǭCOȋC}7Ce<۞=`oW|;+/;E^;IYvFQUD"9MUnxTqUVh@o/y^Pi& RAbc 2,垽o~)1k!UE[RI)O6"B _H~0_JٚdvNUկbfF>pMu_/ 3sCFHʌHJ / :CH[18^PkSo,GʳĉLt:=dR %wJ;dG m\Bxm`*".Bci'FTU}Azobb1[Vj5ϼAIvL|՛bXQ ,~dgկ%n(u >"R^Sp, !^-L2\HRڭl6tӎ, zW ;lOC9J(s . R Q*@H8B0APyTO_/?-<ݷAx]hT  GVv|O#Rި4!J_vm{H#"wqqґ#Gh-a2١Aۙ)foq"Rk#HX'ai H! ?( pYTPs"!=R|ҕKn~ϯ{a={w4"d1":Iߍ;̟D .j8E_zulnn>۶0Ţ2==]>y05=3sIYq`ti }HOBSPD ti1Q3$@%8K(V^Bž)^R'jOUsqo\^cXZ'CIf~0".A|-+.)qFl>ؚBDARp}p~驟q`¯k#O'*Ia`tt("0I$OkX*|y0oALZS~ (|?̓q'fffbՈ;/<"UU=S.كjp.f|/M||rdWIqB_a =y[ێ1TJT%0NP. _E͹1 ]|"O[}'O{IJFjNDQT."ŋF{Q45M0k^f^i fR٥?๋Uo{0~ aGL9 ]e@&(_w!^g_jX(Ad6^>"0(aFa9EQn:#G~G.|? θu#D:T)! X کJ 4T5\ƓD FgCoNa<3%bEQn!2s8"`?B-O^Qx<^rI"[@H:{ Ӎat'[W?Or9\|SSSr(Jm 8z(0V!y?UI"a[sf>xڿ{;8W<ڸ4333Cو;HU D4/mփ 0WHsRpQnu&aG=prWmxWOcii }A"PUe!H`ttOߏaL`G lK#EJdչԍ?x`gV`2ض}}٨/:z7ۖB4HbAQFJfS1k'SP}H%7h8p###(JpA4yjXZZ4^y|'> |[B\ mCO"|4w-%gvqQoZqDv۞RŁ HE) CDojj}a PDl牽{-?yqY|3,,,tČ05{?DD9"@ɶPдS& "[3W|);TB"vn,`iߏ;a~~_}SSSH!i݃仡]#AP}X:C3ɵЦ[QE#"~jX ?11x =N _ӬgI7كt0&~ m(xSOaffpH@*~_SIe>{r -DDj((H&;6U܉'5 .:ă Lݢ` (K]("S߷n޼k׮mRJ\|gϞ8+4SixAlf&b$".UEQʝ>8jvxۺCe_aZ}aa/2_鋮VtRcXFV ~P9L8$@KzDDt)ڛ6Q2 y={zy pW`fܼy+ 4h,cߺ(V[mN頻nfܶNHV/N>mC׆;xg>wG0TUm/^ķ-;wBgqMض 4[&:M@n<]_r0yr^UBw4. ZG&2*%1aii 7n܀rxNN|\۪#bii {,_J NG4z+b"l*V._0ePetWYT%4gQ.8BB@4H)yަ">: )dum);&\o3 BdlA_e%ds^$f |tx jY l[ShK) V@A`߰;1M Xz˄!X@nT}oB\?2v "ɬNktkl=+òu:t"6&jIq&53/"hWYDCB~u` \]HY[QN;nY.R&gi~9+rӈEحNpսiI r+^.$I!X\oiCkyXNv 0jl{blvW݌kV`dd+L0?(qgfMى2ka oD͙Zz"C068tЊ\w56>EÉ9:k@Wrl:`y5!?SNm3<99ӧO#Zn7ӑWlkifF4,F]+&x`PsuߏӧOc߾}riɓ8qĊ4 (f_ezRU(Pd,ZCF{B.wںFyKm8qw"No N».+]}K]U"^Q zk"E9ucQTQRq${򛚦?a>}cܚ37a7l]5 ioޮs'(th%zqg4%S###x'066o~pBW ###xG#`Ϟ=д}\/WP(?fo:$t(9Yp]zD]`I)M{GžL*}[Wn:C=ܹsx055]aB >}!Lv AKo`1Kwc?K㵈j,\׵t]"&[X~ cLLp=`aaW\kאP.HRÇKR\\_܊ѕi9jQض``lj }JI +ȗF>uX X 8|0j?rY4aƚ[==?W}w[Ӭ\he̼t; ϝDw J5[~PB,/TUE*z /bxZ{[AGixj3 ̼`g C.1fnFt%YĖ d ʫ"l:~ )k(U_C6%+t ؼZE3u]hDB,[ SHlIHvQu]ZD B:}ԁRWQ-li lQu5fNy^D(9BIDAT)e$gS)Tm8栱[B͹|9$c!B8gQG2*7xsʶ-983[sE7fD ?i%SkLv3gz * CE<8M퇪AU ?( pYTjQs BcO[YkɶSN5G9&[&Ojz%{"<;r ("A:i v%${`ߑ6@zɀa"964@3h"-&P@k6b d`^#UL7 ,BH%$* >|?:@ dr N{GGM "Ѱ-XN02Dt31lA0RVӱX,Y%"Q` pmȕMR0Nv^L@ P zGj);o벎,Jvs|KÎ>_(I 'QboM=1XJ7uՉPs XF֏ Rօ]ʺ`^[?gPyd[ƭIENnp"j9|cǎ9vǙWUF-̃'?\'lTu_="Py`4fbIͩ&yBTJ#J#53unnf& @q f͟O* RD)Ewݑ-uHxHġ6/NU޲v K@ .TLה MT_Z]ЖiBchI$Rʈ{-56hY@@$@ [rĔ C~0i\0iZ!"^?N̨ &]Z_n!D>y!čD>kShBy.Xn߇6߰2mj@o=.EIAoCTKv lf+BDC"ajL4@ z*2x\z7㥃hݖ@DFI`!Ga+9{YN×%@YEW@CY_E$[!d4>Ho<i4D4{C7\@Y4z㰌`ןk/5Qj>. eF5\i`f]0[dk@ϩѲ09E @ ^Dn?6+eR vDtymDZ{47낋 >|_kMruxԟ5Ӭ!kSg_Bp6".þ} ]_W] DX1{D{rw51щH2s n Rۺ KzEэHTl|ћw5ah/FeUUUK V Л  -4;".^h AD'׊E?z}D"a !.?1MTjvn(Й3g'Bsk~!7hfaYֲ*.{MzgWCXʱ-;|ObÇ# }MMM=44={v_pɓfZ~D"X, Zbnc;}T*|Jj À H$:.3\. 'm-˲ _i)"j8}R @ض ˲Va4MT*TU3aQqx|Ei'( ?>~<by/tȓR m7')=Y`?;efeqqa=<#Ht$|JDjuQ(8E8|ޚ ECbkEQ3)[g~q:8XZZHHR>U*kDbSNw|?RUM&V''L"ϣT*5;w8|M 30 +Iukfhvi9ZEQzneh8rMuo%TTJ]3N>+ iOJ_`f+̲,8tt5Mx PSd2fSlVKnoZ s' g/a6udrյ04z+u]TUA]y;!;ʘ?bsݕPUU öm,..qU54M03 VMHE4}ٻ|i56{̈́D"U P.QV*Ds .4MC,KxүUaЅE ,aV)*ʪh1<< 48NGbucѺ>Ԗh( FGG߿yr[g Sh6 F#6Z!RJ妣#d2 ?rGN1`w]J)bubj\#Juʆ}=۸֑: n"@rsf~[]$X,d2jd}EJe!މ50Q3880P*fWuvCG+5"fffV23g݂p !i"c"z@od2d2UD"LG_9(-l%@6-3sjތ 8f}3444+ X\\ pT*'W7kka3O1 P*ϒ$߿>P( P[:39~j1]IDM{>\<TjE-4zt H"vl*-phtMUՋl6;}Dt0LjjyOAmT~p_"j6}yhh;ll}H&Rq 4Wl gf4+juPU%(ʕ5ګ4^5ߨXf___avoR_B|h-I)NuaYĪ&*H06hiX CCCH$}\bqٷv ]בJ_Z3_c\'K}h%UbʡfĚ{y>??C'hC$IrfUy k #-a(tkD4ED^ Rfc<ü"4Üd醘D6MӾs`ttyǻkFbGZm:D:}8CCCe" `a`8­k 3D4500puEA;}^JT,qƍfj(Hسg6u>̜%CwpcP. +&T*uɲO|eYs . Bgo@u]?rrSl6\Ψj aH$ŭؖ6Lbfw:?'''9*̌Zwk} Df!vZ ,822fxA)EQ*w E)sK8˄ UᅵJ>>::glhvZ#A;mrp5f>ww=ϻ900Nz*7Ct:]p[q|4P(rG?x 64 MG*3<44Xnѥ]U#jyuN8B]۩vTU8Ԁpy[ۭX,bqqL9Uy]56\9]_ɼk`bm~h(wGQ1ɼJDWqʅH$PUAZ6Ei4mݛ\ZL?<σyM7k,Y0sΖu/@S~rFWTj:Qn\V"z^i3.lf_c旈Xpn꿴>ZpJ͕Ř\b6R$Je^`4SۙmhA[ZZ:̿`}t:/ ^f/3z 뺾|ILZN"ZkhMκnWEZWӗډMo'X}Jk/..^mWoo;ih6LLe"zsppp]]FGGߜJ~"z[c``m%@z=snr^Wccc]%N[j uF{]UaUvmAn uaYw]}f7LwE!ī/8HYt:&_d2Yؠ)R{RʮÙRʔZYT*튢[,m<ƙd2 L&-_J)hy"?44266Xc?-<3)`963d2#`&IXlxe:vw80j8j5ItMF\樂יY\~H$@aIDijqUU ]h%6ql,ǁmpY;V;i26 [CAu13?+_]!R{H,k\UU*u ^B1W=cؚbw]wQkqժF+0\+Y;$ӉMUq]uwO>]Ф;t/hz=?9fN=4hbl{oZ=8ΚGk&hFjRY,k\.A\ժ.TUeY0im0{_&(gBuGmafV-ҪU5ҭa6(H$R afj` ZP֚WA}d:^y6f0MvnZ{4MR^p`ll*H${ l~ÅДX+cccuMf~r=_oD(pߌY4"% "}]Ӵa0N!ÞaƵrrZ{y5|(]ow|_}&ϭB:si=$b^۳gO-"݅7JD4Mџ03kVxkn[4&4-{رj_r%nuݾV!_kR]ﶆ@~k#t}ޭBp/sNEQev9Qֆw0$͍17} rG-B_Ӿ,0󳃃#}f\XX=-<@mNN}Z}u] Z&Pbll -1޽{0"(9"z4;0 ]`0>%R~m_2MOI' zU`7"@_A?==m9(f>GyA3`DTB}kf˨*pQU A\#p1(Bย(BDɆ=oP8nQQJy_pAQ)f>44T"D!B"D!B"D!B"D!B"D!B"D!B"D!B"Da{<IENDB`minigalaxy-1.1.0/data/images/000077500000000000000000000000001414231301100160175ustar00rootroot00000000000000minigalaxy-1.1.0/data/images/winehq_logo_glass.png000066400000000000000000000021231414231301100222270ustar00rootroot00000000000000PNG  IHDR pHYs  tIME  /!5iTXtCommentCreated with GIMPd.eIDAT8_lSeƟ;vj׵nutcu9Bt hbLH2+ ܈b)8tP 9Fڎn======>͛7u sMf2/Ȱ{ܵ]_t<ǃ1С:|~o_4&u/ >\i1(%`P%45—nܜ\xO=sgFxҮXJqw2b'NA+vͫ1dɲĮ:7}{fS ^bRX_pg$\:A8$,P #gU9z %,OL{gI"moV'$)Zҷ'lt_!$wO} C B2 yh9^ဨY!dұLw,7K(P7,A& ˽s`M_ϥ2 )-h @@J(Г8>}O}@i(rz^tӥa=3c}q+WڝNVРPNI.ja,n l~Sy%H7XW#Sц$ᭁ=-m65.2z_Hr&n,wvԌ'6T{##'< ^U𾡃kV~T:`q69:_ io.github.sharkwouter.Minigalaxy CC0-1.0 GPL-3.0-or-later Minigalaxy A simple GOG client for Linux

Minigalaxy lets you download, install and play your GOG Linux games without getting in your way.

Besides all that, it offers the following additional features:

  • Select in which language you'd prefer to download your games
  • Change where games are installed
  • Search your GOG Linux library
  • Show all games or just the ones you've installed
  • View the error message if a game fails to launch
  • Enable displaying the FPS in games

An account on gog.com is required to use this application.

io.github.sharkwouter.Minigalaxy.desktop Minigalaxy https://raw.githubusercontent.com/sharkwouter/minigalaxy/master/screenshot.jpg https://github.com/sharkwouter/minigalaxy Wouter "sharkwouter" Wijsman minigalaxy

Implements the following changes:

  • Fix updates sometimes not working
  • Fix some games always showing an update is available
  • Fix DLC not downloading (thanks to stephanlachnit)
  • Fix DLC update option not showing up (thanks to makson96)
  • Fix show store page button not showing anymore (thanks to makson96)
  • Fix missing thumbnails not being downloaded for already installed games (thanks to makson96)
  • Fix the login screen crashing in some cases (thanks to makson96)
  • Use the system's icon theme for icons used (thanks to stephanlachnit and makson96)

Implements the following changes:

  • Open maximized if the window was maximized when last closed (thanks to TotalCaesar659)
  • Kept installers are now stored in ~/.cache/minigalaxy/download
  • Fix about window displaying wrong version number
  • Fix show store page button not showing anymore (thanks to makson96)
  • Fix the download manager crashing when an installer has been damaged during downloading (thanks to makson96)
  • Fix games showing an update is available while the latest version is installed (thanks to makson96)
  • Fix loading the library taking a long time when many games are installed (thanks to makson96)
  • Fix Gex not launching

Added the following translations:

  • Swedish (thanks to Newbytee)

Updated the following translations:

  • Polish (thanks to ArturWroblewski)
  • Russian (thanks to TotalCaesar659)

Implements the following changes:

  • Games can now be updated (thanks to mdgomes and makson96)
  • DLC can now be installed and updated (thanks to makson96)
  • The installed filter now also shows games which are downloading (thanks to makson96)
  • Fix crash on some systems where /usr/bin is linked to /bin (thanks to sgn)
  • Create new config file if old one is unreadable (thanks to SvdB-nonp)
  • Fix some Windows games not installing because of the directory name used (thanks to SvdB-nonp)
  • Fix some Windows games like Witcher 3 not launching because of the working directory not being set (thanks for kibun1)
  • Clean up installation files for cancelled downloads (thanks to SvdB-nonp)
  • Fix crash on flaky internet connection (thanks to makson96)
  • Use 755 permissions for all directories created by Minigalaxy
  • Remove cached files when cancelling a download (thanks to svdB-nonp)
  • Installed games should no longer be shown twice (thanks to makson96)

Added the following translations:

  • Simplified Chinese (thanks to dummyx)
  • Spanish (thanks to juanborda)

Updated the following translations:

  • Brazilian Portuguese (thanks to EsdrasTarsis)
  • Dutch
  • French (thanks to Thomasb22)
  • German (thanks to BlindJerobine)
  • Norwegian Bokmål (thanks to kimmalmo)
  • Russian (thanks to protheory8)
  • Taiwanese Mandarin (thanks to s8321414)
  • Turkish (thanks to fuzunspm
  • Added Norwegian Nynorsk translation (thanks to LordPilum).
  • Added Russian translation (thanks to protheory8).
  • Updated Brazilian Portuguese translation (thanks to EsdrasTarsis).
  • Updated French translation (thanks to thomasb22).
  • Updated German translation (thanks to BlindJerobine).
  • Updated Norwegian Bokmål translation (thanks to kimmalmo).
  • Updated Polish translation (thanks to ArturWroblewski).
  • Updated Taiwanese Mandarin translation (thanks to s8321414).
  • Updated Turkish translation (thanks to fuzunspm).
  • Added support for installing Windows games (with help from Odelpasso).
  • Added store page link to game menus (thanks to larslindq).
  • Fixed game directories being created without any spaces in the name (thanks to larslindq).
  • Fixed thumbnails not being downloaded for already installed games.
  • Fixed symlinks to libraries not being created correctly upon installation.
  • Made preparations for a Flathub package.
  • Added all contributors and translators to the about window.
  • Added German translation (thanks to BlindJerobine).
  • Added Turkish translation (thanks to fuzunspm).
  • Added Brazilian Portuguese translation (thanks to EsdrasTarsis).
  • Added Norwegian Bokmål translation (thanks to kimmalmo).
  • Added Polish translation (thanks to ArturWroblewski).
  • Added French translation (thanks to thomasb22).
  • Added option to cancel downloads.
  • Changed the way games are downloaded to a queue instead of trying to download everything at once.
  • Added support option to game specific menus which open the GOG support page (thanks to BlindJerobine).
  • Ask for confirmation before uninstalling (thanks to Odelpasso).
  • Added option to display FPS in games (thanks to Odelpasso).
  • Downloads can now be resumed after having been cancelled before.
  • Installers are now verified before installing.
  • The active download is now resumed when restarting Minigalaxy.
  • Fixed issue with games not downloading.
  • Added a button which allows you to uninstall game.
  • Added a button which allows you to open directory in which game is installed.
  • Added Dutch translation.
  • Added Taiwanese Mandarin translation (thanks to s8321414).
  • Added offline mode.
  • The system's Dosbox and Scummvm installations are now preferred over the ones bundled with games.
  • Improved game detection to check in all directories in the installation path.
  • Added the option to keep game installers (thanks to Odelpasso).
  • Added the option to disable staying logged in (thanks to Odelpasso).
  • The preferences menu now uses a file picker for setting the installation path (thanks to Odelpasso).
  • Startup time has been reduced.
  • Games which aren't installed are now grayed out.
  • Fixed crashes and freezes sometimes happening while downloading and installing games.
  • Fixed installation failing when the installation directory is not on same filesystem as /home.
  • Fixed downloads crashing when the installation directory is changed or the refresh button is pressed.
  • Fixed changing installation directory not loading which games are installed in the new directory.
  • Fixed copyright file in deb package not being machine readable.
  • Moved binary to /usr/games in the deb package.
  • Add command line options --help, --version and --reset. The reset option will reset the cache and configuration.

Initial release.

moderate moderate moderate intense intense intense none moderate moderate moderate moderate intense moderate moderate moderate moderate none none none intense intense intense intense intense moderate intense intense
minigalaxy-1.1.0/data/po/000077500000000000000000000000001414231301100151705ustar00rootroot00000000000000minigalaxy-1.1.0/data/po/cs_CZ.po000066400000000000000000000310741414231301100165360ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-11-02 14:04+0100\n" "PO-Revision-Date: 2021-11-02 14:19+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: cs_CZ\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.0\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n>=2 && n<=4 ? 1 : 2);\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Jednoduchý klient GOG pro Linux" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "O aplikaci" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "O aplikaci" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "Přidáno na konec příkazu pro spuštění hry" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "Přidáno před příkaz pro spuštění hry" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "Opravdu chcete zrušit stahování {}?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "Opravdu se chcete odhlásit z GOG?" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "Opravdu chcete odinstalovat %s?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Brazilská portugalština" #: data/ui/properties.ui:266 msgid "Cancel" msgstr "Zrušit" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Zrušit" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Čínština" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "Možnosti příkazu:" #: minigalaxy/ui/properties.py:103 msgid "Couldn't open store page" msgstr "Stránku obchodu se nepodařilo otevřít" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "Stránku podpory se nepodařilo otevřít" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "Vytvořit zástupce: " #: minigalaxy/constants.py:30 msgid "Czech" msgstr "Čeština" #: data/ui/gametile.ui:36 msgid "DLC" msgstr "Stažitelný obsah" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Dánština" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "Chyba stahování" #: minigalaxy/constants.py:10 minigalaxy/constants.py:31 msgid "Dutch" msgstr "Nizozemština" #: minigalaxy/constants.py:11 minigalaxy/constants.py:32 msgid "English" msgstr "Angličtina" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" "Nepodařilo se změnit jazyk aplikace. Ujistěte se, že je na Vašem systému " "vygenerováno příslušné locale." #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "Instalace {} se nezdařila" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "Získání knihovny se nezdařilo" #: minigalaxy/launcher.py:34 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "{} se nezdařilo spustit:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:33 msgid "Finnish" msgstr "Finština" #: minigalaxy/constants.py:13 minigalaxy/constants.py:34 msgid "French" msgstr "Francouzština" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "Žánr" #: minigalaxy/constants.py:14 minigalaxy/constants.py:35 msgid "German" msgstr "Němčina" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Stránka na Githubu" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "Skrýt hru:" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Maďarština" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "Rozbalení pomocí Innoextract se nezdařilo." #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "Innoextract není nainstalován." #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Cesta pro instalaci: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Nainstalované" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Italština" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Japonština" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Ponechat instalátory po stažení hry.\n" "Instalátory jsou uloženy v: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Ponechat instalátory: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Korejština" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "Jazyk: " #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Přihlášení" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Odhlásit" #: minigalaxy/launcher.py:179 msgid "No executable was found in {}" msgstr "{} neobsahuje žádný spustitelný soubor" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Norština" #: minigalaxy/constants.py:36 msgid "Norwegian Bokmål" msgstr "Norština Bokmål" #: minigalaxy/constants.py:37 msgid "Norwegian Nynorsk" msgstr "Norština Nynorsk" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "Nedostatek místa pro rozbalení hry. Požadované: {} Dostupné: {}" #: data/ui/properties.ui:280 msgid "OK" msgstr "Budiž" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Otevřít soubory" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Zkontrolujte připojení k internetu" #: minigalaxy/constants.py:20 minigalaxy/constants.py:38 msgid "Polish" msgstr "Polština" #: minigalaxy/constants.py:21 minigalaxy/constants.py:39 msgid "Portuguese" msgstr "Portugalština" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Možnosti" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Možnosti" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Preferovaný jazyk hry: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "Možnosti" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "Možnosti {}" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Obnovit seznam her" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "Regedit" #: minigalaxy/constants.py:22 minigalaxy/constants.py:40 msgid "Russian" msgstr "Ruština" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Uložit" #: data/ui/properties.ui:154 msgid "Show FPS in game:" msgstr "Zobrazit FPS ve hře:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Zobrazit hry pro Windows: " #. Has to end with ": " #: data/ui/preferences.ui:224 msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Zobrazit skryté hry: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Zobrazit pouze nainstalované hry" #: minigalaxy/constants.py:41 msgid "Simplified Chinese" msgstr "Zjednodušená čínština" #: minigalaxy/constants.py:23 minigalaxy/constants.py:42 msgid "Spanish" msgstr "Španělština" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Zapamatovat přihlášení:" #: data/ui/properties.ui:77 msgid "Store" msgstr "Obchod" #: data/ui/properties.ui:63 msgid "Support" msgstr "Podpora" #: minigalaxy/constants.py:24 minigalaxy/constants.py:43 msgid "Swedish" msgstr "Švédština" #: minigalaxy/constants.py:29 msgid "System default" msgstr "Výchozí hodnota systému" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "Instalace {} se nezdařila. Zkuste to znovu." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "Preferovaný jazyk pro stahované hry" #: data/ui/preferences.ui:65 msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "Preferovaný jazyk pro Minigalaxy" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "Došlo k chybě při získávání odkazu pro stažení!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "Sem se budou instalovat hry" #: minigalaxy/constants.py:44 msgid "Traditional Chinese" msgstr "Tradiční čínština" #: minigalaxy/constants.py:25 minigalaxy/constants.py:45 msgid "Turkish" msgstr "Turečtina" #: minigalaxy/constants.py:46 msgid "Ukrainian" msgstr "Ukrajinština" #: data/ui/gametile.ui:66 msgid "Uninstall" msgstr "Odinstalovat" #: data/ui/gametile.ui:51 msgid "Update" msgstr "Aktualizovat" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "Použít tmavé téma: " #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "Argumenty příkazu:" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "Verze" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "Pokud je tato možnost vypnuta, budete se muset přihlásit při každém startu " "programu Minigalaxy" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "Určuje zdali se použije tmavý vzhled" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Určuje zdali se mají zobrazovat hry pro Windows" #: data/ui/preferences.ui:221 msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Určuje zdali se mají zobrazovat skryté hry" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "Určuje zdali se mají vytvářet zástupci pro nově nainstalované hry" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "Rozbalení Wine se nezdařilo." #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "Wine nebyl nalezen. Zobrazení her pro Windows nemůže být zapnuto." #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "Winecfg" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "stáhnout" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "stahování…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "ve frontě…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "nainstalovat" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "instalace…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "hrát" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "odinstalace…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "aktualizace…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} nemohl být rozbalen." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "{} se nezdařilo stáhnout." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} není použitelná cesta" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} byl poškozen. Stáhněte ho znovu." minigalaxy-1.1.0/data/po/de.po000066400000000000000000000354701414231301100161310ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: minigalaxy 0.9.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2021-10-10 21:36+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.4.2\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Ein einfacher GOG-Client für Linux" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "Info" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "Info" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "Wird am Ende des Befehls zum Starten des Spiels eingefügt" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "Wird vor dem Befehl zum Starten des Spiels eingefügt" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "Bist du sicher, dass du den Download von {} abbrechen möchtest?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "Bist du sicher, dass du dich von GOG abmelden möchtest?" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "Bist du sicher, dass du %s deinstallieren möchtest?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Brasilianisches Portugiesisch" #: data/ui/properties.ui:266 msgid "Cancel" msgstr "Abbrechen" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Abbrechen" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Chinesisch" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "Kommandozeilenparameter:" #: minigalaxy/ui/properties.py:103 msgid "Couldn't open store page" msgstr "Konnte die Store-Seite nicht öffnen" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "Konnte die Support-Seite nicht öffnen" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "Menü-Verknüpfungen erstellen: " #: data/ui/gametile.ui:36 msgid "DLC" msgstr "DLC" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Dänisch" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "Download-Fehler" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "Niederländisch" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "Englisch" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "Fehler beim Installieren von {}" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "Fehler beim Abrufen der Bibliothek" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "Fehler beim Starten von {}:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "Finnisch" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "Französisch" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "Genre" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "Deutsch" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Github-Seite" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "Spiel verstecken:" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Ungarisch" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "Entpacken mit Innoextract fehlgeschlagen." #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "Innoextract ist nicht installiert." #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Installationspfad: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Installiert" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Italienisch" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Japanisch" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Installationsdateien behalten, nachdem ein Spiel heruntergeladen wurde.\n" "Installationsdateien werden gespeichert in: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Installationsdateien behalten: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Koreanisch" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "Sprache: " #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Anmelden" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Abmelden" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "Es wurden keine Ausführbaren Dateien in {} gefunden" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Norwegisch" #: minigalaxy/constants.py:35 msgid "Norwegian Bokmål" msgstr "Norwegisch Bokmål" #: minigalaxy/constants.py:36 msgid "Norwegian Nynorsk" msgstr "Norwegisch Nynorsk" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "" "Nicht genug Speicher, um das Spiel zu entpacken. Benötigt: {} Verfügbar: {}" #: data/ui/properties.ui:280 msgid "OK" msgstr "OK" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Dateien öffnen" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Bitte überprüfe deine Internetverbindung" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "Polnisch" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "Portugiesisch" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Einstellungen" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Einstellungen" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Bevorzugte Sprache für Spiele: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "Eigenschaften" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "Eigenschaften von {}" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Spieleliste aktualisieren" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "Regedit" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "Russisch" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Speichern" #: data/ui/properties.ui:154 msgid "Show FPS in game:" msgstr "FPS im Spiel anzeigen:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Windows-Spiele anzeigen: " #. Has to end with ": " #: data/ui/preferences.ui:224 msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Versteckte Spiele anzeigen: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Nur installierte Spiele anzeigen" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "Vereinfachtes Chinesisch" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "Spanisch" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Angemeldet bleiben:" #: data/ui/properties.ui:77 msgid "Store" msgstr "Store" #: data/ui/properties.ui:63 msgid "Support" msgstr "Support" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "Schwedisch" #: minigalaxy/constants.py:29 msgid "System default" msgstr "Systemstandard" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "Die Installation von {} ist fehlgeschlagen. Bitte versuche es erneut." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "Die bevorzugte Sprache, in der Spiele heruntergeladen werden" #: data/ui/preferences.ui:65 msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "Die bevorzugte Sprache beim Start von Minigalaxy" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "Fehler beim Abrufen des Download-Links!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "Ort, an dem Spiele installiert werden" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "Traditionelles Chinesisch" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "Türkisch" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "Ukrainisch" #: data/ui/gametile.ui:66 msgid "Uninstall" msgstr "Deinstallieren" #: data/ui/gametile.ui:51 msgid "Update" msgstr "Aktualisieren" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "Dunkles Farbschema verwenden: " #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "Umgebungsvariablen:" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "Version" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "Wenn deaktiviert, wirst du bei jedem Start von Minigalaxy aufgefordert, dich " "anzumelden" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "Ob Minigalaxy ein dunkles Farbschema verwenden soll oder nicht" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Ob Windows-Spiele in der Bibliothek angezeigt werden oder nicht" #: data/ui/preferences.ui:221 msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Ob versteckte Spiele in der Bibliothek angezeigt werden oder nicht" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "" "Ob Verknüpfungen für neu installierte Spiele erstellt werden oder nicht" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "Entpacken mit Wine fehlgeschlagen." #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "" "Wine wurde nicht gefunden. Das Anzeigen von Windows-Spielen kann nicht " "aktiviert werden." #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "Winecfg" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "Herunterladen" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "Wird heruntergeladen…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "In der Warteschlange…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "Installieren" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "Wird installiert…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "Spielen" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "Wird deinstalliert…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "Wird aktualisiert…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} konnte nicht entpackt werden." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "Der Download von {} schlug fehl." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} ist kein gültiger Pfad" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} wurde beschädigt. Bitte starte den Download erneut." #~ msgid "Couldn't connect to GOG servers" #~ msgstr "Keine Verbindung zu den GOG Servern möglich" #~ msgid "Install Wine to enable this feature" #~ msgstr "Installiere Wine, um diese Funktion zu aktivieren" #~ msgctxt "Wine Settings" #~ msgid "Settings" #~ msgstr "Einstellungen" #~ msgctxt "show_fps_tooltip" #~ msgid "" #~ "Show the framerate while playing games. Only works with AMD and Nvidia " #~ "graphics cards." #~ msgstr "" #~ "Zeigt die Framerate während du spielst. Funktioniert nur mit AMD und " #~ "Nvidia Grafikkarten." #~ msgid "" #~ "Artur Wróblewski\n" #~ "BlindJerobine\n" #~ "Esdras Tarsis\n" #~ "Hüseyin Fahri Uzun\n" #~ "Jan Kjetil Myklebust\n" #~ "Jeff Huang\n" #~ "kimmalmo\n" #~ "ProTheory8\n" #~ "thomasb22" #~ msgstr "" #~ "Artur Wróblewski\n" #~ "BlindJerobine\n" #~ "Esdras Tarsis\n" #~ "Hüseyin Fahri Uzun\n" #~ "Jan Kjetil Myklebust\n" #~ "Jeff Huang\n" #~ "kimmalmo\n" #~ "ProTheory8\n" #~ "thomasb22" #~ msgid "Couldn't start subprocess" #~ msgstr "Konnte Unterprozess nicht starten" #~ msgid "No error message was returned" #~ msgstr "Keine Fehlermeldungen vorhanden" #~ msgid "Minigalaxy is now running in offline mode" #~ msgstr "Minigalaxy läuft nun im Offline-Modus" #~ msgid "Try again with an active internet connection" #~ msgstr "Versuche es mit einer aktiven Internetverbindung erneut" minigalaxy-1.1.0/data/po/es.po000066400000000000000000000325621414231301100161470ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2021-10-07 18:22+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.3.1\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Un cliente sencillo de GOG para Linux" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "Acerca de" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "Acerca de" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "Añadido al final del comando utilizado para lanzar el juego" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "Añadido al comienzo del comando utilizado para lanzar el juego" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "¿Estás seguro que deseas cancelar la descarga de {}?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "¿Estás seguro que quieres cerrar la sesión de GOG?" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "¿Estás seguro que deseas desinstalar %s?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Portugués de Brasil" #: data/ui/properties.ui:266 #, fuzzy msgid "Cancel" msgstr "Cancelar" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Cancelar" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Chino" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "Argumentos del comando:" #: minigalaxy/ui/properties.py:103 #, fuzzy msgid "Couldn't open store page" msgstr "No se pudo abrir la página de soporte" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "No se pudo abrir la página de soporte" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "Crear accesos directos en el menú: " #: data/ui/gametile.ui:36 msgid "DLC" msgstr "" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Danés" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 #, fuzzy msgid "Download error" msgstr "Error en la descarga" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "Holandés" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "Inglés" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" "Fallo al cambiar el idioma del programa. Asegúrate de que el local se ha" "generado en tu sistema" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "No se pudo instalar {}" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "No se pudo recuperar la biblioteca" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "No se pudo iniciar {}" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "Finlandés" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "Francés" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "Género" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "Alemán" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Página de GitHub" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "Ocultar juego:" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Húngaro" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "La extracción de Innoextract falló." #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "Innoextract no instalado." #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Ruta de instalación: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Instalados" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Italiano" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Japones" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Guardar los instaladores al descargar un juego.\n" "Los instaladores se guardan en: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Guardar los instaladores: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Coreano" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "Idioma: " #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Iniciar sesión" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Cerrar sesión" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "No se encontró ningún ejecutable en {}" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Noruego" #: minigalaxy/constants.py:35 #, fuzzy msgid "Norwegian Bokmål" msgstr "Noruego" #: minigalaxy/constants.py:36 #, fuzzy msgid "Norwegian Nynorsk" msgstr "Noruego" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "" "No hay suficiente espacio para extraer el juego. Se necesita: {} Disponible: " "{}" #: data/ui/properties.ui:280 msgid "OK" msgstr "Aceptar" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Abrir Archivos" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Por favor, verifique su conexión a internet" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "Polaco" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "Portugués" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Preferencias" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Preferencias" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Idioma preferido: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "Propiedades" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "Propiedades de {}" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Refrescar lista de juegos" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "Ruso" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Guardar" #: data/ui/properties.ui:154 #, fuzzy msgid "Show FPS in game:" msgstr "Mostrar el indicador de FPS en los juegos:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Mostrar los juegos para Windows: " #. Has to end with ": " #: data/ui/preferences.ui:224 #, fuzzy msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Mostrar los juegos ocultos: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Mostrar solo los juegos instalados" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "Chino simplificado" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "Español" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Permanecer conectado:" #: data/ui/properties.ui:77 #, fuzzy msgid "Store" msgstr "Pagina de la tienda" #: data/ui/properties.ui:63 #, fuzzy msgid "Support" msgstr "Soporte" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "Sueco" #: minigalaxy/constants.py:29 msgid "System default" msgstr "Por defecto del sistema" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "La instalación de {} ha fallado. Por favor, intentelo de nuevo." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "El lenguage preferido en el que descargar los juegos" #: data/ui/preferences.ui:65 #, fuzzy msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "El lenguage preferido en el que lanzar Minigalaxy" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "¡Ocurrio un error al intentar obtener el enlace de descarga!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "La ruta donde se instalaran los juegos" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "Chino tradicional" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "Turco" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "Ucraniano" #: data/ui/gametile.ui:66 #, fuzzy msgid "Uninstall" msgstr "Desinstalar" #: data/ui/gametile.ui:51 msgid "Update" msgstr "Actualizar" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "Usar tema oscuro: " #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "Parámetros" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "Versión" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "Si se desactiva se te requerira que inicies sesion cada vez que abras " "Minigalaxy" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "Si Minigalaxy ha de utilizar el tema oscuro o no" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Si mostrar los juegos para Windows en la biblioteca o no" #: data/ui/preferences.ui:221 #, fuzzy msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Si mostrar los juegos para Windows en la biblioteca o no" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "Si los atajos son creados al instalar nuevos juegos o no" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "La extracción de Wine fallo." #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "" "No se encontro Wine. Mostrar los juegos para Windows no se puede activar" #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "descarga" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "descargando…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "en cola…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "instalar" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "instalando…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "jugar" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "desinstalando…" #: minigalaxy/ui/gametile.py:552 #, fuzzy msgid "updating…" msgstr "descargando…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} no se pudo descomprimir." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "{} no se pudo descargar." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} no es una ruta valida" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} se ha corrompido. Por favor descargalo nuevamente." #~ msgid "Couldn't connect to GOG servers" #~ msgstr "No se pudo conectar a los servidores de GOG" #~ msgid "Install Wine to enable this feature" #~ msgstr "Instala Wine para habilitar esta función" #~ msgctxt "Wine Settings" #~ msgid "Settings" #~ msgstr "Configuración" #~ msgctxt "show_fps_tooltip" #~ msgid "" #~ "Show the framerate while playing games. Only works with AMD and Nvidia " #~ "graphics cards." #~ msgstr "" #~ "Muestra el indicador de los cuadros por segundo mientras juegas. Solo " #~ "funciona con placas graficas de AMD y nVidia." #~ msgid "Couldn't start subprocess" #~ msgstr "No se pudo iniciar el sub-proceso" #~ msgid "No error message was returned" #~ msgstr "Ningún mensaje de error fue devuelto" minigalaxy-1.1.0/data/po/fi.po000066400000000000000000000307421414231301100161340ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2021-09-30 12:59+0300\n" "Last-Translator: \n" "Language-Team: \n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.4.2\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-Bookmarks: 3,-1,-1,-1,-1,-1,-1,-1,-1,-1\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Yksinkertainen GOG-asiakasohjelma Linuxille" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "Tietoja" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "Tietoja" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "Lisätään pelin käynnistämiseen käytettävän komennon loppuun" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "Lisätään pelin käynnistämiseen käytettävän komennon alkuun" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "Oletko varma että haluat keskeyttää latauksen {}?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "Oletko varma että halua kirjautua ulos palvelusta GOG?" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "Oletko varma että haluat poistaa asennuksen %s?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Brasilian portugali" #: data/ui/properties.ui:266 msgid "Cancel" msgstr "Peruuta" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Peruuta" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Kiina" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "Komentoparametrit:" #: minigalaxy/ui/properties.py:103 msgid "Couldn't open store page" msgstr "Kauppasivua ei voitu avata" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "Tukisivua ei voitu avata" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "Luo valikon pikakuvakkeet: " #: data/ui/gametile.ui:36 msgid "DLC" msgstr "DLC-lisäosa" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Tanska" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "Latausvirhe" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "Hollanti" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "Englanti" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "{} asentaminen epäonnistui" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "Kirjaston noutaminen epäonnistui" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "Kohteen {} käynnistäminen epäonnistui:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "Suomi" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "Ranska" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "Genre" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "Saksa" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Github-sivu" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "Piilota peli:" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Unkari" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "Innoextract-purku epäonnistui." #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "Innoextract ei asennettu." #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Asennuspolku: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Asennetut" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Italia" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Japani" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Säilytä asennusohjelmat pelin lataamisen jälkeen.\n" "Asennusohjelmat löytyvät täältä: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Säilytä asennusohjelmat: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Korea" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "Kieli: " #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Kirjaudu sisään" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Kirjaudu ulos" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "Ajettavaa käynnistystiedostoa ei löytynyt kohteelle {}" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Norja" #: minigalaxy/constants.py:35 msgid "Norwegian Bokmål" msgstr "Norja (kirjakieli)" #: minigalaxy/constants.py:36 msgid "Norwegian Nynorsk" msgstr "Norja (Nynorsk)" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "" "Levytilaa ei ole tarpeeksi pelin purkamiseen. Tarvitaan {} Saatavilla {}" #: data/ui/properties.ui:280 msgid "OK" msgstr "OK" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Avaa tiedostot" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Ole hyvä ja tarkista, että internet-yhteytesi on toiminnassa" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "Puola" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "Portugali" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Asetukset" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Asetukset" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Ensisijainen kieli peleille: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "Ominaisuudet" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "Ominaisuudet kohteelle {}" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Virkistä peliluettelo" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "Regedit-muokkaus" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "Venäjä" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Tallenna" #: data/ui/properties.ui:154 msgid "Show FPS in game:" msgstr "Näytä ruudunpäivitysnopeus pelissä:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Näytä Windows-pelit: " #. Has to end with ": " #: data/ui/preferences.ui:224 msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Näytä piilotetut pelit: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Näytä ainoastaan asennetut pelit" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "Yksinkertaistettu kiina" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "Espanja" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Pysy kirjautuneena:" #: data/ui/properties.ui:77 msgid "Store" msgstr "Kauppa" #: data/ui/properties.ui:63 msgid "Support" msgstr "Tuki" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "Ruotsi" #: minigalaxy/constants.py:29 msgid "System default" msgstr "Järjestelmän oletus" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "Asennus {} epäonnistui. Yritä uudelleen." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "Ensisijainen kieli jolle pelit ladataan" #: data/ui/preferences.ui:65 msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "Ensisijainen kieli jota minigalaxy itsessään käyttää" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "Ilmeni virhe noudettaessa latauslinkkiä!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "Tämä on sijainti johon pelit asennetaan" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "Perinteinen kiina" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "Turkki" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "Ukraina" #: data/ui/gametile.ui:66 msgid "Uninstall" msgstr "Poista asennus" #: data/ui/gametile.ui:51 msgid "Update" msgstr "Päivitä" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "Käytä tummaa teemaa: " #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "Muuttujat:" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "Versio" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "Mikäli pois päältä, sinua pyydetään kirjautumaan uudelleen aina Minigalaxyn " "käynnistyksessä" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "Tulisiko minigalaxyn käyttää tummaa teemaa vai ei" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Näytetäänkö Windows-pelit kirjastossa vaiko ei" #: data/ui/preferences.ui:221 msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Näytetäänkö piilotetut pelit kirjastossa vaiko ei" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "Luodaanko uusille peleille pikakuvakkeet vaiko ei" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "Wine-purku epäonnistui." #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "" "Wine-ohjelmaa ei löytynyt. Windows-pelien näyttämistä ei voida kytkeä päälle." #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "Winecfg-asetukset" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "lataa" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "ladataan…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "jonossa…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "asenna" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "asennetaan…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "pelaa" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "poistetaan asennusta…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "päivitetään…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} ei voitu purkaa." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "{} lataus epäonnistui." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} ei ole käytettävä polku" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} korruptoitui. Suorita lataus uudelleen." minigalaxy-1.1.0/data/po/fr.po000066400000000000000000000355471414231301100161550ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2021-10-23 16:33+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.4.2\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Un client GOG simple pour GNU/Linux" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "À propos" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "À propos" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "Ajouté à la fin de la commande utilisée pour lancer le jeu" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "Ajouté devant la commande utilisée pour lancer le jeu" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "Êtes-vous sûr de vouloir annuler le téléchargement {} ?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "Êtes-vous sûr de vouloir vous déconnecter de GOG ?" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "Êtes-vous sûr de vouloir désinstaller %s ?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Portugais Brésilien" #: data/ui/properties.ui:266 msgid "Cancel" msgstr "Annuler" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Annuler" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Chinois" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "Paramètres de la commande :" #: minigalaxy/ui/properties.py:103 msgid "Couldn't open store page" msgstr "Impossible d'ouvrir la page de la boutique" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "Impossible d'ouvrir la page de support" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "Créez des raccourcis dans le menu : " #: data/ui/gametile.ui:36 msgid "DLC" msgstr "DLC" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Danois" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "Erreur de téléchargement" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "Néerlandais" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "Anglais" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "Impossible de démarrer {} :" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "Impossible de récupérer la bibliothèque" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "Impossible de démarrer {} :" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "Finlandais" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "Français" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "Genre" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "Allemand" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Page GitHub" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "Cacher le jeu :" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Hongrois" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "L'extraction de l'Innoextract a échoué." #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "Innoextract n'est pas installé." #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Chemin d'installation : " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Installé" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Italien" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Japonais" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Conservez les installateurs après avoir téléchargé un jeu.\n" "Les installateurs sont stockés dans : {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Conserver les installateurs : " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Coréen" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "Langue : " #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Connexion" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Déconnexion" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "Aucun exécutable n'a été trouvé dans {}" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Norvégien" #: minigalaxy/constants.py:35 msgid "Norwegian Bokmål" msgstr "Norvégien Bokmål" #: minigalaxy/constants.py:36 msgid "Norwegian Nynorsk" msgstr "Norvégien Nynorsk" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "Pas assez d'espace pour extraire le jeu. Requis : {} Disponible : {}" #: data/ui/properties.ui:280 msgid "OK" msgstr "OK" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Ouvrir le dossier" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Veuillez vérifier votre connexion Internet" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "Polonais" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "Portugais" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Préférences" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Préférences" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Langue préférée : " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "Propriétés" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "Propriétés de {}" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Rafraîchir la liste de jeux" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "Regedit" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "Russe" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Sauvegarder" #: data/ui/properties.ui:154 msgid "Show FPS in game:" msgstr "Montrer les IPS en jeu :" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Montrer les jeux Windows : " #. Has to end with ": " #: data/ui/preferences.ui:224 msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Montrer les jeux cachés : " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Afficher uniquement les jeux installés" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "Chinois simplifié" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "Espagnol" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Rester connecté :" #: data/ui/properties.ui:77 msgid "Store" msgstr "Boutique" #: data/ui/properties.ui:63 msgid "Support" msgstr "Support" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "Suédois" #: minigalaxy/constants.py:29 msgid "System default" msgstr "Système par défaut" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "L'installation de {} a échoué. Veuillez réessayer." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "La langue préférée pour le téléchargement des jeux" #: data/ui/preferences.ui:65 msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "La langue préférée au démarrage de Minigalaxy" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "Il y a eu une erreur en essayant de récupérer le lien de téléchargement !\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "C'est ici que les jeux seront installés" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "Chinois traditionnel" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "Turc" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "Ukrainien" #: data/ui/gametile.ui:66 msgid "Uninstall" msgstr "Désinstaller" #: data/ui/gametile.ui:51 msgid "Update" msgstr "Mise à jour" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "Utilisez le thème sombre : " #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "Paramètres variables :" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "Version" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "Lorsque cette option est désactivée, il vous sera demandé de vous connecter " "à chaque démarrage de Minigalaxy" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "Minigalaxy doit-il utiliser un thème sombre ou non" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Si les jeux Windows sont affichés dans la bibliothèque ou non" #: data/ui/preferences.ui:221 msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Si les jeux cachés sont montrés dans la bibliothèque ou non" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "" "Si les raccourcis sont créés pour les jeux nouvellement installés ou non" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "L'extraction de Wine a échoué." #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "" "Wine n'a pas été trouvé. L'affichage des jeux Windows ne peut pas être " "activé." #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "Winecfg" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "télécharger" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "téléchargement…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "dans la file d'attente…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "installer" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "installation…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "jouer" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "désinstallation…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "mise à jour…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} n'a pas pu être décompressé." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "{} n'a pas pu être téléchargé." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} n'est pas un chemin utilisable" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} a été corrompu. Veuillez le télécharger à nouveau." #~ msgid "Couldn't connect to GOG servers" #~ msgstr "Impossible de se connecter aux serveurs de GOG" #~ msgid "Install Wine to enable this feature" #~ msgstr "Installez Wine pour activer cette fonction" #~ msgctxt "Wine Settings" #~ msgid "Settings" #~ msgstr "Paramètres" #~ msgctxt "show_fps_tooltip" #~ msgid "" #~ "Show the framerate while playing games. Only works with AMD and Nvidia " #~ "graphics cards." #~ msgstr "" #~ "Montrez le framerate en jouant. Ne fonctionne qu'avec les cartes " #~ "graphiques AMD et Nvidia." #~ msgid "" #~ "Artur Wróblewski\n" #~ "BlindJerobine\n" #~ "Esdras Tarsis\n" #~ "Hüseyin Fahri Uzun\n" #~ "Jan Kjetil Myklebust\n" #~ "Jeff Huang\n" #~ "kimmalmo\n" #~ "ProTheory8\n" #~ "thomasb22" #~ msgstr "" #~ "Artur Wróblewski\n" #~ "BlindJerobine\n" #~ "Esdras Tarsis\n" #~ "Hüseyin Fahri Uzun\n" #~ "Jan Kjetil Myklebust\n" #~ "Jeff Huang\n" #~ "kimmalmo\n" #~ "ProTheory8\n" #~ "thomasb22" #~ msgid "Couldn't start subprocess" #~ msgstr "Impossible de démarrer le sous-processus" #~ msgid "No error message was returned" #~ msgstr "Aucun message d'erreur n'a été renvoyé" #~ msgid "Minigalaxy is now running in offline mode" #~ msgstr "Minigalaxy fonctionne maintenant en mode hors ligne" #~ msgid "Try again with an active internet connection" #~ msgstr "Essayez à nouveau avec une connexion Internet active" minigalaxy-1.1.0/data/po/it_IT.po000066400000000000000000000302621414231301100165430ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2021-05-25 19:07+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.4.3\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Un semplice client Linux per GOG" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "Informazioni" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "Informazioni" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "Sei sicuro di voler annullare lo scaricamento di {}?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "Sei sicuro di voler disinstallare %s?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Portoghese Brasiliano" #: data/ui/properties.ui:266 msgid "Cancel" msgstr "Annulla" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Annulla" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Cinese" # I don't know where it's used, so this translation might be wrong. #: data/ui/properties.ui:180 #, fuzzy msgid "Command flags:" msgstr "Opzione dei comandi" #: minigalaxy/ui/properties.py:103 msgid "Couldn't open store page" msgstr "Apertura della pagina del negozio non riuscita" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "Apertura della pagina di supporto non riuscita" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "" #: data/ui/gametile.ui:36 msgid "DLC" msgstr "DLC" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Danese" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "Errore di download" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "Olandese" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "Inglese" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "Installazione di {} fallita" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "Recupero della libreria fallito" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "Apertura di {} fallita:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "Finlandese" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "Francese" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "Tedesco" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Pagina di Github" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Ungherese" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "" #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "" #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Percorso di installazione: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Installati" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Italiano" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Giapponese" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Mantieni i file di installazione dopo aver scaricato un gioco.\n" "I file di installazione sono salvati in: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Mantieni file di installazione: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Coreano" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "" #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Accedi" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Disconnettiti" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "Nessun eseguibile trovato in {}" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Norvegese" #: minigalaxy/constants.py:35 #, fuzzy msgid "Norwegian Bokmål" msgstr "Norvegese" #: minigalaxy/constants.py:36 #, fuzzy msgid "Norwegian Nynorsk" msgstr "Norvegese" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "" #: data/ui/properties.ui:280 msgid "OK" msgstr "OK" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Apri cartella" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Controlla la tua connessione a internet" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "Polacco" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "Portoghese" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Impostazioni" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Impostazioni" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Lingua preferita: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "Proprietà" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "Proprietà di {}" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Aggiorna lista dei giochi" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "Regedit" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "Russo" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Salva" #: data/ui/properties.ui:154 msgid "Show FPS in game:" msgstr "Visualizza FPS in gioco:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Visualizza giochi di Windows: " #. Has to end with ": " #: data/ui/preferences.ui:224 #, fuzzy msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Visualizza giochi di Windows: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Visualizza solo i giochi installati" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "Spagnolo" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Mantieni l'accesso:" #: data/ui/properties.ui:77 msgid "Store" msgstr "Negozio" #: data/ui/properties.ui:63 msgid "Support" msgstr "Supporto" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "Svedese" #: minigalaxy/constants.py:29 msgid "System default" msgstr "" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "L'installazione di {} è fallita. Riprova." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "La lingua in cui si preferisce avere i giochi scaricati" #: data/ui/preferences.ui:65 #, fuzzy msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "La lingua in cui si preferisce avere i giochi scaricati" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "C'è stato un errore cercando di recuperare il link per lo scaricamento!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "Qui è dove i giochi verranno installati" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "Turco" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "" #: data/ui/gametile.ui:66 msgid "Uninstall" msgstr "Disinstalla" #: data/ui/gametile.ui:51 msgid "Update" msgstr "Aggiorna" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "" # I don't know where it's used, so this translation might be wrong. #: data/ui/properties.ui:167 #, fuzzy msgid "Variable flags:" msgstr "Opzione delle variabili" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "Se disabilitato ti verrà richiesto di fare l'accesso ogni volta che avvierai " "Minigalaxy" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Se abilitato visualizza anche i giochi di Windows nella libreria" #: data/ui/preferences.ui:221 #, fuzzy msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Se abilitato visualizza anche i giochi di Windows nella libreria" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "" #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "" "Wine non è stato trovato. Non potrai abilitare la Visualizzazione dei giochi " "di Windows." #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "Winecfg" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "scarica" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "scaricando…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "in coda…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "installa" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "installando…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "gioca" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "disinstallando…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "aggiornando…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "Estrazione di {} non riuscita." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "Scaricamento di {} fallito." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} non è un percorso utilizzabile" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} era corrotto. Riscaricalo." #~ msgid "Couldn't connect to GOG servers" #~ msgstr "Connessione ai server di GOG non riuscita" minigalaxy-1.1.0/data/po/nb_NO.po000066400000000000000000000307421414231301100165310ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2020-04-11 13:17+0200\n" "Last-Translator: Kim Malmo \n" "Language-Team: \n" "Language: nb_NO\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.2.4\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Enkel GOG klient for Linux" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "Om" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "Om" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "Er du sikker på at du vil avbryte nedlastingen av {}?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "Er du sikker på at du vil avinstallere %s?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Brasiliansk Portugisisk" #: data/ui/properties.ui:266 #, fuzzy msgid "Cancel" msgstr "Avbryt" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Avbryt" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Kinesisk" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "" #: minigalaxy/ui/properties.py:103 #, fuzzy msgid "Couldn't open store page" msgstr "Kunne ikke åpne siden for støtte" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "Kunne ikke åpne siden for støtte" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "" #: data/ui/gametile.ui:36 msgid "DLC" msgstr "" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Dansk" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "Feil ved nedlasting" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "Nederlandsk" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "Engelsk" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "Kunne ikke installere {}:" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "Kunne ikke hente bibliotek" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "Kunne ikke starte {}:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "Finsk" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "Fransk" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "Tysk" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Github side" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Ungarsk" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "" #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "" #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Installasjonssti: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Installert" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Italiensk" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Japansk" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Behold installere etter nedlasting av spill.\n" "Installere er plassert i: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Behold installere: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Koreansk" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "" #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Innlogging" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Logg ut" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "Ingen kjørbar fil funnet i {}" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Norsk" #: minigalaxy/constants.py:35 #, fuzzy msgid "Norwegian Bokmål" msgstr "Norsk" #: minigalaxy/constants.py:36 #, fuzzy msgid "Norwegian Nynorsk" msgstr "Norsk" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "" #: data/ui/properties.ui:280 msgid "OK" msgstr "" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Åpne filer" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Vennligst sjekk internettforbindelsen din" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "Polsk" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "Portugisisk" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Brukervalg" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Brukervalg" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Foretrukket språk: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Oppdater spillisten" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "Russisk" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Lagre" #: data/ui/properties.ui:154 #, fuzzy msgid "Show FPS in game:" msgstr "Vis FPS i spill:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Vis Windows spill: " #. Has to end with ": " #: data/ui/preferences.ui:224 #, fuzzy msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Vis Windows spill: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Vis kun installerte spill" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "Spansk" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Forbli pålogget:" #: data/ui/properties.ui:77 #, fuzzy msgid "Store" msgstr "Butikkside" #: data/ui/properties.ui:63 #, fuzzy msgid "Support" msgstr "Støtte" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "Svensk" #: minigalaxy/constants.py:29 msgid "System default" msgstr "" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "Feil ved installasjon av {}. Vennligst prøv igjen." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "Foretrukket språk for nedlasting av spill" #: data/ui/preferences.ui:65 #, fuzzy msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "Foretrukket språk for nedlasting av spill" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "Det oppstod en feil ved henting av nedlastingslenken!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "Dette er hvor spill vil bli installert" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "Tyrkisk" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "" #: data/ui/gametile.ui:66 #, fuzzy msgid "Uninstall" msgstr "Avinstaller" #: data/ui/gametile.ui:51 #, fuzzy msgid "Update" msgstr "Oppdater" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "" #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "Om deaktivert vil du bli spurt om å logge inn hver gang Minigalaxy starter" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Om Windows spill skal vises i bibloteket eller ikke" #: data/ui/preferences.ui:221 #, fuzzy msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Om Windows spill skal vises i bibloteket eller ikke" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "" #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "" #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "last ned" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "laster ned…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "i kø…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "installer" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "installerer…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "spill" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "avinstallerer…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "oppdaterer…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} kunne ikke pakkes ut." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "{} kunne ikke lastes ned." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} er ikke en brukbar sti" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} ble ødelagt. Vennligst last ned på nytt." #~ msgid "Couldn't connect to GOG servers" #~ msgstr "Kunne ikke koble til GOG tjenerne" #~ msgid "Install Wine to enable this feature" #~ msgstr "Installér Wine for å aktivere denne egenskapen" #~ msgctxt "Wine Settings" #~ msgid "Settings" #~ msgstr "Innstillinger" #~ msgctxt "show_fps_tooltip" #~ msgid "" #~ "Show the framerate while playing games. Only works with AMD and Nvidia " #~ "graphics cards." #~ msgstr "" #~ "Vis bildeoppdateringen mens du spiller. Kun mulig med AMD og Nvidia " #~ "grafikk-kort." #~ msgid "Couldn't start subprocess" #~ msgstr "Kunne ikke starte underprosess" #~ msgid "No error message was returned" #~ msgstr "Ingen feilmelding ble returnert" #~ msgid "Minigalaxy is now running in offline mode" #~ msgstr "Minigalaxy kjører i frakoblet modus" #~ msgid "Try again with an active internet connection" #~ msgstr "Prøv igjen med en aktiv internettforbindelse" minigalaxy-1.1.0/data/po/nl.po000066400000000000000000000327751414231301100161570ustar00rootroot00000000000000# Dutch translations for minigalaxy package. # Copyright (C) 2019 THE minigalaxy'S COPYRIGHT HOLDER # This file is distributed under the same license as the minigalaxy package. # Wouter Wijsman , 2019. # msgid "" msgstr "" "Project-Id-Version: minigalaxy 0.9.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2021-09-30 11:00+0200\n" "Last-Translator: Wouter Wijsman \n" "Language-Team: Dutch\n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 2.3\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Een simpele GOG client voor Linux" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "Over Minigalaxy" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "Over Minigalaxy" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "" "Wordt aan het commando dat gebruikt wordt om de game te starten toegevoegd" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "" "Wordt voor het commando dat gebruikt wordt om de game te starten toegevoegd" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "Weet je zeker dat je de {} download wilt stoppen?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "Weet je zeker dat je uit wilt loggen?" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "Weet je zeker dat je %s wilt verwijderen?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Braziliaans-Portugees" #: data/ui/properties.ui:266 msgid "Cancel" msgstr "Annuleren" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Annuleren" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Chinees" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "Commando flaggetjes:" #: minigalaxy/ui/properties.py:103 msgid "Couldn't open store page" msgstr "De pagina kon niet worden geopend" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "De ondersteuningspagina kon niet worden geopend" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "Maak menusnelkoppelingen: " #: data/ui/gametile.ui:36 msgid "DLC" msgstr "DLC" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Deens" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "Downloadfout" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "Nederlands" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "Engels" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "Kon {} niet geïnstalleerd worden:" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "De lijst me games kon niet opgehaald worden" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "Kon {} niet starten:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "Fins" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "Frans" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "Genre" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "Duits" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Github pagina" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "Verberg game:" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Hongaars" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "Innoextract kon de game niet uitpakken." #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "Innoextract is niet geïnstalleerd." #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Installatiepad: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Geïnstalleerd" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Italiaans" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Japans" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Behoud installatiebestanden nadat een game is gedownload.\n" "Installatie bestanden worden opgeslagen in: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Behoud installatiebestanden: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Koreaans" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "Taal: " #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Log in" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Uitloggen" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "Geen programma gevonden in {}" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Noors" #: minigalaxy/constants.py:35 msgid "Norwegian Bokmål" msgstr "Noors (Bokmål)" #: minigalaxy/constants.py:36 msgid "Norwegian Nynorsk" msgstr "Noors (Nynorsk)" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "Niet genoeg ruimt om" #: data/ui/properties.ui:280 msgid "OK" msgstr "OK" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Bestanden openen" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Controleer je internetverbinding" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "Pools" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "Portugees" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Voorkeuren" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Voorkeuren" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Voorkeurstaal: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "Instellingen" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "Instellingen van {}" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Haal gamelijst opnieuw op" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "Regedit" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "Russisch" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Opslaan" #: data/ui/properties.ui:154 msgid "Show FPS in game:" msgstr "Laat FPS zijn tijdens het spelen:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Toon games voor Windows: " #. Has to end with ": " #: data/ui/preferences.ui:224 msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Toon verborgen games: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Laat alleen geïnstalleerde games zien" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "Vereenvoudigd Chinees" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "Spaans" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Blijf ingelogd:" #: data/ui/properties.ui:77 msgid "Store" msgstr "Winkelpagina" #: data/ui/properties.ui:63 msgid "Support" msgstr "Ondersteuning" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "Zweeds" #: minigalaxy/constants.py:29 msgid "System default" msgstr "Systeemsstandard" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "De installatie van {} is mislukt. Probeer het opnieuw." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "De voorkeurstaal voor gedownloadde games" #: data/ui/preferences.ui:65 msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "De voorkeurstaal voorMinigalaxy bij het starten" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "Er is een fout opgetreden bij het ophalen van de downloadlink!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "Dit is waar games geinstalleerd worden" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "Traditioneel Chinees" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "Turks" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "Oekraïens" #: data/ui/gametile.ui:66 msgid "Uninstall" msgstr "Verwijderen" #: data/ui/gametile.ui:51 msgid "Update" msgstr "Update" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "Gebruik donker thema: " #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "Variabelen:" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "Versie" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "Als deze optie uitgeschakeld is, zal Minigalaxy altijd het inlogscherm tonen " "bij het opstarten" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "Of Minigalaxy een donkerder thema gebruikt of niet" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Of Windows games zichtbaar zijn in de bibliotheek" #: data/ui/preferences.ui:221 msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Of verborgen games zichtbaar zijn in de bibliotheek" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "" "Of snelkoppelingen in het menu van het besturingssysteem aangemaakt worden " "voor nieuw geïnstalleerde games" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "Het uitpakken met wine is mislukt." #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "" "Wine kon niet gevonden worden. Het tonen van Windows games kan niet aangezet " "worden." #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "Winecfg" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "download" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "downloaden…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "in de wachtrij…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "installeren" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "installeren…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "spelen" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "verwijderen…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "updaten…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} kan niet uitgepakt worden." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "{} kon niet gedownload worden." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} is geen bruikbaar pad" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} is beschadigd. Download het opnieuw." #~ msgid "Couldn't connect to GOG servers" #~ msgstr "Er kon geen verbinding gemaakt worden met de GOG servers" #~ msgid "Install Wine to enable this feature" #~ msgstr "Installeer Wine om deze feature te te kunnen gebruiken" #~ msgctxt "Wine Settings" #~ msgid "Settings" #~ msgstr "Instellingen" #~ msgctxt "show_fps_tooltip" #~ msgid "" #~ "Show the framerate while playing games. Only works with AMD and Nvidia " #~ "graphics cards." #~ msgstr "" #~ "Laat de hoeveelheid beelden per seconde on het scherm zien tijdens het " #~ "spelen van games. Dit werkt alleen met AMD en Nvidia grafische kaarten." #~ msgid "Couldn't start subprocess" #~ msgstr "Het subprocess kon niet gestart worden" #~ msgid "No error message was returned" #~ msgstr "Er is geen foutmelding afgegeven" #~ msgid "Minigalaxy is now running in offline mode" #~ msgstr "Minigalaxy is nu in offline modus" #~ msgid "Try again with an active internet connection" #~ msgstr "Probeer het opnieuw als u weer met het internet vebonden bent" minigalaxy-1.1.0/data/po/nn_NO.po000066400000000000000000000344601414231301100165460ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2021-10-04 11:33+0200\n" "Last-Translator: Jan Kjetil Myklebust\n" "Language-Team: \n" "Language: nb_NO\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.2.4\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Ein enkel GOG klient for Linux" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "Om" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "Om" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "Lagt til bakom kommandoen som er brukt for å starte spelet" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "Lagt til framføre kommandoen som er brukt for å starte spelet" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "Er du sikker på at du vil avbryte nedlastinga av {}?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "Er du sikker på at du vil logge ut av GOG?" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "Er du sikker på at du vil avinstallere %s?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Brasiliansk Portugisisk" #: data/ui/properties.ui:266 msgid "Cancel" msgstr "Avbryt" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Avbryt" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Kinesisk" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "Kommandolinjeflagg:" #: minigalaxy/ui/properties.py:103 msgid "Couldn't open store page" msgstr "Kunne ikkje opne produktsida" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "Kunne ikkje opne hjelpesida" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "Opprett menysnarvegar: " #: data/ui/gametile.ui:36 msgid "DLC" msgstr "DLC" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Dansk" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "Nedlastingsfeil" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "Nederlandsk" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "Engelsk" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "Klarte ikkje å installere {}" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "Klarte ikkje å hente bibliotek" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "Klarte ikkje å starte {}:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "Finsk" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "Fransk" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "Sjanger" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "Tysk" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Github-side" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "Skjul spel:" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Ungarsk" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "Innoextract utpakking feila." #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "Innoextract er ikkje installert." #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Installasjonssti: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Installert" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Italiensk" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Japansk" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Behalde installeringsfiler etter nedlasting av spel.\n" "Installerarar ligg under: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Behalde installerarar: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Koreansk" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "Språk: " #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Inlogging" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Logg ut" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "Inga køyrbar fil funnen i {}" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Norsk" #: minigalaxy/constants.py:35 msgid "Norwegian Bokmål" msgstr "Norsk Bokmål" #: minigalaxy/constants.py:36 msgid "Norwegian Nynorsk" msgstr "Norsk Nynorsk" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "Ikkje nok plass til å pakke ut spelet. Trengs: {} Tilgjengeleg: {}" #: data/ui/properties.ui:280 msgid "OK" msgstr "OK" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Opne filer" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Ver venleg og sjekk internettilkoplinga di" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "Polsk" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "Portugisisk" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Brukarval" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Brukarval" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Foretrukke språk: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "Eigenskapar" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "Eigenskapar for {}" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Oppdater spelelista" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "Regedit" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "Russisk" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Lagre" #: data/ui/properties.ui:154 msgid "Show FPS in game:" msgstr "Vis FPS i spelet:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Vis spel for Windows: " #. Has to end with ": " #: data/ui/preferences.ui:224 msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Vis spel for Windows: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Vis berre installerte spel" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "Foreinkla Kinesisk" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "Spansk" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Bli verande pålogga:" #: data/ui/properties.ui:77 msgid "Store" msgstr "Produktside" #: data/ui/properties.ui:63 msgid "Support" msgstr "Støtte" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "Svensk" #: minigalaxy/constants.py:29 msgid "System default" msgstr "System standardverdi" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "Installasjonen av {} feila. Ver venleg og prøv på nytt." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "Foretrukke språk for nedlasting av spel" #: data/ui/preferences.ui:65 msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "Foretrukke språk ved oppstart av Minigalaxy" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "Ein feil oppstod ved henting av nedlastingslink!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "Spel vil verte installerte her" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "Tradisjonell kinesisk" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "Tyrkisk" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "Ukrainsk" #: data/ui/gametile.ui:66 msgid "Uninstall" msgstr "Avinstaller" #: data/ui/gametile.ui:51 msgid "Update" msgstr "Oppdater" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "Bruk mørkt tema: " #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "Variabelflagg:" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "Versjon" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "Viss deaktivert vil du bli spurd om å logge på kvar gong Minigalaxy starter" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "Om Minigalaxy skal nytte mørtk tema eller ikkje" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Om spel for Windows vert vist i biblioteket eller ikkje" #: data/ui/preferences.ui:221 msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Om skjulte spel vert vist i biblioteket eller ikkje" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "Om snarvegar blir oppretta for nyinstallerte spel eller ikkje" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "Wine utpakking feila." #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "Fann ikkje Wine. Kan ikkje skru på vising av Windows-spel." #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "Winecfg" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "last ned" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "lastar ned…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "i kø…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "installer" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "installerar…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "spel" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "avinstallerar…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "oppdaterar…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} kunne ikkje pakkast ut." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "{} kunne ikkje lastast ned." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} er ikkje ein brukbar sti" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} var korrumpert. Ver venleg å last den ned på ny." #~ msgid "Couldn't connect to GOG servers" #~ msgstr "Kunne ikkje kople til GOG sine tenarar" #~ msgid "Install Wine to enable this feature" #~ msgstr "Installer Wine for å aktivere denne funksjonen" #~ msgctxt "Wine Settings" #~ msgid "Settings" #~ msgstr "Innstillingar" #~ msgctxt "show_fps_tooltip" #~ msgid "" #~ "Show the framerate while playing games. Only works with AMD and Nvidia " #~ "graphics cards." #~ msgstr "" #~ "Vis framerate medan du speler spel. Fungerar berre med AMD og Nvidia " #~ "grafikkort." #~ msgid "" #~ "Artur Wróblewski\n" #~ "BlindJerobine\n" #~ "Esdras Tarsis\n" #~ "Hüseyin Fahri Uzun\n" #~ "Jan Kjetil Myklebust\n" #~ "Jeff Huang\n" #~ "kimmalmo\n" #~ "ProTheory8\n" #~ "thomasb22" #~ msgstr "" #~ "Artur Wróblewski\n" #~ "BlindJerobine\n" #~ "Esdras Tarsis\n" #~ "Hüseyin Fahri Uzun\n" #~ "Jan Kjetil Myklebust\n" #~ "Jeff Huang\n" #~ "kimmalmo\n" #~ "ProTheory8\n" #~ "thomasb22" #~ msgid "Couldn't start subprocess" #~ msgstr "Kunne ikkje starte underprosess" #~ msgid "No error message was returned" #~ msgstr "Inga feilmelding vart returnert" #~ msgid "Minigalaxy is now running in offline mode" #~ msgstr "Minigalaxy køyrer i fråkopla modus" #~ msgid "Try again with an active internet connection" #~ msgstr "Prøv igjen med ein aktiv internettilkopling" minigalaxy-1.1.0/data/po/pl.po000066400000000000000000000327251414231301100161540ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Artur Krzysztof Wróblewski , 2020-2021. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2021-09-30 10:17+0200\n" "Last-Translator: \n" "Language-Team: Artur Wróblewski\n" "Language: pl_PL\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.2.3\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 " "|| n%100>14) ? 1 : 2);\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Prosty klient GOG dla Linuksa" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "O programie" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "O programie" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "Dodano na końcu polecenie służące do uruchomienia gry" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "Dodano przed komendą służącą do uruchomienia gry" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "Czy na pewno chcesz anulować pobieranie {}?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "Czy na pewno chcesz wylogować się z GOG?" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "Czy na pewno chcesz odinstalować %s?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Portugalski brazylijski" #: data/ui/properties.ui:266 msgid "Cancel" msgstr "Anuluj" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Anuluj" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Chiński" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "Flagi poleceń:" #: minigalaxy/ui/properties.py:103 msgid "Couldn't open store page" msgstr "Nie można otworzyć strony w sklepie" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "Nie można otworzyć strony pomocy technicznej" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "Utwórz skróty w menu: " #: data/ui/gametile.ui:36 msgid "DLC" msgstr "DLC" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Duński" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "Błąd pobierania" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "Holenderski" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "Angielski" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "Instalacja {} nie powiodła się" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "Nie można pobrać biblioteki" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "Nie można uruchomić {}:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "Fiński" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "Francuski" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "Gatunek" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "Niemiecki" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Strona GitHub" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "Ukryj grę:" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Węgierski" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "Ekstrakcja Innoextract nie powiodła się." #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "Innoextract nie jest zainstalowany." #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Ścieżka instalacji: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Zainstalowane" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Włoski" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Japoński" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Zachowaj pliki instalacyjne po pobraniu gry.\n" "Pliki instalacyjne są przechowywane w: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Zachowaj pliki instalacyjne: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Koreański" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "Język: " #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Zaloguj się" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Wyloguj" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "Nie znaleziono pliku wykonywalnego w {}" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Norweski" #: minigalaxy/constants.py:35 msgid "Norwegian Bokmål" msgstr "Norweski Bokmål" #: minigalaxy/constants.py:36 msgid "Norwegian Nynorsk" msgstr "Norweski Nynorsk" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "" #: data/ui/properties.ui:280 msgid "OK" msgstr "OK" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Otwórz pliki" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Sprawdź swoje połączenie internetowe" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "Polski" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "Portugalski" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Ustawienia" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Ustawienia" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Preferowany język: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "Właściwości" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "Właściwości {}" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Odśwież listę gier" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "Regedit" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "Rosyjski" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Zapis" #: data/ui/properties.ui:154 msgid "Show FPS in game:" msgstr "Pokaż FPS w grze:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Wyświetl gry dla Systemu Windows: " #. Has to end with ": " #: data/ui/preferences.ui:224 msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Pokaż ukryte gry: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Pokaż tylko zainstalowane gry" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "Chiński uproszczony" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "Hiszpański" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Pozostań zalogowany:" #: data/ui/properties.ui:77 msgid "Store" msgstr "Sklep" #: data/ui/properties.ui:63 msgid "Support" msgstr "Wsparcie" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "Szwedzki" #: minigalaxy/constants.py:29 msgid "System default" msgstr "Domyślny systemu" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "Instalacja {} zakończona niepowodzeniem. Proszę spróbować ponownie." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "Preferowany język pobierania gier w" #: data/ui/preferences.ui:65 msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "Preferowany język podczas uruchamiania Minigalaxy" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "Wystąpił błąd podczas próby pozyskania linku do pobrania!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "W tym miejscu zostaną zainstalowane gry" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "Chinski tradycyjny" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "Turecki" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "" #: data/ui/gametile.ui:66 msgid "Uninstall" msgstr "Odinstaluj" #: data/ui/gametile.ui:51 msgid "Update" msgstr "Aktualizuj" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "Użyj ciemnego motywu: " #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "Flagi zmienne:" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "Wersja" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "Po wyłączeniu zostanie wyświetlony monit o zalogowanie się przy każdym " "uruchomieniu Minigalaxy" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "Czy Minigalaxy ma używać ciemnego motywu, czy nie" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "" "Czy gry natywnie przeznaczone dla systemu Windows mają być wyświetlane w " "bibliotece, czy nie" #: data/ui/preferences.ui:221 msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Czy ukryte gry są wyświetlane w bibliotece, czy nie" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "Czy skróty mają być tworzone dla nowo zainstalowanych gier, czy nie" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "Ekstrakcja Wine nie powiodła się." #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "" "Wine nie został znaleziony. Nie można włączyć wyświetlania gier systemu " "Windows." #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "Winecfg" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "pobierz" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "pobieranie…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "w kolejce…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "zainstaluj" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "instalowanie…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "graj" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "odinstalowywanie…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "aktualizowanie..." #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} nie można rozpakować." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "{} nie udało się pobrać." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} nie jest poprawną ścieżką" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} jest uszkodzony. Pobierz go ponownie." #~ msgid "Couldn't connect to GOG servers" #~ msgstr "Nie można połączyć się z serwerami GOG" #~ msgid "Install Wine to enable this feature" #~ msgstr "Zainstaluj Wine, aby włączyć tę funkcję" #~ msgctxt "Wine Settings" #~ msgid "Settings" #~ msgstr "Ustawienia" #~ msgctxt "show_fps_tooltip" #~ msgid "" #~ "Show the framerate while playing games. Only works with AMD and Nvidia " #~ "graphics cards." #~ msgstr "" #~ "Pokaż ilość klatek na sekundę FPS w trakcie gry. Działa tylko z kartami " #~ "graficznymi AMD i Nvidia." #~ msgid "Couldn't start subprocess" #~ msgstr "Nie można uruchomić podprocesu" #~ msgid "No error message was returned" #~ msgstr "Nie został zwrócony żaden komunikat o błędzie" #~ msgid "Minigalaxy is now running in offline mode" #~ msgstr "Minigalaxy jest teraz uruchomiony w trybie offline" #~ msgid "Try again with an active internet connection" #~ msgstr "Spróbuj ponownie z aktywnym połączeniem internetowym" minigalaxy-1.1.0/data/po/pt_BR.po000066400000000000000000000313461414231301100165450ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Esdras Tarsis , 2020. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2020-11-17 03:06-0300\n" "Last-Translator: Esdras Tarsis \n" "Language-Team: \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.4.1\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Um cliente simples da GOG para o Linux" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "Sobre" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "Sobre" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "Tem certeza de que deseja cancelar o download do game {}?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "Você tem certeza de que deseja desinstalar %s?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Português Brasileiro" #: data/ui/properties.ui:266 #, fuzzy msgid "Cancel" msgstr "Cancelar" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Cancelar" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Chinês" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "" #: minigalaxy/ui/properties.py:103 #, fuzzy msgid "Couldn't open store page" msgstr "Não foi possível abrir a página de suporte" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "Não foi possível abrir a página de suporte" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "" #: data/ui/gametile.ui:36 msgid "DLC" msgstr "DLC" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Dinamarquês" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "Erro ao baixar" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "Holandês" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "Inglês" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "Falha ao instalar {}" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "Falha ao recuperar a biblioteca" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "Falha ao iniciar {}:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "Finlandês" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "Francês" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "Alemão" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Página no GitHub" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Húngaro" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "" #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "" #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Caminho de instalação: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Instalados" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Italiano" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Japonês" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Manter instaladores após baixar um jogo.\n" "Instaladores são armazenados em: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Manter instaladores: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Coreano" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "" #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Login" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Logout" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "Nenhum executável foi encontrado em {}" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Norueguês" #: minigalaxy/constants.py:35 #, fuzzy msgid "Norwegian Bokmål" msgstr "Norueguês" #: minigalaxy/constants.py:36 #, fuzzy msgid "Norwegian Nynorsk" msgstr "Norueguês" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "" #: data/ui/properties.ui:280 msgid "OK" msgstr "" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Abrir arquivos" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Por favor, verifique sua conexão à internet" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "Polonês" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "Português" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Preferências" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Preferências" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Idioma preferido: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Recarregar lista de jogos" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "Russo" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Salvar" #: data/ui/properties.ui:154 #, fuzzy msgid "Show FPS in game:" msgstr "Mostrar FPS nos jogos:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Mostrar jogos para Windows: " #. Has to end with ": " #: data/ui/preferences.ui:224 #, fuzzy msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Mostrar jogos para Windows: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Mostrar apenas jogos instalados" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "Espanhol" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Permanecer conectado:" #: data/ui/properties.ui:77 #, fuzzy msgid "Store" msgstr "Página da Loja" #: data/ui/properties.ui:63 #, fuzzy msgid "Support" msgstr "Suporte" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "Sueco" #: minigalaxy/constants.py:29 msgid "System default" msgstr "" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "A instalação de {} falhou. Por favor tente novamente." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "O idioma preferido para baixar os jogos" #: data/ui/preferences.ui:65 #, fuzzy msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "O idioma preferido para baixar os jogos" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "Ocorreu um erro ao tentar obter o link de download!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "É onde os jogos serão instalados" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "Turco" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "" #: data/ui/gametile.ui:66 #, fuzzy msgid "Uninstall" msgstr "Desinstalar" #: data/ui/gametile.ui:51 #, fuzzy msgid "Update" msgstr "Atualizar" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "" #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "Quando desativado, você será solicitado a fazer login sempre que o " "Minigalaxy for iniciado" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Mostrar jogos para Windows na biblioteca ou não" #: data/ui/preferences.ui:221 #, fuzzy msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Mostrar jogos para Windows na biblioteca ou não" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "" #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "" #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "Baixar" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "Baixando…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "na fila…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "Instalar" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "Instalando…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "Jogar" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "Desinstalando…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "Atualizando…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} não pode ser descompactado." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "{} falhou ao realizar o download." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} não é um caminho utilizável" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} está corrompido. Por favor faça o download novamente." #~ msgid "Couldn't connect to GOG servers" #~ msgstr "Não foi possível conectar aos servidores da GOG" #~ msgid "Install Wine to enable this feature" #~ msgstr "Instale o Wine para habilitar esse recurso" #~ msgctxt "Wine Settings" #~ msgid "Settings" #~ msgstr "Configurações" #~ msgctxt "show_fps_tooltip" #~ msgid "" #~ "Show the framerate while playing games. Only works with AMD and Nvidia " #~ "graphics cards." #~ msgstr "" #~ "Mostrar a taxa de quadros enquanto joga. Funciona apenas com placas " #~ "gráficas AMD e Nvidia." #~ msgid "Couldn't start subprocess" #~ msgstr "Não foi possível iniciar o subprocesso" #~ msgid "No error message was returned" #~ msgstr "Nenhuma mensagem de erro foi retornada" #~ msgid "Minigalaxy is now running in offline mode" #~ msgstr "Minigalaxy está rodando no modo offline" #~ msgid "Try again with an active internet connection" #~ msgstr "Tente novamente com uma conexão ativa com a internet" minigalaxy-1.1.0/data/po/ru_RU.po000066400000000000000000000347441414231301100166000ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # Artem Polishchuk , 2020. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2021-11-05 18:00+0300\n" "Last-Translator: Artem Polishchuk \n" "Language-Team: \n" "Language: ru_RU\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.4.1\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Простой клиент GOG для Linux" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "О Minigalaxy" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "О Minigalaxy" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "Добавляется в конце команды запуска игры" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "Добавляется в начале команды запуска игры" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "Вы уверены, что хотите отменить загрузку {}?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "Вы уверены, что хотите выйти из GOG?" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "Вы уверены, что хотите удалить %s?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Бразильский португальский" #: data/ui/properties.ui:266 msgid "Cancel" msgstr "Отменить" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Отменить" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Китайский" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "Флаги команд:" #: minigalaxy/ui/properties.py:103 msgid "Couldn't open store page" msgstr "Не удалось открыть страницу магазина" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "Не удалось открыть страницу поддержки" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "Создавать ярлыки в меню: " #: minigalaxy/constants.py:30 msgid "Czech" msgstr "Чешский" #: data/ui/gametile.ui:36 msgid "DLC" msgstr "Дополнения" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Датский" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "Ошибка загрузки" #: minigalaxy/constants.py:10 minigalaxy/constants.py:31 msgid "Dutch" msgstr "Нидерландский" #: minigalaxy/constants.py:11 minigalaxy/constants.py:32 msgid "English" msgstr "Английский" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" "Не удалось изменить язык программы. Убедитесь, что на вашей системе " "сгенерирована локаль." #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "Не удалось установить {}" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "Не удалось получить библиотеку" #: minigalaxy/launcher.py:34 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "Не удалось запустить {}:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:33 msgid "Finnish" msgstr "Финский" #: minigalaxy/constants.py:13 minigalaxy/constants.py:34 msgid "French" msgstr "Французский" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "Жанр" #: minigalaxy/constants.py:14 minigalaxy/constants.py:35 msgid "German" msgstr "Немецкий" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Страница на Github" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "Скрывать игру:" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Венгерский" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "Не удалось извлечь игру с помощью Innoextract." #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "Не установлен Innoextract." #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Путь установки: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Установленные" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Итальянский" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Японский" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Сохранять файлы установки после загрузки игры.\n" "Файлы установки хранятся в: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Сохранять файлы установки: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Корейский" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "Язык: " #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Войти" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Выйти" #: minigalaxy/launcher.py:179 msgid "No executable was found in {}" msgstr "Не найден запускаемый файл в {}" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Норвежский" #: minigalaxy/constants.py:36 msgid "Norwegian Bokmål" msgstr "Норвежский букмол" #: minigalaxy/constants.py:37 msgid "Norwegian Nynorsk" msgstr "Норвежский нюнорск" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "Недостаточно места для извлечения игры. Требуется: {} Доступно: {}" #: data/ui/properties.ui:280 msgid "OK" msgstr "" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Открыть файлы" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Проверьте ваше подключение к Интернету" #: minigalaxy/constants.py:20 minigalaxy/constants.py:38 msgid "Polish" msgstr "Польский" #: minigalaxy/constants.py:21 minigalaxy/constants.py:39 msgid "Portuguese" msgstr "Португальский" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Настройки" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Настройки" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Предпочтительный язык игр: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "Свойства" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "Свойства {}" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Обновить список игр" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "" #: minigalaxy/constants.py:22 minigalaxy/constants.py:40 msgid "Russian" msgstr "Русский" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Сохранить" #: data/ui/properties.ui:154 msgid "Show FPS in game:" msgstr "Показывать FPS в игре:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Показывать игры для Windows: " #. Has to end with ": " #: data/ui/preferences.ui:224 msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Показывать скрытые игры: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Показывать только установленные игры" #: minigalaxy/constants.py:41 msgid "Simplified Chinese" msgstr "Китайский упрощенный" #: minigalaxy/constants.py:23 minigalaxy/constants.py:42 msgid "Spanish" msgstr "Испанский" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Не выходить из системы:" #: data/ui/properties.ui:77 msgid "Store" msgstr "Магазин" #: data/ui/properties.ui:63 msgid "Support" msgstr "Поддержка" #: minigalaxy/constants.py:24 minigalaxy/constants.py:43 msgid "Swedish" msgstr "Шведский" #: minigalaxy/constants.py:29 msgid "System default" msgstr "Системный по умолчанию" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "Не удалось установить {}. Попробуйте ещё раз." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "Язык, на котором вы хотите скачивать игры" #: data/ui/preferences.ui:65 msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "Язык, на котором вы хотите запускать Minigalaxy" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "Произошла ошибка при получении ссылки для скачивания!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "Место, куда будут установлены игры" #: minigalaxy/constants.py:44 msgid "Traditional Chinese" msgstr "Китайский традиционный" #: minigalaxy/constants.py:25 minigalaxy/constants.py:45 msgid "Turkish" msgstr "Турецкий" #: minigalaxy/constants.py:46 msgid "Ukrainian" msgstr "Украинский" #: data/ui/gametile.ui:66 msgid "Uninstall" msgstr "Удалить" #: data/ui/gametile.ui:51 msgid "Update" msgstr "Обновить" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "Использовать темную тему: " #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "Переменные-флаги:" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "Версия" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "Если эта опция отключена, вам придется всегда входить в GOG при запуске " "Minigalaxy" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "Использовать темную тему для Minigalaxy или нет" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Показывать игры для Windows в библиотеке или нет" #: data/ui/preferences.ui:221 msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Показывать скрытые игры в библиотеке или нет" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "Создавать ярлыки для недавно установленных игр или нет" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "Не удалось извлечь игру с помощью Wine." #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "Wine не найден. Отображение игр для Windows не может быть включено." #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "загрузить" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "загрузка…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "в очереди…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "установить" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "установка…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "играть" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "удаление…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "обновление…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "Не удалось распаковать {}." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "Не удалось загрузить {}." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "Невозможно использовать {} для установки" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} поврежден. Пожалуйста, загрузите заново." minigalaxy-1.1.0/data/po/sv_SE.po000066400000000000000000000316701414231301100165560ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2021-10-01 12:46+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: sv_SE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.0\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "En simpel GOG-klient för Linux" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "Om" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "Om" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "Läggs till vid slutet av kommandot som används för att starta spelet" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "Läggs till vid början av kommandot som används för att starta spelet" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "Är du säker på att du vill avbryta nedladdningen av {}?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "Är du säker på att du vill logga ut från GOG?" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "Är du säker på att du vill avinstallera %s?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Brasiliansk portugisiska" #: data/ui/properties.ui:266 msgid "Cancel" msgstr "Avbryt" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Avbryt" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Kinesiska" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "Kommandoflaggor:" #: minigalaxy/ui/properties.py:103 msgid "Couldn't open store page" msgstr "Kunde inte öppna butikssidan" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "Kunde inte öppna supportsidan" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "Skapa menygenvägar: " #: data/ui/gametile.ui:36 msgid "DLC" msgstr "Nedladdningsbart innehåll" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Danska" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "Nedladdningsfel" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "Nederländska" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "Engelska" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "Misslyckades att installera {}" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "Misslyckades att hämta bibliotek" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "Misslyckades att starta {}:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "Finska" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "Franska" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "Genre" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "Tyska" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "GitHub sida" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "Göm spel:" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Ungerska" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "Innoextract-extraheringen misslyckades." #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "Innoextract är inte installerat." #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Installationssökväg: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Installerade" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Italienska" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Japanska" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Behåll installationsprogram efter spel är nedladdade.\n" "Installationsprogram sparas i: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Behåll installationsprogram: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Koreanska" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "Språk: " #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Inloggning" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Logga ut" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "Ingen körbar fil hittades i {}" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Norska" #: minigalaxy/constants.py:35 msgid "Norwegian Bokmål" msgstr "Bokmål" #: minigalaxy/constants.py:36 msgid "Norwegian Nynorsk" msgstr "Nynorska" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "" "Det finns inte tillräckligt mycket utrymme för att packa upp spelet. Behövs: " "{} Tillgängligt: {}" #: data/ui/properties.ui:280 #, fuzzy msgid "OK" msgstr "OK" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Öppna filer" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Var god kontrollera din internetanslutning" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "Polska" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "Portugisiska" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Inställningar" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Inställningar" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Föredraget språk: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "Egenskaper" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "Egenskaper för {}" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Uppdatera spellistan" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "Regedit" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "Ryska" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Spara" #: data/ui/properties.ui:154 msgid "Show FPS in game:" msgstr "Visa bilder per sekund (FPS) i spel:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Visa Windowsspel: " #. Has to end with ": " #: data/ui/preferences.ui:224 msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Visa gömda spel: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Visa endast installerade spel" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "Förenklad kinesiska" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "Spanska" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Håll mig inloggad:" #: data/ui/properties.ui:77 msgid "Store" msgstr "Butikssida" #: data/ui/properties.ui:63 msgid "Support" msgstr "Support" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "Svenska" #: minigalaxy/constants.py:29 msgid "System default" msgstr "Standardvärde för systemet" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "Installationen av {} misslyckades. Var god försök igen." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "Det föredragna språket att ladda ner spel i" #: data/ui/preferences.ui:65 msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "Det föredragna språket vid uppstart av Minigalaxy" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "Ett fel uppstod när ledladdningslänken hämtades\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "Detta är var spel kommer installeras" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "Traditionell kinesiska" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "Turkiska" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "Ukrainska" #: data/ui/gametile.ui:66 msgid "Uninstall" msgstr "Avinstallera" #: data/ui/gametile.ui:51 msgid "Update" msgstr "Uppdatera" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "Använd mörkt tema: " #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "Variabelflaggor:" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "Version" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "När detta är avstängt kommer du bli frågad att logga in varje gång " "Minigalaxy startas" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "Om Minigalaxy ska använda mörkt tema eller inte" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Om Windowsspel ska visas i biblioteket eller inte" #: data/ui/preferences.ui:221 msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Om gömda spel ska visas i biblioteket eller inte" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "Om genvägar ska skapas för nyinstallerade spel eller inte" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "Extrahering av Wine misslyckades." #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "Wine kunde inte hittas. Visning av Windowsspel kan inte slås på." #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "Winecfg" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "ladda ner" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "laddar ner…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "i kö…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "installera" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "installerar…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "spela" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "avinstallerar…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "uppdaterar…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} kunde inte packas upp." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "{} kunde inte laddas ner." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} är inte en korrekt filsökväg" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} var korrupt. Försök ladda ner det igen." #~ msgid "Couldn't connect to GOG servers" #~ msgstr "Kunde inte ansluta till GOG-serverarn" #~ msgid "Install Wine to enable this feature" #~ msgstr "Installera Wine för att möjliggöra denna funktion" #~ msgctxt "Wine Settings" #~ msgid "Settings" #~ msgstr "Inställningar" #~ msgctxt "show_fps_tooltip" #~ msgid "" #~ "Show the framerate while playing games. Only works with AMD and Nvidia " #~ "graphics cards." #~ msgstr "" #~ "Visa bildhastighet (FPS) i spel. Fungerar endast med AMD och NVIDIA " #~ "grafikkort." minigalaxy-1.1.0/data/po/tr.po000066400000000000000000000347341414231301100161700ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2021-09-30 11:22+0300\n" "Last-Translator: Hüseyin Fahri Uzun \n" "Language-Team: \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.3\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Linux için basit bir GOG uygulaması" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "Hakkında" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "Hakkında" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "Oyun çalıştırılırken kullanılacak olan komutun sonuna eklendi" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "Oyun çalıştırılırken kullanılacak olan komutun başına eklendi" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "{} indirmesini iptal etmek istediğine emin misin?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "GOG üzerinden çıkış yapmak istediğinize emin misiniz?" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "%s silmek istediğine emin misin?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Brezilya Portekizçesi" #: data/ui/properties.ui:266 msgid "Cancel" msgstr "İptal" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "İptal" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Çince" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "Komut bayrakları:" #: minigalaxy/ui/properties.py:103 msgid "Couldn't open store page" msgstr "Mağaza sayfası açılamadı" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "Destek sayfası açılamadı" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "Menü kısayolları oluştur: " #: data/ui/gametile.ui:36 msgid "DLC" msgstr "DLC" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Danimarka Dili" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "İndirme hatası" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "Flemenkçe" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "İngilzce" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "{} yüklenemedi:" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "Kütüphane alınamadı" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "{} başlatılamadı:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "Fince" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "Fransızca" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "Genre" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "Almanca" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Github sayfası" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "Oyunu gizle:" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Macarca" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "Innoextract dışa aktarım başarısız." #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "Innoextract yüklü değil." #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Yükleme klasör yolu: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Yüklendi" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "İtalyanca" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Japonca" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Oyun indirmesi sonrasında yükleyiciyi saklı tut.\n" "Yükleyiciler şurada tutuluyor: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Yükleyicileri saklı tut: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Korece" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "Dil: " #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Giriş Yap" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Çıkış Yap" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "{} burada başlatma dosyası bulunamadı" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Norveçce" #: minigalaxy/constants.py:35 msgid "Norwegian Bokmål" msgstr "Norveçce" #: minigalaxy/constants.py:36 msgid "Norwegian Nynorsk" msgstr "Norveçce" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "Oyunu dışarı çıkartmak için yeterli alan yok. Gerekli: {} Mevcut {}" #: data/ui/properties.ui:280 msgid "OK" msgstr "Tamam" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Dosyaları Aç" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Lütfen internet bağlantınızı kontrol ediniz" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "Lehçe" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "Portekizce" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Ayarlar" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Ayarlar" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Tercih edilen dil: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "Seçenekler" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "{} Seçenekleri" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Oyun listesini güncelle" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "Regedit" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "Rusça" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Kaydet" #: data/ui/properties.ui:154 msgid "Show FPS in game:" msgstr "Oyunlarda FPS göster:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Windows oyunlarını göster: " #. Has to end with ": " #: data/ui/preferences.ui:224 msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Gizli oyunları göster: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Sadece yüklü oyunları göster" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "Basitleştirilmiş Çince" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "İspanyolca" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Çevrimci tut:" #: data/ui/properties.ui:77 msgid "Store" msgstr "Market Sayfası" #: data/ui/properties.ui:63 msgid "Support" msgstr "Destek" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "İsveçce" #: minigalaxy/constants.py:29 msgid "System default" msgstr "Sistem varsayılanları" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "{} yüklemesi başarısız oldu. Lütfen bir daha deneyiniz." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "İndirilen oyunlar için tercih edilen dil" #: data/ui/preferences.ui:65 msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "Minigalaxy çalıştırıldığında tercih edilecek dil" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "İndirme linki alınırken bir hata oluştu! {}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "Burası oyunların indireleceği yerdir" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "Geleneksel Çince" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "Türkçe" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "" #: data/ui/gametile.ui:66 msgid "Uninstall" msgstr "Kaldır" #: data/ui/gametile.ui:51 msgid "Update" msgstr "Güncelle" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "Koyu tema kullan: " #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "Değişken bayrakları:" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "Versiyon" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "Etkin değilken her Minigalaxy açıldığında giriş yapılması istenir" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "Minigalaxy'nin koyu tema kullanıp kullanmayacağı" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Windows oyunları kütüphanede gözükmeli mi" #: data/ui/preferences.ui:221 msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Gizlenmiş oyunların kütüphanede gözükmeli mi" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "Yeni yüklenen oyunların kısa yol oluşturup oluşturmayacağı" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "Wine dışarı aktarım başarısız." #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "Wine bulunamadı. Windows oyunlarının gösterimi etkinleştirilemez." #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "Winecfg" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "indir" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "indirliyor…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "sırada…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "yükle" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "yükleniyor…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "oyna" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "siliniyor…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "güncelleniyor…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} arşivden çıkartılamadı." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "{} indirirken hata." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} kullanılabilinir bir yol değil" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} bozuk. Lütfen yeniden indirin." #~ msgid "Couldn't connect to GOG servers" #~ msgstr "GOG sunucularına bağlanılanamıyor" #~ msgid "Install Wine to enable this feature" #~ msgstr "Bu özelliği etkinleştirmek için Wine yükleyin" #~ msgctxt "Wine Settings" #~ msgid "Settings" #~ msgstr "Ayarlar" #~ msgctxt "show_fps_tooltip" #~ msgid "" #~ "Show the framerate while playing games. Only works with AMD and Nvidia " #~ "graphics cards." #~ msgstr "" #~ "Oyun oynarken kare hızını göster. Sadece AMD ve Nvidia ekran kartlarında " #~ "çalışır." #~ msgid "" #~ "Artur Wróblewski\n" #~ "BlindJerobine\n" #~ "Esdras Tarsis\n" #~ "Hüseyin Fahri Uzun\n" #~ "Jan Kjetil Myklebust\n" #~ "Jeff Huang\n" #~ "kimmalmo\n" #~ "ProTheory8\n" #~ "thomasb22" #~ msgstr "" #~ "Artur Wróblewski\n" #~ "BlindJerobine\n" #~ "Esdras Tarsis\n" #~ "Hüseyin Fahri Uzun\n" #~ "Jan Kjetil Myklebust\n" #~ "Jeff Huang\n" #~ "kimmalmo\n" #~ "ProTheory8\n" #~ "thomasb22" #~ msgid "Couldn't start subprocess" #~ msgstr "Alt işlem başlatılamadı" #~ msgid "No error message was returned" #~ msgstr "Hata mesajı alınmadı" #~ msgid "Minigalaxy is now running in offline mode" #~ msgstr "Minigalaxy şuan çevrimdışı modunda çalışıyor" #~ msgid "Try again with an active internet connection" #~ msgstr "Aktif bir internet bağlantısı ile yeniden deneyiniz" minigalaxy-1.1.0/data/po/uk.po000066400000000000000000000341611414231301100161540ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2021-09-29 19:02+0300\n" "Last-Translator: \n" "Language-Team: \n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.0\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Простий клієнт GOG для Linux" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "Інформація" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "Інформація" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "Додано в кінці команди, яка використовується для запуску гри" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "Додано перед командою, яка використовується для запуску гри" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "Ви впевнені, що хочете скасувати завантаження {}?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "Ви дійсно хочете вийти з GOG?" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "Ви впевнені, що хочете видалити %s?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "Бразильський Португальська" #: data/ui/properties.ui:266 msgid "Cancel" msgstr "Скасувати" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "Скасувати" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "Китайська" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "Флажки для команди:" #: minigalaxy/ui/properties.py:103 msgid "Couldn't open store page" msgstr "Не вдалося відкрити сторінку магазину" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "Не вдалося відкрити сторінку підтримки" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "Створити ярлики меню: " #: data/ui/gametile.ui:36 msgid "DLC" msgstr "DLC" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "Датська" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "Помилка при завантаженні" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "Голландська" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "Англійська" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "Не вдалося встановити {}" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "Не вдалося отримати бібліотеку" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "Не вдалося запустити {}:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "Фінська" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "Французька" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "Жанр" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "Німецька" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Сторінка Github" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "Сховати гру:" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "Угорська" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "Помилка вилучення Innoextract." #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "Innoextract не встановлено." #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "Шлях установки: " #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "Встановлено" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "Італійська" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "Японська" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "Зберегти інсталятори після завантаження гри.\n" "Інсталятори зберігаються в: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "Зберігати інсталятори: " #: minigalaxy/constants.py:18 msgid "Korean" msgstr "Корейська" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "Мова: " #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "Увійти" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "Вийти" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "У {} не знайдено жодного виконуваного файлу" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "Норвезька" #: minigalaxy/constants.py:35 msgid "Norwegian Bokmål" msgstr "Норвезька Букмол" #: minigalaxy/constants.py:36 msgid "Norwegian Nynorsk" msgstr "Норвезька Ньорск" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "Не вистачає місця для розпакування гри. Потрібно: {} Доступно: {}" #: data/ui/properties.ui:280 msgid "OK" msgstr "ОК" #: data/ui/properties.ui:216 msgid "Open files" msgstr "Відкрийте файли" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "Перевірте підключення до Інтернету" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "Польська" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "Португальська" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "Налаштування" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "Налаштування" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "Бажана мова: " #: data/ui/gametile.ui:81 msgid "Properties" msgstr "Властивості" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "Властивості {}" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "Оновити список ігор" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "Regedit (регіт)" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "Російська" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "Зберегти" #: data/ui/properties.ui:154 msgid "Show FPS in game:" msgstr "Показати FPS у грі:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "Показати ігри для Windows: " #. Has to end with ": " #: data/ui/preferences.ui:224 msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "Показати приховані ігри: " #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "Показати лише встановлені ігри" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "Спрощена Китайська" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "Іспанська" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "Залишатися в системі:" #: data/ui/properties.ui:77 msgid "Store" msgstr "Магазин" #: data/ui/properties.ui:63 msgid "Support" msgstr "Підтримка" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "Шведська" #: minigalaxy/constants.py:29 msgid "System default" msgstr "За замовчуванням" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "Не вдалося встановити {}. Спробуйте ще раз." #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "Бажана мова для завантаження ігор в" #: data/ui/preferences.ui:65 msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "Бажана мова для запуску Minigalaxy" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "Під час спроби отримати посилання для завантаження сталася помилка!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "Тут будуть встановлені ігри" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "Традиційна Китайська" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "Турецька" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "" #: data/ui/gametile.ui:66 msgid "Uninstall" msgstr "Видалити" #: data/ui/gametile.ui:51 msgid "Update" msgstr "Оновити" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "Використовувати темну тему: " #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "Флажки для змінної:" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "Версія" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "" "Коли вимкнено, вам буде запропоновано входити в систему кожного разу при " "запуску Minigalaxy" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "Використовувати темну тему для Minigalaxy чи ні" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Відображати ігри Windows у бібліотеці чи ні" #: data/ui/preferences.ui:221 msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Показувати приховані ігри в бібліотеці чи ні" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "" "Незалежно від того, створені ярлики для нещодавно встановлених ігор чи ні" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "Помилка вилучення Wine." #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "Wine не знайдено. Показ ігор Windows не може бути ввімкнено." #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "Winecfg" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "завантажити" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "завантаження…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "в черзі…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "встановити" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "встановлення…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "грати" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "видалення…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "оновлення…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} не вдалося розпакувати." #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "Не вдалося завантажити {}." #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} некоректний шлях" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} пошкоджено. Завантажте ще раз." minigalaxy-1.1.0/data/po/zh_CN.po000066400000000000000000000311361414231301100165350ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-11-06 23:23+0900\n" "PO-Revision-Date: 2021-11-06 23:37+0900\n" "Last-Translator: \n" "Language-Team: \n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.0\n" "Plural-Forms: nplurals=1; plural=0;\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "用于 Linux 的简易 GOG 客户端" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "关于" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "关于" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "已添加至游戏启动命令末尾处" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "已添加至游戏启动命令开头处" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "确定要取消下载 {} 吗?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "确定要登出GOG吗?" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "确定要卸载 %s 吗?" #: minigalaxy/constants.py:7 minigalaxy/constants.py:30 msgid "Brazilian Portuguese" msgstr "巴西葡萄牙语" #: data/ui/properties.ui:266 msgid "Cancel" msgstr "取消" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "取消" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "汉语" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "命令标记:" #: minigalaxy/ui/properties.py:103 msgid "Couldn't open store page" msgstr "无法打开商店页面" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "无法打开支持页面" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "创建菜单快捷方式" #: minigalaxy/constants.py:31 msgid "Czech" msgstr "捷克语" #: data/ui/gametile.ui:36 msgid "DLC" msgstr "DLC" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "丹麦语" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "下载错误" #: minigalaxy/constants.py:10 minigalaxy/constants.py:32 msgid "Dutch" msgstr "荷兰语" #: minigalaxy/constants.py:11 minigalaxy/constants.py:33 msgid "English" msgstr "英语" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "更改软件语言失败。请确保已生成locale。" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "安装 {} 失败" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "获取游戏库失败" #: minigalaxy/launcher.py:34 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "启动 {} 失败:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:34 msgid "Finnish" msgstr "芬兰语" #: minigalaxy/constants.py:13 minigalaxy/constants.py:35 msgid "French" msgstr "法语" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "类型" #: minigalaxy/constants.py:14 minigalaxy/constants.py:36 msgid "German" msgstr "德语" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "Github 页面" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "隐藏游戏:" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "匈牙利语" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "使用Innoextract提取失败。" #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "未安装Innoextract" #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "安装路径:" #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "仅显示已安装的游戏" #: minigalaxy/constants.py:16 minigalaxy/constants.py:37 msgid "Italian" msgstr "意大利语" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "日语" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "下载后保留安装包。安装包会保存在: {}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "保留安装包:" #: minigalaxy/constants.py:18 msgid "Korean" msgstr "韩语" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "语言" #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "登录" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "退出登录" #: minigalaxy/launcher.py:179 msgid "No executable was found in {}" msgstr "在 {} 内未找到可执行文件" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "挪威语" #: minigalaxy/constants.py:38 msgid "Norwegian Bokmål" msgstr "书面挪威语" #: minigalaxy/constants.py:39 msgid "Norwegian Nynorsk" msgstr "新挪威语" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "可用空间不足,无法解压游戏。需要:{},可用:{}" #: data/ui/properties.ui:280 msgid "OK" msgstr "好" #: data/ui/properties.ui:216 msgid "Open files" msgstr "打开文件" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "请检查网络连接" #: minigalaxy/constants.py:20 minigalaxy/constants.py:40 msgid "Polish" msgstr "波兰语" #: minigalaxy/constants.py:21 msgid "Portuguese" msgstr "葡萄牙语" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "偏好设置" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "偏好设置" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "首选语言:" #: data/ui/gametile.ui:81 msgid "Properties" msgstr "属性" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "{} 的属性" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "刷新游戏列表" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "注册表" #: minigalaxy/constants.py:22 minigalaxy/constants.py:41 msgid "Russian" msgstr "俄语" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "保存" #: data/ui/properties.ui:154 msgid "Show FPS in game:" msgstr "在游戏内显示 FPS:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "显示 Windows 游戏:" #. Has to end with ": " #: data/ui/preferences.ui:224 msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "显示隐藏的游戏:" #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "只显示已安装的游戏" #: minigalaxy/constants.py:42 msgid "Simplified Chinese" msgstr "简体中文" #: minigalaxy/constants.py:23 minigalaxy/constants.py:43 msgid "Spanish" msgstr "西班牙语" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "保持登录:" #: data/ui/properties.ui:77 msgid "Store" msgstr "商店" #: data/ui/properties.ui:63 msgid "Support" msgstr "支持" #: minigalaxy/constants.py:24 minigalaxy/constants.py:44 msgid "Swedish" msgstr "瑞典语" #: minigalaxy/constants.py:29 msgid "System default" msgstr "系统默认" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "{} 安装错误,请重试。" #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "下载游戏时优先选择的语言" #: data/ui/preferences.ui:65 msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "启动 Minigalaxy 时有限选择的语言" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "尝试获取下载链接时发生错误!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "游戏会被安装到这里" #: minigalaxy/constants.py:45 msgid "Traditional Chinese" msgstr "繁体中文" #: minigalaxy/constants.py:25 minigalaxy/constants.py:46 msgid "Turkish" msgstr "土耳其语" #: minigalaxy/constants.py:47 msgid "Ukrainian" msgstr "乌克兰语" #: data/ui/gametile.ui:66 msgid "Uninstall" msgstr "卸载" #: data/ui/gametile.ui:51 msgid "Update" msgstr "更新" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "使用暗色主题:" #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "变量标记:" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "版本" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "如果禁用,Minigalaxy 每次启动时将会请求您登录" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "是否让 Minigalaxy 使用暗色主题" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "是否在游戏库内显示 Windows 游戏" #: data/ui/preferences.ui:221 msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "是否在游戏库内显示隐藏的游戏" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "游戏安装完成后是否创建快捷方式" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "Wine 提取失败" #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "未找到 Wine。无法启用显示 Windows 游戏" #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "Winecfg" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "下载" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "正在下载…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "队列中…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "安装" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "正在安装…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "开始游戏" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "正在卸载…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "正在更新…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "{} 无法解压。" #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "{} 下载失败。" #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} 路径不可用" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} 已损坏,请重新下载。" #~ msgid "Couldn't connect to GOG servers" #~ msgstr "无法连接至 GOG 服务器" #~ msgid "Install Wine to enable this feature" #~ msgstr "安装 Wine 以启用这项功能" #~ msgctxt "Wine Settings" #~ msgid "Settings" #~ msgstr "设置" #~ msgctxt "show_fps_tooltip" #~ msgid "" #~ "Show the framerate while playing games. Only works with AMD and Nvidia " #~ "graphics cards." #~ msgstr "在游戏内显示帧率。仅支持 AMD 和英伟达显卡。" #~ msgid "Couldn't start subprocess" #~ msgstr "无法启动子进程" #~ msgid "No error message was returned" #~ msgstr "未返回错误信息" minigalaxy-1.1.0/data/po/zh_TW.po000066400000000000000000000330241414231301100165650ustar00rootroot00000000000000# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Jeff Huang , 2019, 2020. msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-27 22:44-0400\n" "PO-Revision-Date: 2020-11-15 07:53+0800\n" "Last-Translator: Jeff Huang \n" "Language-Team: Chinese \n" "Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Lokalize 19.08.3\n" #. A short description of what Minigalaxy is #: data/ui/about.ui:10 msgctxt "short_description" msgid "A simple GOG client for Linux" msgstr "Linux 上簡單的 GOG 客戶端" #: minigalaxy/ui/about.py:13 msgid "About" msgstr "關於" #. Opens about dialog #: data/ui/application.ui:58 msgctxt "about" msgid "About" msgstr "關於" #: data/ui/properties.ui:129 msgid "Added at the end of the command used to launch the game" msgstr "" #: data/ui/properties.ui:141 msgid "Added in front of the command used to launch the game" msgstr "" #: minigalaxy/ui/gametile.py:132 msgid "Are you sure you want to cancel downloading {}?" msgstr "您確定您想要取消下載 {} 嗎?" #: minigalaxy/ui/window.py:100 msgid "Are you sure you want to log out of GOG?" msgstr "" #: minigalaxy/ui/gametile.py:145 #, python-format msgid "Are you sure you want to uninstall %s?" msgstr "您確定要解除安裝 %s 嗎?" #: minigalaxy/constants.py:7 msgid "Brazilian Portuguese" msgstr "葡萄牙文(巴西)" #: data/ui/properties.ui:266 #, fuzzy msgid "Cancel" msgstr "取消" #: data/ui/preferences.ui:20 msgctxt "cancel" msgid "Cancel" msgstr "取消" #: minigalaxy/constants.py:8 msgid "Chinese" msgstr "中文" #: data/ui/properties.ui:180 msgid "Command flags:" msgstr "" #: minigalaxy/ui/properties.py:103 #, fuzzy msgid "Couldn't open store page" msgstr "無法開啟支援頁面" #: minigalaxy/ui/properties.py:93 msgid "Couldn't open support page" msgstr "無法開啟支援頁面" #. Has to end with ": " #: data/ui/preferences.ui:288 msgctxt "create_menu_shortcuts" msgid "Create menu shortcuts: " msgstr "" #: data/ui/gametile.ui:36 msgid "DLC" msgstr "DLC" #: minigalaxy/constants.py:9 msgid "Danish" msgstr "丹麥文" #: minigalaxy/ui/gametile.py:207 minigalaxy/ui/gametile.py:236 msgid "Download error" msgstr "下載錯誤" #: minigalaxy/constants.py:10 minigalaxy/constants.py:30 msgid "Dutch" msgstr "荷蘭文" #: minigalaxy/constants.py:11 minigalaxy/constants.py:31 msgid "English" msgstr "英文" #: minigalaxy/ui/preferences.py:102 msgid "" "Failed to change program language. Make sure locale is generated on your " "system." msgstr "" #: minigalaxy/ui/gametile.py:298 msgid "Failed to install {}" msgstr "安裝 {} 失敗" #: minigalaxy/ui/library.py:152 msgid "Failed to retrieve library" msgstr "擷取收藏庫失敗" #: minigalaxy/launcher.py:36 minigalaxy/ui/gametile.py:122 msgid "Failed to start {}:" msgstr "啟動 {} 失敗:" #: minigalaxy/constants.py:12 minigalaxy/constants.py:32 msgid "Finnish" msgstr "芬蘭文" #: minigalaxy/constants.py:13 minigalaxy/constants.py:33 msgid "French" msgstr "法文" #: minigalaxy/ui/properties.py:137 msgid "Genre" msgstr "" #: minigalaxy/constants.py:14 minigalaxy/constants.py:34 msgid "German" msgstr "德文" #. A link to the Github page #: data/ui/about.ui:12 msgctxt "github_page_link" msgid "Github page" msgstr "GitHub 頁面" #: data/ui/properties.ui:105 msgid "Hide game:" msgstr "" #: minigalaxy/constants.py:15 msgid "Hungarian" msgstr "匈牙利文" #: minigalaxy/installer.py:147 msgid "Innoextract extraction failed." msgstr "" #: minigalaxy/installer.py:158 msgid "Innoextract not installed." msgstr "" #. The place directory in which games are installed. Ends with ": ". #: data/ui/preferences.ui:118 msgctxt "install_path" msgid "Installation path: " msgstr "安裝路徑:" #. Used next to a checkbox which switches between showing all games and only installed ones #: data/ui/application.ui:116 msgctxt "installed" msgid "Installed" msgstr "已安裝" #: minigalaxy/constants.py:16 msgid "Italian" msgstr "義大利文" #: minigalaxy/constants.py:17 msgid "Japanese" msgstr "日文" #: minigalaxy/ui/preferences.py:46 msgid "" "Keep installers after downloading a game.\n" "Installers are stored in: {}" msgstr "" "在下載遊戲後保留安裝程式。\n" "安裝程式儲存於:{}" #. Whether installer files are kept after download. Ends with ": ". #: data/ui/preferences.ui:145 msgctxt "keep_installer" msgid "Keep installers: " msgstr "保留安裝程式:" #: minigalaxy/constants.py:18 msgid "Korean" msgstr "韓文" #. The preferred language on Minigalaxy start. Ends with ": ". #: data/ui/preferences.ui:68 msgctxt "language" msgid "Language: " msgstr "" #: minigalaxy/ui/login.py:20 msgid "Login" msgstr "登入" #. Logs the users gog account out and returns to login page #: data/ui/application.ui:17 msgctxt "logout" msgid "Logout" msgstr "登出" #: minigalaxy/launcher.py:184 msgid "No executable was found in {}" msgstr "在 {} 找不到可執行檔" #: minigalaxy/constants.py:19 msgid "Norwegian" msgstr "挪威文" #: minigalaxy/constants.py:35 #, fuzzy msgid "Norwegian Bokmål" msgstr "挪威文" #: minigalaxy/constants.py:36 #, fuzzy msgid "Norwegian Nynorsk" msgstr "挪威文" #: minigalaxy/installer.py:97 msgid "Not enough space to extract game. Required: {} Available: {}" msgstr "" #: data/ui/properties.ui:280 msgid "OK" msgstr "" #: data/ui/properties.ui:216 msgid "Open files" msgstr "開啟檔案" #: minigalaxy/ui/properties.py:94 minigalaxy/ui/properties.py:104 msgid "Please check your internet connection" msgstr "請檢查您的網際網路連線" #: minigalaxy/constants.py:20 minigalaxy/constants.py:37 msgid "Polish" msgstr "波蘭文" #: minigalaxy/constants.py:21 minigalaxy/constants.py:38 msgid "Portuguese" msgstr "葡萄牙文" #: minigalaxy/ui/preferences.py:30 msgid "Preferences" msgstr "偏好設定" #. Opens preferences dialog #: data/ui/application.ui:32 msgctxt "preferences" msgid "Preferences" msgstr "偏好設定" #. Prefered language for downloading games in. Ends with ": ". #: data/ui/preferences.ui:93 msgctxt "preferred_game_language" msgid "Preferred game language: " msgstr "偏好的語言:" #: data/ui/gametile.ui:81 msgid "Properties" msgstr "" #: minigalaxy/ui/properties.py:33 msgid "Properties of {}" msgstr "" #. Tooltip for refresh button #: data/ui/application.ui:89 msgctxt "refresh" msgid "Refresh game list" msgstr "重新整理遊戲清單" #: data/ui/properties.ui:203 msgid "Regedit" msgstr "" #: minigalaxy/constants.py:22 minigalaxy/constants.py:39 msgid "Russian" msgstr "俄文" #. Saves the preferences #: data/ui/preferences.ui:34 msgctxt "save" msgid "Save" msgstr "儲存" #: data/ui/properties.ui:154 #, fuzzy msgid "Show FPS in game:" msgstr "在遊戲中顯示 FPS:" #. Has to end with ": " #: data/ui/preferences.ui:250 msgctxt "show_windows_games" msgid "Show Windows games: " msgstr "顯示 Windows 遊戲:" #. Has to end with ": " #: data/ui/preferences.ui:224 #, fuzzy msgctxt "show_hidden_games" msgid "Show hidden games: " msgstr "顯示 Windows 遊戲:" #. Tooltip for the switch which allows only showing installed games or all games #: data/ui/application.ui:105 msgctxt "tooltip_installed" msgid "Show only installed games" msgstr "僅顯示已安裝的遊戲" #: minigalaxy/constants.py:40 msgid "Simplified Chinese" msgstr "" #: minigalaxy/constants.py:23 minigalaxy/constants.py:41 msgid "Spanish" msgstr "西班牙文" #. Whether the user will stay logged in after closing Minigalaxy. Ends with ": ". #: data/ui/preferences.ui:171 msgctxt "stay_logged_in" msgid "Stay logged in:" msgstr "保持登入:" #: data/ui/properties.ui:77 #, fuzzy msgid "Store" msgstr "商店頁面" #: data/ui/properties.ui:63 #, fuzzy msgid "Support" msgstr "支援" #: minigalaxy/constants.py:24 minigalaxy/constants.py:42 msgid "Swedish" msgstr "瑞典文" #: minigalaxy/constants.py:29 msgid "System default" msgstr "" #: minigalaxy/installer.py:128 msgid "The installation of {} failed. Please try again." msgstr "{} 安裝失敗。請再試一次。" #: data/ui/preferences.ui:90 msgctxt "preferred_game_language_tooltip" msgid "The preferred language for downloading games in" msgstr "下載遊戲的偏好語言" #: data/ui/preferences.ui:65 #, fuzzy msgctxt "language_tooltip" msgid "The preferred language on Minigalaxy start" msgstr "下載遊戲的偏好語言" #: minigalaxy/ui/gametile.py:208 msgid "" "There was an error when trying to fetch the download link!\n" "{}" msgstr "" "嘗試擷取下載連結時發生錯誤!\n" "{}" #: data/ui/preferences.ui:115 msgctxt "install_path_tooltip" msgid "This is where games will be installed" msgstr "遊戲會安裝在" #: minigalaxy/constants.py:43 msgid "Traditional Chinese" msgstr "" #: minigalaxy/constants.py:25 minigalaxy/constants.py:44 msgid "Turkish" msgstr "土耳其文" #: minigalaxy/constants.py:45 msgid "Ukrainian" msgstr "" #: data/ui/gametile.ui:66 #, fuzzy msgid "Uninstall" msgstr "解除安裝" #: data/ui/gametile.ui:51 #, fuzzy msgid "Update" msgstr "更新" #. Has to end with ": " #: data/ui/preferences.ui:198 msgctxt "use_dark_theme" msgid "Use dark theme: " msgstr "" #: data/ui/properties.ui:167 msgid "Variable flags:" msgstr "" #: minigalaxy/ui/properties.py:139 msgid "Version" msgstr "" #: data/ui/preferences.ui:168 msgctxt "stay_logged_in_tooltip" msgid "When disabled you'll be asked to log in each time Minigalaxy is started" msgstr "若停用,您每次打開 Minigalaxy 時都會被要求登入" #: data/ui/preferences.ui:195 msgctxt "use_dark_theme_tooltip" msgid "Whether Minigalaxy should use dark theme or not" msgstr "" #: data/ui/preferences.ui:247 msgctxt "show_windows_games_tooltip" msgid "Whether Windows games are shown in the library or not" msgstr "Windows 遊戲是否要顯示在收藏庫中" #: data/ui/preferences.ui:221 #, fuzzy msgctxt "show_hidden_games_tooltip" msgid "Whether hidden games are shown in the library or not" msgstr "Windows 遊戲是否要顯示在收藏庫中" #: data/ui/preferences.ui:285 msgctxt "create_menu_shortcuts_tooltip" msgid "Whether shortcuts are created for newly installed games or not" msgstr "" #: minigalaxy/installer.py:172 msgid "Wine extraction failed." msgstr "" #: minigalaxy/ui/preferences.py:162 msgid "Wine wasn't found. Showing Windows games cannot be enabled." msgstr "" #: data/ui/properties.ui:190 msgid "Winecfg" msgstr "" #: minigalaxy/ui/gametile.py:450 msgid "download" msgstr "下載" #: minigalaxy/ui/gametile.py:489 msgid "downloading…" msgstr "正在下載…" #: minigalaxy/ui/gametile.py:481 msgid "in queue…" msgstr "在佇列中…" #: minigalaxy/ui/gametile.py:469 msgid "install" msgstr "安裝" #: minigalaxy/ui/gametile.py:499 msgid "installing…" msgstr "正在安裝…" #: minigalaxy/ui/gametile.py:513 minigalaxy/ui/gametile.py:543 msgid "play" msgstr "遊玩" #: minigalaxy/ui/gametile.py:529 msgid "uninstalling…" msgstr "正在解除安裝…" #: minigalaxy/ui/gametile.py:552 msgid "updating…" msgstr "正在更新…" #: minigalaxy/installer.py:130 msgid "{} could not be unzipped." msgstr "無法解壓縮 {}。" #: minigalaxy/installer.py:73 msgid "{} failed to download." msgstr "{} 下載失敗。" #: minigalaxy/ui/preferences.py:174 msgid "{} isn't a usable path" msgstr "{} 不是可用的路徑" #: minigalaxy/installer.py:85 msgid "{} was corrupted. Please download it again." msgstr "{} 已損毀。請再下載一次。" #~ msgid "Couldn't connect to GOG servers" #~ msgstr "無法連線至 GOG 伺服器" #~ msgid "Install Wine to enable this feature" #~ msgstr "安裝 Wine 以啟用此功能" #~ msgctxt "Wine Settings" #~ msgid "Settings" #~ msgstr "設定" #~ msgctxt "show_fps_tooltip" #~ msgid "" #~ "Show the framerate while playing games. Only works with AMD and Nvidia " #~ "graphics cards." #~ msgstr "在遊玩遊戲時顯示畫面率。僅可與 AMD 及 Nvidia 的顯示卡一同運作。" #~ msgid "" #~ "Artur Wróblewski\n" #~ "BlindJerobine\n" #~ "Esdras Tarsis\n" #~ "Hüseyin Fahri Uzun\n" #~ "Jan Kjetil Myklebust\n" #~ "Jeff Huang\n" #~ "kimmalmo\n" #~ "ProTheory8\n" #~ "thomasb22" #~ msgstr "" #~ "Artur Wróblewski\n" #~ "BlindJerobine\n" #~ "Esdras Tarsis\n" #~ "Hüseyin Fahri Uzun\n" #~ "Jan Kjetil Myklebust\n" #~ "Jeff Huang\n" #~ "kimmalmo\n" #~ "ProTheory8\n" #~ "thomasb22" #~ msgid "Couldn't start subprocess" #~ msgstr "無法啟動子行程" #~ msgid "No error message was returned" #~ msgstr "未傳回錯誤訊息" #~ msgid "Minigalaxy is now running in offline mode" #~ msgstr "Minigalaxy 目前以離線模式執行" #~ msgid "Try again with an active internet connection" #~ msgstr "使用有效的網際網路連線重試" minigalaxy-1.1.0/data/ui/000077500000000000000000000000001414231301100151675ustar00rootroot00000000000000minigalaxy-1.1.0/data/ui/about.ui000066400000000000000000000104561414231301100166460ustar00rootroot00000000000000 minigalaxy-1.1.0/data/ui/application.ui000066400000000000000000000170501414231301100200340ustar00rootroot00000000000000 False True False vertical True True True Logout True False True 0 True True True Preferences True False True 1 True False False True 2 True True True About True False True 3 minigalaxy-1.1.0/data/ui/gametile.ui000066400000000000000000000222651414231301100173240ustar00rootroot00000000000000 False True False vertical False True False vertical True True none left dlc_popover True False DLC False True 0 True True True Update True False True 1 True True True Uninstall True False True 2 True True True Properties True False True 3 minigalaxy-1.1.0/data/ui/library.ui000066400000000000000000000016431414231301100171760ustar00rootroot00000000000000 minigalaxy-1.1.0/data/ui/login.ui000066400000000000000000000025561414231301100166460ustar00rootroot00000000000000 minigalaxy-1.1.0/data/ui/preferences.ui000066400000000000000000000371651414231301100200430ustar00rootroot00000000000000 minigalaxy-1.1.0/data/ui/properties.ui000066400000000000000000000362671414231301100177400ustar00rootroot00000000000000 minigalaxy-1.1.0/debian/000077500000000000000000000000001414231301100150635ustar00rootroot00000000000000minigalaxy-1.1.0/debian/changelog000066400000000000000000000221041414231301100167340ustar00rootroot00000000000000minigalaxy (1.1.0) focal; urgency=medium * Improve integrity check after downloading (thanks to makson96) * Show an error showing Windows games cannot be enabled * Add properties menu for games where game specific actions can be made like setting launch options and opening the store page (thanks to Odelpasso and makson96) * Add a disk space check before downloading (thanks to SvdB-nonp and makson96) * Use a different color for the play button for installed games * Put installed games at the top of the list * Store saved installers in ``~/GOG Games/installer`` by default again (thanks to makson96) * Remember if the user had the installed filter enabled (thanks to makson96) * Extract Windows games in the background if Innoextract is available (thanks to makson96) * Extract Windows games in the background (thanks to Odelpasso) * Fix installing DLC for Windows games (thanks to makson96) * Fix an error showing if the user has no games (thanks to makson96) * Add option to hide games (thanks to TotalCaesar659) * Ask user if they are sure when logging out (thanks to TotalCaesar659) * Add a dark theme (thanks to TotalCaesar659) * Run post install script after installation. This fixes Full Throttle Remastered (thanks to makson96) * Fix games being shown twice * Fix crash when GOG is down (thanks to lmeunier) * Make the language configurable (thanks to TotalCaesar659 and zweif) * Add the following translations: * Czech (thanks to jakbuz23) * Finnish (thanks to heidiwenger and jonnelafin) * Italian (thanks to koraynilay) * Swedish (thanks to Newbytee) * Ukrainian (thanks to karaushu) * Update the following translations: * Dutch * German (thanks to zweif) * Norwegian Nynorsk (thanks to LordPilum) * Polish (thanks to ArturWroblewski) * Russian (thanks to TotalCaesar659) * Simplified Chinese (thanks to dummyx) * Spanish (thanks to LocalPinkRobin and advy99) * Turkish (thanks to fuzunspm) -- Wouter Wijsman Mon, 08 Nov 2021 10:40:34 +0100 minigalaxy (1.0.2) buster; urgency=medium * Fix updates sometimes not working * Fix some games always showing an update is available * Fix DLC not downloading (thanks to stephanlachnit) * Fix DLC update option not showing up (thanks to makson96) * Fix show store page button not showing anymore (thanks to makson96) * Fix missing thumbnails not being downloaded for already installed games (thanks to makson96) * Fix the login screen crashing in some cases (thanks to makson96) * Use the system's icon theme for icons used (thanks to stephanlachnit and makson96) -- Wouter Wijsman Thu, 14 Jan 2021 09:20:17 +0100 minigalaxy (1.0.1) buster; urgency=medium * Open maximized if the window was maximized when last closed (thanks to TotalCaesar659) * Kept installers are now stored in ~/.cache/minigalaxy/download * Fix about window displaying wrong version number * Fix show store page button not showing anymore (thanks to makson96) * Fix the download manager crashing when an installer has been damaged during downloading (thanks to makson96) * Fix games showing an update is available while the latest version is installed (thanks to makson96) * Fix loading the library taking a long time when many games are installed (thanks to makson96) * Fix Gex not launching * Add the following translations: * Swedish (thanks to Newbytee) * Update the following translations: * Polish (thanks to ArturWroblewski) * Russian (thanks to TotalCaesar659) -- Wouter Wijsman Thu, 07 Jan 2021 12:51:33 +0100 minigalaxy (1.0.0) buster; urgency=medium * Games can now be updated (thanks to mdgomes and makson96) * DLC can now be installed and updated (thanks to makson96) * The installed filter now also shows games which are downloading (thanks to makson96) * Fix crash on some systems where /usr/bin is linked to /bin (thanks to sgn) * Create new config file if old one is unreadable (thanks to SvdB-nonp) * Fix some Windows games not installing because of the directory name used (thanks to SvdB-nonp) * Fix some Windows games like Witcher 3 not launching because of the working directory not being set (thanks for kibun1) * Clean up installation files for cancelled downloads (thanks to SvdB-nonp) * Fix crash on flaky internet connection (thanks to makson96) * Use 755 permissions for all directories created by Minigalaxy * Remove cached files when cancelling a download (thanks to svdB-nonp) * Installed games should no longer be shown twice (thanks to makson96) * Add the following translations: * Simplified Chinese (thanks to dummyx) * Spanish (thanks to juanborda) * Update the following translations: * Brazilian Portuguese (thanks to EsdrasTarsis) * Dutch * French (thanks to Thomasb22) * German (thanks to BlindJerobine) * Norwegian Bokmål (thanks to kimmalmo) * Russian (thanks to protheory8) * Taiwanese Mandarin (thanks to s8321414) * Turkish (thanks to fuzunspm) -- Wouter Wijsman Sun, 29 Nov 2020 13:24:10 +0100 minigalaxy (0.9.4) buster; urgency=medium * Added the following translations: * Norwegian Nynorsk (thanks to LordPilum) * Russian (thanks to protheory8) * Updated the following translations: * Brazilian Portuguese (thanks to EsdrasTarsis) * French (thanks to Thomasb22) * German (thanks to BlindJerobine) * Norwegian Bokmål (thanks to kimmalmo) * Polish (thanks to ArturWroblewski) * Taiwanese Mandarin (thanks to s8321414) * Turkish (thanks to fuzunspm) * Added support for installing Windows games (with help from Odelpasso). * Added store page link to game menus (thanks to larslindq). * Fixed game directories being created without any spaces in the name (thanks to larslindq). * Fixed thumbnails not being downloaded for already installed games. * Fixed symlinks to libraries not being created correctly upon installation. * Made preparations for a Flathub package. * Added all contributors and translators to the about window. -- Wouter Wijsman Mon, 20 Apr 2020 20:51:08 +0200 minigalaxy (0.9.3) buster; urgency=medium * Added the following translations: * German (thanks to BlindJerobine) * Turkish (thanks to fuzunspm) * Brazilian Portuguese (thanks to EsdrasTarsis) * Norwegian Bokmål (thanks to kimmalmo) * Polish (thanks to ArturWroblewski) * French (thanks to thomansb22) * Added option to cancel downloads. * Changed the way games are downloaded to a queue instead of trying to download everything at once. * Added support option to game specific menus which open the GOG support page (thanks to BlindJerobine). * Ask for confirmation before uninstalling (thanks to Odelpasso). * Downloads can now be resumed after having been cancelled before. * Installers are now verified before installing. * The active download is now resumed when restarting Minigalaxy. * Fixed issue with games not downloading. -- Wouter Wijsman Wed, 04 Mar 2020 21:15:37 +0100 minigalaxy (0.9.2) buster; urgency=medium * Added a button to installed games which allow you to: * Uninstall a game. * Open the directory in which the game is installed. * Added translations for the following languages: * Dutch * Taiwanese Mandarin (thanks to s8321414) * German (thanks to BlindJerobine) * Added offline mode. * The system's Dosbox and Scummvm installations are now preferred over the ones bundled with games. * Improved game detection to check in all directories in the installation path. * Added the option to keep game installers (thanks to Odelpasso). * Added the option to disable staying logged in (thanks to Odelpasso). * The preferences menu now uses a file picker for setting the installation path (thanks to Odelpasso). * Startup time has been reduced. * Games which aren't installed are now grayed out. * Fixed FTL not being able to start. * Fixed issue with thumbnails sometimes not fully loading. * Fixed potential crash after logging in the first time. * Fixed close button on about window not working. -- Wouter Wijsman Tue, 07 Jan 2020 21:22:38 +0100 minigalaxy (0.9.1) buster; urgency=medium * Fixed crashes and freezes sometimes happening while downloading and installing games. * Fixed installation failing when the installation directory is not on same filesystem as /home. * Fixed downloads crashing when the installation directory is changed or the refresh button is pressed. * Fixed changing installation directory not loading which games are installed in the new directory. * Fixed copyright file in deb package not being machine readable. * Moved binary to /usr/games in the deb package. * Add command line options --help, --version and --reset. The reset option will reset the cache and configuration. -- Wouter Wijsman Fri, 27 Dec 2019 22:31:31 +0100 minigalaxy (0.9.0) buster; urgency=medium * Initial Release. -- Wouter Wijsman Tue, 24 Dec 2019 12:09:27 +0100 minigalaxy-1.1.0/debian/clean000066400000000000000000000001121414231301100160620ustar00rootroot00000000000000minigalaxy.egg-info/ minigalaxy/__pycache__/ data/mo/ debian/minigalaxy.6 minigalaxy-1.1.0/debian/control000066400000000000000000000027031414231301100164700ustar00rootroot00000000000000Source: minigalaxy Section: games Priority: optional Maintainer: Wouter Wijsman Build-Depends: debhelper-compat (= 12), dh-sequence-python3, python3-all, python3-setuptools, help2man, Standards-Version: 4.5.0 Rules-Requires-Root: no Vcs-Git: https://github.com/sharkwouter/minigalaxy.git Vcs-Browser: https://github.com/sharkwouter/minigalaxy Homepage: https://sharkwouter.github.io/minigalaxy/ Package: minigalaxy Architecture: all Depends: ${misc:Depends}, ${python3:Depends}, python3-requests, python3-gi (>= 3.29.1), python3-gi-cairo, gir1.2-gtk-3.0, gir1.2-glib-2.0, gir1.2-gdkpixbuf-2.0, gir1.2-webkit2-4.0, unzip, xdg-utils, Suggests: dosbox, scummvm, wine32 | wine32-development | wine-stable-i386 | wine-devel-i386 | wine-staging-i386, innoextract, Description: Simple GOG Linux client Allows you to download and play Linux games from the gog.com game store. . Besides installing games, it offers the following feature: - Update your games - Install and update DLC - Select in which language you'd prefer to download your games - Change where games are installed - Search your GOG Linux library - Show all games or just the ones you've installed - View the error message if a game fails to launch . A GOG account is required to use this software. minigalaxy-1.1.0/debian/copyright000066400000000000000000000457111414231301100170260ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: minigalaxy Upstream-Contact: Wouter Wijsman Source: https://github.com/sharkwouter/minigalaxy Files: * Copyright: 2019-2020 Wouter Wijsman License: GPL-3+ Files: data/icons/* Copyright: 2014 Epic Runes License: CC-BY-3.0 Files: data/io.github.sharkwouter.Minigalaxy.metainfo.xml data/io.github.sharkwouter.Minigalaxy.desktop Copyright: 2019-2020 Wouter Wijsman . . On Debian systems, the complete text of the GNU General Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". License: CC-BY-3.0 http://creativecommons.org/licenses/by/3.0/ . THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. . BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. . 1. Definitions . a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. c. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. d. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. e. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. f. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. g. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. h. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. i. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. . 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. . 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: . a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, d. to Distribute and Publicly Perform Adaptations. e. For the avoidance of doubt: . i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. . The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. . 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: . a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(b), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(b), as requested. b. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4 (b) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. c. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. . 5. Representations, Warranties and Disclaimer . UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. . 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. . 7. Termination . a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. . 8. Miscellaneous . a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. License: CC0-1.0 On Debian systems, the complete text of the Create Commons Universal license version 1.0 can be found in "/usr/share/common-licenses/CC0-1.0". minigalaxy-1.1.0/debian/minigalaxy.docs000066400000000000000000000000121414231301100200700ustar00rootroot00000000000000README.md minigalaxy-1.1.0/debian/minigalaxy.manpages000066400000000000000000000000231414231301100207350ustar00rootroot00000000000000debian/minigalaxy.6minigalaxy-1.1.0/debian/rules000077500000000000000000000005201414231301100161400ustar00rootroot00000000000000#!/usr/bin/make -f #export DH_VERBOSE = 1 export PYBUILD_DISABLE=test export PYBUILD_NAME=minigalaxy export PYBUILD_INSTALL_ARGS_python3=--install-scripts=/usr/games/ %: dh $@ --buildsystem=pybuild override_dh_auto_build: help2man -N -s 6 -n "a simple GTK based GOG Linux client" bin/minigalaxy > debian/minigalaxy.6 dh_auto_build minigalaxy-1.1.0/debian/source/000077500000000000000000000000001414231301100163635ustar00rootroot00000000000000minigalaxy-1.1.0/debian/source/format000066400000000000000000000000151414231301100175720ustar00rootroot000000000000003.0 (native) minigalaxy-1.1.0/minigalaxy/000077500000000000000000000000001414231301100160035ustar00rootroot00000000000000minigalaxy-1.1.0/minigalaxy/__init__.py000066400000000000000000000000341414231301100201110ustar00rootroot00000000000000""" MiniGalaxy packages """ minigalaxy-1.1.0/minigalaxy/api.py000066400000000000000000000251641414231301100171360ustar00rootroot00000000000000import os import time from urllib.parse import urlencode import requests import xml.etree.ElementTree as ET from minigalaxy.game import Game from minigalaxy.constants import IGNORE_GAME_IDS, SESSION from minigalaxy.config import Config class NoDownloadLinkFound(BaseException): pass class Api: def __init__(self): self.login_success_url = "https://embed.gog.com/on_login_success" self.redirect_uri = "https://embed.gog.com/on_login_success?origin=client" self.client_id = "46899977096215655" self.client_secret = "9d85c43b1482497dbbce61f6e4aa173a433796eeae2ca8c5f6129f2dc4de46d9" self.debug = os.environ.get("MG_DEBUG") self.active_token = False self.active_token_expiration_time = time.time() # use a method to authenticate, based on the information we have # Returns an empty string if no information was entered def authenticate(self, login_code: str = None, refresh_token: str = None) -> str: if refresh_token: return self.__refresh_token(refresh_token) elif login_code: return self.__get_token(login_code) else: return '' # Get a new token with the refresh token received when authenticating the last time def __refresh_token(self, refresh_token: str) -> str: params = { 'client_id': self.client_id, 'client_secret': self.client_secret, 'grant_type': 'refresh_token', 'refresh_token': refresh_token, } response_token = self.__get_refresh_token(params) return response_token # Get a token based on the code returned by the login screen def __get_token(self, login_code: str) -> str: params = { 'client_id': self.client_id, 'client_secret': self.client_secret, 'grant_type': 'authorization_code', 'code': login_code, 'redirect_uri': self.redirect_uri, } response_token = self.__get_refresh_token(params) return response_token def __get_refresh_token(self, params: dict) -> str: request_url = "https://auth.gog.com/token" response = SESSION.get(request_url, params=params) response_params = response.json() if "access_token" in response_params and "expires_in" in response_params and "refresh_token" in response_params: self.active_token = response_params["access_token"] expires_in = response_params["expires_in"] self.active_token_expiration_time = time.time() + int(expires_in) refresh_token = response_params["refresh_token"] else: refresh_token = "" return refresh_token # Get all Linux games in the library of the user. Ignore other platforms and movies def get_library(self): err_msg = "" games = [] if self.active_token: current_page = 1 all_pages_processed = False url = "https://embed.gog.com/account/getFilteredProducts" while not all_pages_processed: params = { 'mediaType': 1, # 1 means game 'page': current_page, } response = self.__request(url, params=params) total_pages = response["totalPages"] for product in response["products"]: if product["id"] not in IGNORE_GAME_IDS: # Only support Linux unless the show_windows_games setting is enabled if product["worksOn"]["Linux"]: platform = "linux" elif Config.get("show_windows_games"): platform = "windows" else: continue if not product["url"]: print("{} ({}) has no store page url".format(product["title"], product['id'])) game = Game(name=product["title"], url=product["url"], game_id=product["id"], image_url=product["image"], platform=platform) games.append(game) if current_page == total_pages: all_pages_processed = True current_page += 1 else: err_msg = "Couldn't connect to GOG servers" return games, err_msg def get_owned_products_ids(self): if not self.active_token: return url2 = "https://embed.gog.com/user/data/games" response2 = self.__request(url2) return response2["owned"] # Generate the URL for the login page for GOG def get_login_url(self) -> str: params = { 'client_id': self.client_id, 'redirect_uri': self.redirect_uri, 'response_type': 'code', 'layout': 'client2', } return "https://auth.gog.com/auth?" + urlencode(params) def get_redirect_url(self) -> str: return self.redirect_uri # Get Extrainfo about a game def get_info(self, game: Game) -> dict: request_url = "https://api.gog.com/products/{}?expand=downloads,expanded_dlcs,description,screenshots,videos," \ "related_products,changelog ".format(str(game.id)) response = self.__request(request_url) return response # This returns a unique download url and a link to the checksum of the download def get_download_info(self, game: Game, operating_system="linux", dlc_installers="") -> dict: if dlc_installers: installers = dlc_installers else: response = self.get_info(game) installers = response["downloads"]["installers"] possible_downloads = [] for installer in installers: if installer["os"] == operating_system: possible_downloads.append(installer) if not possible_downloads: if operating_system == "linux": return self.get_download_info(game, "windows") else: raise NoDownloadLinkFound("Error: {} with id {} couldn't be installed".format(game.name, game.id)) download_info = possible_downloads[0] for installer in possible_downloads: if installer['language'] == Config.get("lang"): download_info = installer break if installer['language'] == "en": download_info = installer # Return last entry in possible_downloads. This will either be English or the first langauge in the list # This is just a backup, if the preferred language has been found, this part won't execute return download_info def get_real_download_link(self, url): return self.__request(url)['downlink'] def get_download_file_md5(self, url): xml_link = self.__request(url)['checksum'] xml_string = SESSION.get(xml_link).text root = ET.fromstring(xml_string) return root.attrib['md5'] def get_file_size(self, url): xml_link = self.__request(url)['checksum'] xml_string = SESSION.get(xml_link).text root = ET.fromstring(xml_string) return root.attrib["total_size"] def get_user_info(self) -> str: username = Config.get("username") if not username: url = "https://embed.gog.com/userData.json" response = self.__request(url) username = response["username"] Config.set("username", username) return username def get_version(self, game: Game, gameinfo=None, dlc_name="") -> str: if gameinfo is None: gameinfo = self.get_info(game) version = "0" if dlc_name: installers = {} for dlc in gameinfo["expanded_dlcs"]: if dlc["title"] == dlc_name: installers = dlc["downloads"]["installers"] break else: installers = gameinfo["downloads"]["installers"] for installer in installers: if installer["os"] == game.platform: version = installer["version"] break return version @staticmethod def can_connect() -> bool: urls = [ "https://embed.gog.com", "https://auth.gog.com", ] for url in urls: try: SESSION.get(url, timeout=5) except requests.exceptions.ConnectionError: return False return True # Make a request with the active token def __request(self, url: str = None, params: dict = None) -> dict: # Refresh the token if needed if self.active_token_expiration_time < time.time(): print("Refreshing token") refresh_token = Config.get("refresh_token") Config.set("refresh_token", self.__refresh_token(refresh_token)) # Make the request headers = { 'Authorization': "Bearer {}".format(str(self.active_token)), } response = SESSION.get(url, headers=headers, params=params) if self.debug: print("Request: {}".format(url)) print("Return code: {}".format(response.status_code)) print("Response body: {}".format(response.text)) print("") return response.json() @staticmethod def __request_gamesdb(game: Game): request_url = "https://gamesdb.gog.com/platforms/gog/external_releases/{}".format(game.id) try: response = SESSION.get(request_url) respones_dict = response.json() except (requests.exceptions.ConnectionError, ValueError): respones_dict = {} return respones_dict def get_gamesdb_info(self, game: Game) -> dict: gamesdb_dict = {"cover": "", "vertical_cover": "", "background": ""} response_json = self.__request_gamesdb(game) if "game" in response_json: for gamesdb_key in gamesdb_dict: if gamesdb_key in response_json['game']: gamesdb_dict[gamesdb_key] = response_json["game"][gamesdb_key]["url_format"].replace( '{formatter}.{ext}', '.png') gamesdb_dict["summary"] = {} for summary_key in response_json["game"]["summary"]: gamesdb_dict["summary"][summary_key] = response_json["game"]["summary"][summary_key] gamesdb_dict["genre"] = {} for genre_key in response_json["game"]["genres"][0]["name"]: gamesdb_dict["genre"][genre_key] = response_json["game"]["genres"][0]["name"][genre_key] else: gamesdb_dict["summary"] = {} gamesdb_dict["genre"] = {} return gamesdb_dict minigalaxy-1.1.0/minigalaxy/config.py000066400000000000000000000073421414231301100176300ustar00rootroot00000000000000import os import threading import json import time from minigalaxy.paths import CONFIG_DIR, CONFIG_FILE_PATH, DEFAULT_INSTALL_DIR # The default values for new configuration files DEFAULT_CONFIGURATION = { "locale": "", "lang": "en", "install_dir": DEFAULT_INSTALL_DIR, "keep_installers": False, "stay_logged_in": True, "show_fps": False, "use_dark_theme": False, "show_hidden_games": False, "show_windows_games": False, "keep_window_maximized": False, "installed_filter": False, "create_applications_file": False } # Make sure you never spawn two instances of this class # If multiple instances go out of sync, they will overwrite each others changes # The config file is only read once upon starting up class __Config: def __init__(self): self.first_run = False self.__config = {} self.__config_file = CONFIG_FILE_PATH self.__update_required = False def first_run_init(self): if not self.first_run: self.first_run = True self.__config = self.__load_config_file() self.__add_missing_config_entries() # Update the config file regularly to reflect the self.__config dictionary keep_config_synced_thread = threading.Thread(target=self.__keep_config_synced) keep_config_synced_thread.daemon = True keep_config_synced_thread.start() def __keep_config_synced(self): while True: if self.__update_required: self.__update_config_file() self.__update_required = False time.sleep(0.1) def __load_config_file(self) -> dict: if os.path.exists(self.__config_file): with open(self.__config_file, "r") as file: try: return json.loads(file.read()) except json.decoder.JSONDecodeError: print("Reading config.json failed, creating new config file.") return self.__create_config_file() else: return self.__create_config_file() def __create_config_file(self) -> dict: # Make sure the configuration directory exists before creating the configuration file if not os.path.exists(CONFIG_DIR): os.makedirs(CONFIG_DIR, mode=0o755) with open(self.__config_file, "w") as file: file.write(json.dumps(DEFAULT_CONFIGURATION)) file.close() # Make sure the default installation path exists if not os.path.isdir(DEFAULT_CONFIGURATION['install_dir']): os.makedirs(DEFAULT_CONFIGURATION['install_dir'], mode=0o755) return DEFAULT_CONFIGURATION def __update_config_file(self): with open(self.__config_file, "w") as file: file.write(json.dumps(self.__config)) file.close() def __add_missing_config_entries(self): # Make sure all config values in the default configuration are available added_value = False for key in DEFAULT_CONFIGURATION: if self.get(key) is None: self.set(key, DEFAULT_CONFIGURATION[key]) added_value = True if added_value: self.__update_config_file() self.__config = self.__load_config_file() def set(self, key, value): self.first_run_init() self.__config[key] = value self.__update_required = True def get(self, key): self.first_run_init() try: return self.__config[key] except KeyError: return None def unset(self, key): self.first_run_init() try: del self.__config[key] self.__update_required = True except KeyError: pass Config = __Config() minigalaxy-1.1.0/minigalaxy/constants.py000066400000000000000000000035011414231301100203700ustar00rootroot00000000000000import requests import platform from minigalaxy.translation import _ from minigalaxy.version import VERSION SUPPORTED_DOWNLOAD_LANGUAGES = [ ["br", _("Brazilian Portuguese")], ["cn", _("Chinese")], ["da", _("Danish")], ["nl", _("Dutch")], ["en", _("English")], ["fi", _("Finnish")], ["fr", _("French")], ["de", _("German")], ["hu", _("Hungarian")], ["it", _("Italian")], ["jp", _("Japanese")], ["ko", _("Korean")], ["no", _("Norwegian")], ["pl", _("Polish")], ["pt", _("Portuguese")], ["ru", _("Russian")], ["es", _("Spanish")], ["sv", _("Swedish")], ["tr", _("Turkish")], ] SUPPORTED_LOCALES = [ ["", _("System default")], ["pt_BR", _("Brazilian Portuguese")], ["cs_CZ", _("Czech")], ["nl", _("Dutch")], ["en_US", _("English")], ["fi", _("Finnish")], ["fr", _("French")], ["de", _("German")], ["it_IT", _("Italian")], ["nb_NO", _("Norwegian Bokmål")], ["nn_NO", _("Norwegian Nynorsk")], ["pl", _("Polish")], ["ru_RU", _("Russian")], ["zh_CN", _("Simplified Chinese")], ["es", _("Spanish")], ["sv_SE", _("Swedish")], ["zh_TW", _("Traditional Chinese")], ["tr", _("Turkish")], ["uk", _("Ukrainian")], ] # Game IDs to ignore when received by the API IGNORE_GAME_IDS = [ 1424856371, # Hotline Miami 2: Wrong Number - Digital Comics 1980301910, # The Witcher Goodies Collection 2005648906, # Spring Sale Goodies Collection #1 1486144755, # Cyberpunk 2077 Goodies Collection ] DOWNLOAD_CHUNK_SIZE = 1024 * 1024 # 1 MB # This is the file size needed for the download manager to consider resuming worthwhile MINIMUM_RESUME_SIZE = 50 * 1024**2 # 50 MB SESSION = requests.Session() SESSION.headers.update({'User-Agent': 'Minigalaxy/{} (Linux {})'.format(VERSION, platform.machine())}) minigalaxy-1.1.0/minigalaxy/css.py000066400000000000000000000002401414231301100171410ustar00rootroot00000000000000from minigalaxy.ui.gtk import Gtk css = '.test { border: 1px solid green; }' CSS_PROVIDER = Gtk.CssProvider() CSS_PROVIDER.load_from_data(css.encode('utf-8')) minigalaxy-1.1.0/minigalaxy/download.py000066400000000000000000000022521414231301100201650ustar00rootroot00000000000000from zipfile import BadZipFile class Download: def __init__(self, url, save_location, finish_func=None, progress_func=None, cancel_func=None, number=1, out_of_amount=1): self.url = url self.save_location = save_location self.__finish_func = finish_func self.__progress_func = progress_func self.__cancel_func = cancel_func self.number = number self.out_of_amount = out_of_amount def set_progress(self, percentage: int) -> None: if self.__progress_func: if self.out_of_amount > 1: # Change the percentage based on which number we are progress_start = 100 / self.out_of_amount * (self.number - 1) percentage = progress_start + percentage / self.out_of_amount percentage = int(percentage) self.__progress_func(percentage) def finish(self): if self.__finish_func: try: self.__finish_func(self.save_location) except (FileNotFoundError, BadZipFile): self.cancel() def cancel(self): if self.__cancel_func: self.__cancel_func() minigalaxy-1.1.0/minigalaxy/download_manager.py000066400000000000000000000144261414231301100216650ustar00rootroot00000000000000import os import shutil import time import threading import queue from requests.exceptions import ConnectionError from minigalaxy.config import Config from minigalaxy.constants import DOWNLOAD_CHUNK_SIZE, MINIMUM_RESUME_SIZE, SESSION from minigalaxy.download import Download class __DownloadManger: def __init__(self): self.__queue = queue.Queue() self.__current_download = None self.__cancel = False self.__paused = False download_thread = threading.Thread(target=self.__download_thread) download_thread.daemon = True download_thread.start() def download(self, download): if isinstance(download, Download): self.__queue.put(download) else: # Assume we've received a list of downloads for d in download: self.__queue.put(d) def download_now(self, download): download_file_thread = threading.Thread(target=self.__download_file, args=(download,)) download_file_thread.daemon = True download_file_thread.start() def cancel_download(self, downloads): # Make sure we're always dealing with a list if isinstance(downloads, Download): downloads = [downloads] for download in downloads: if download == self.__current_download: self.cancel_current_download() else: self.__paused = True new_queue = queue.Queue() while not self.__queue.empty(): queued_download = self.__queue.get() if download == queued_download: download.cancel() else: new_queue.put(queued_download) self.__queue = new_queue self.__paused = False def cancel_current_download(self): self.__cancel = True def cancel_all_downloads(self): while not self.__queue.empty(): self.__queue.get() self.cancel_current_download() # wait for the download to be fully cancelled while self.__current_download: time.sleep(0.1) def __download_thread(self): while True: if not self.__queue.empty(): self.__current_download = self.__queue.get() self.__download_file(self.__current_download) time.sleep(0.1) def __download_file(self, download): self.prepare_location(download.save_location) download_max_attempts = 5 download_attempt = 0 result = False while download_attempt < download_max_attempts: try: start_point, download_mode = self.get_start_point_and_download_mode(download) result = self.download_operation(download, start_point, download_mode) break except ConnectionError as e: print(e) download_attempt += 1 # Successful downloads if result: if download.number == download.out_of_amount: finish_thread = threading.Thread(target=download.finish) finish_thread.start() if self.__queue.empty(): Config.unset("current_download") # Unsuccessful downloads and cancels else: self.__cancel = False download.cancel() self.__current_download = None os.remove(download.save_location) def prepare_location(self, save_location): # Make sure the directory exists save_directory = os.path.dirname(save_location) if not os.path.isdir(save_directory): os.makedirs(save_directory, mode=0o755) # Fail if the file already exists if os.path.isdir(save_location): shutil.rmtree(save_location) print("{} is a directory. Will remove it, to make place for installer.".format(save_location)) def get_start_point_and_download_mode(self, download): # Resume the previous download if possible start_point = 0 download_mode = 'wb' if os.path.isfile(download.save_location): if self.__is_same_download_as_before(download): print("Resuming download {}".format(download.save_location)) download_mode = 'ab' start_point = os.stat(download.save_location).st_size else: os.remove(download.save_location) return start_point, download_mode def download_operation(self, download, start_point, download_mode): # Download the file resume_header = {'Range': 'bytes={}-'.format(start_point)} download_request = SESSION.get(download.url, headers=resume_header, stream=True, timeout=30) downloaded_size = start_point file_size = int(download_request.headers.get('content-length')) result = True if downloaded_size < file_size: with open(download.save_location, download_mode) as save_file: for chunk in download_request.iter_content(chunk_size=DOWNLOAD_CHUNK_SIZE): # Pause if needed while self.__paused: time.sleep(0.1) save_file.write(chunk) downloaded_size += len(chunk) if self.__cancel: result = False break if file_size > 0: progress = int(downloaded_size / file_size * 100) download.set_progress(progress) save_file.close() else: download.set_progress(100) return result def __is_same_download_as_before(self, download): file_stats = os.stat(download.save_location) # Don't resume for very small files if file_stats.st_size < MINIMUM_RESUME_SIZE: return False # Check if the first part of the file download_request = SESSION.get(download.url, stream=True) size_to_check = DOWNLOAD_CHUNK_SIZE * 5 for chunk in download_request.iter_content(chunk_size=size_to_check): with open(download.save_location, "rb") as file: file_content = file.read(size_to_check) return file_content == chunk DownloadManager = __DownloadManger() minigalaxy-1.1.0/minigalaxy/game.py000066400000000000000000000147671414231301100173050ustar00rootroot00000000000000import os import re import json from minigalaxy.config import Config from minigalaxy.paths import CONFIG_GAMES_DIR class Game: def __init__(self, name: str, url: str = "", md5sum=None, game_id: int = 0, install_dir: str = "", image_url="", platform="linux", dlcs=None): self.name = name self.url = url self.md5sum = {} if md5sum is None else md5sum self.id = game_id self.install_dir = install_dir self.image_url = image_url self.platform = platform self.dlcs = [] if dlcs is None else dlcs self.status_file_path = self.get_status_file_path() def get_stripped_name(self): return self.__strip_string(self.name) def get_install_directory_name(self): return re.sub('[^A-Za-z0-9 ]+', '', self.name) def get_status_file_path(self): if self.install_dir: last_install_dir = os.path.basename(os.path.normpath(self.install_dir)) else: last_install_dir = self.get_install_directory_name() status_file_path = os.path.join(CONFIG_GAMES_DIR, "{}.json".format(last_install_dir)) return status_file_path def load_minigalaxy_info_json(self): json_dict = {} if os.path.isfile(self.status_file_path): with open(self.status_file_path, 'r') as status_file: json_dict = json.load(status_file) return json_dict def save_minigalaxy_info_json(self, json_dict): if not os.path.exists(CONFIG_GAMES_DIR): os.makedirs(CONFIG_GAMES_DIR, mode=0o755) with open(self.status_file_path, 'w') as status_file: json.dump(json_dict, status_file) @staticmethod def __strip_string(string): return re.sub('[^A-Za-z0-9]+', '', string) def is_installed(self, dlc_title="") -> bool: installed = False if dlc_title: dlc_version = self.get_dlc_info("version", dlc_title) installed = bool(dlc_version) else: if self.install_dir and os.path.exists(self.install_dir): installed = True return installed def is_update_available(self, version_from_api, dlc_title="") -> bool: update_available = False if dlc_title: installed_version = self.get_dlc_info("version", dlc_title) else: installed_version = self.get_info("version") if not installed_version: installed_version = self.fallback_read_installed_version() self.set_info("version", installed_version) if installed_version and version_from_api and version_from_api != installed_version: update_available = True return update_available def fallback_read_installed_version(self): gameinfo = os.path.join(self.install_dir, "gameinfo") gameinfo_list = [] if os.path.isfile(gameinfo): with open(gameinfo, 'r') as file: gameinfo_list = file.readlines() if len(gameinfo_list) > 1: version = gameinfo_list[1].strip() else: version = "0" return version def set_info(self, key, value): json_dict = self.load_minigalaxy_info_json() json_dict[key] = value self.save_minigalaxy_info_json(json_dict) def set_dlc_info(self, key, value, dlc_title): json_dict = self.load_minigalaxy_info_json() if "dlcs" not in json_dict: json_dict["dlcs"] = {} if dlc_title not in json_dict["dlcs"]: json_dict["dlcs"][dlc_title] = {} json_dict["dlcs"][dlc_title][key] = value self.save_minigalaxy_info_json(json_dict) def get_info(self, key): value = "" json_dict = self.load_minigalaxy_info_json() if key in json_dict: value = json_dict[key] # Start: Code for compatibility with minigalaxy 1.0.1 and 1.0.2 elif os.path.isfile(os.path.join(self.install_dir, "minigalaxy-info.json")): with open(os.path.join(self.install_dir, "minigalaxy-info.json"), 'r') as status_file: json_dict = json.load(status_file) if key in json_dict: value = json_dict[key] # Lets move this value to new config self.set_info(key, value) # End: Code for compatibility with minigalaxy 1.0.1 and 1.0.2 return value def get_dlc_info(self, key, dlc_title): value = "" json_dict = self.load_minigalaxy_info_json() if "dlcs" in json_dict: if dlc_title in json_dict["dlcs"]: if key in json_dict["dlcs"][dlc_title]: value = json_dict["dlcs"][dlc_title][key] # Start: Code for compatibility with minigalaxy 1.0.1 and 1.0.2 if os.path.isfile(os.path.join(self.install_dir, "minigalaxy-info.json")) and not value: with open(os.path.join(self.install_dir, "minigalaxy-info.json"), 'r') as status_file: json_dict = json.load(status_file) if "dlcs" in json_dict: if dlc_title in json_dict["dlcs"]: if key in json_dict["dlcs"][dlc_title]: value = json_dict["dlcs"][dlc_title][key] # Lets move this value to new config self.set_dlc_info(key, value, dlc_title) # End: Code for compatibility with minigalaxy 1.0.1 and 1.0.2 return value def set_install_dir(self): if not self.install_dir: self.install_dir = os.path.join(Config.get("install_dir"), self.get_install_directory_name()) def __str__(self): return self.name def __eq__(self, other): if self.id > 0 and other.id > 0: return self.id == other.id if self.name == other.name: return True # Compare names with special characters and capital letters removed if self.get_stripped_name().lower() == other.get_stripped_name().lower(): return True if self.install_dir and \ other.get_install_directory_name() == os.path.basename(os.path.normpath(self.install_dir)): return True if other.install_dir and \ self.get_install_directory_name() == os.path.basename(os.path.normpath(other.install_dir)): return True return False def __lt__(self, other): # Sort installed games before not installed ones if self.is_installed() != other.is_installed(): return self.is_installed() return str(self) < str(other) minigalaxy-1.1.0/minigalaxy/installer.py000066400000000000000000000301241414231301100203520ustar00rootroot00000000000000import os import shutil import subprocess import hashlib import textwrap from minigalaxy.translation import _ from minigalaxy.launcher import get_execute_command from minigalaxy.paths import CACHE_DIR, THUMBNAIL_DIR, APPLICATIONS_DIR from minigalaxy.config import Config def get_available_disk_space(location): """Check disk space available to the user. This method uses the absolute path so symlinks to disks with sufficient space are correctly measured. Note this is a linux-specific command.""" absolute_location = os.path.realpath(location) disk_status = os.statvfs(os.path.dirname(absolute_location)) available_diskspace = disk_status.f_frsize * disk_status.f_bavail return available_diskspace def get_game_size_from_unzip(installer): var = subprocess.Popen(['unzip', '-v', installer], stdout=subprocess.PIPE) output = var.communicate()[0].decode("utf-8") lines_list = output.split("\n") if len(lines_list) > 2 and not lines_list[-1].strip(): last_line = lines_list[-2].strip() else: last_line = lines_list[-1].strip() size_value = int(last_line.split()[0]) return size_value def check_diskspace(required_size, location): """This method will return True when the disk space available is sufficient for the Download and Install. If not sufficient, it returns False.""" installed_game_size = int(required_size) diskspace_available = get_available_disk_space(location) return diskspace_available >= installed_game_size def install_game(game, installer): # noqa: C901 error_message = "" tmp_dir = "" if not error_message: error_message = verify_installer_integrity(game, installer) if not error_message: error_message = verify_disk_space(game, installer) if not error_message: error_message, tmp_dir = make_tmp_dir(game) if not error_message: error_message = extract_installer(game, installer, tmp_dir) if not error_message: error_message = move_and_overwrite(game, tmp_dir) if not error_message: error_message = copy_thumbnail(game) if not error_message: error_message = create_applications_file(game) if not error_message: error_message = remove_installer(game, installer) else: remove_installer(game, installer) if not error_message: error_message = postinstaller(game) if error_message: print(error_message) return error_message def verify_installer_integrity(game, installer): error_message = "" if not os.path.exists(installer): error_message = _("{} failed to download.").format(installer) if not error_message: for installer_file_name in os.listdir(os.path.dirname(installer)): hash_md5 = hashlib.md5() with open(os.path.join(os.path.dirname(installer), installer_file_name), "rb") as installer_file: for chunk in iter(lambda: installer_file.read(4096), b""): hash_md5.update(chunk) calculated_checksum = hash_md5.hexdigest() if installer_file_name in game.md5sum: if game.md5sum[installer_file_name] == calculated_checksum: print("{} integrity is preserved. MD5 is: {}".format(installer_file_name, calculated_checksum)) else: error_message = _("{} was corrupted. Please download it again.").format(installer_file_name) break else: print("Warning. No info about correct {} MD5 checksum".format(installer_file_name)) return error_message def verify_disk_space(game, installer): err_msg = "" if game.platform == "linux": required_space = get_game_size_from_unzip(installer) if not check_diskspace(required_space, game.install_dir): err_msg = _("Not enough space to extract game. Required: {} Available: {}" ).format(required_space, get_available_disk_space(game.install_dir)) return err_msg def make_tmp_dir(game): # Make a temporary empty directory for extracting the installer error_message = "" extract_dir = os.path.join(CACHE_DIR, "extract") temp_dir = os.path.join(extract_dir, str(game.id)) if os.path.exists(temp_dir): shutil.rmtree(temp_dir, ignore_errors=True) os.makedirs(temp_dir, mode=0o755) return error_message, temp_dir def extract_installer(game, installer, temp_dir): # Extract the installer if game.platform in ["linux"]: err_msg = extract_linux(installer, temp_dir) else: err_msg = extract_windows(game, installer, temp_dir) return err_msg def extract_linux(installer, temp_dir): err_msg = "" command = ["unzip", "-qq", installer, "-d", temp_dir] stdout, stderr, exitcode = _exe_cmd(command) if (exitcode not in [0]) and \ (exitcode not in [1] and "(attempting to process anyway)" not in stderr): err_msg = _("The installation of {} failed. Please try again.").format(installer) elif len(os.listdir(temp_dir)) == 0: err_msg = _("{} could not be unzipped.".format(installer)) return err_msg def extract_windows(game, installer, temp_dir): err_msg = extract_by_innoextract(installer, temp_dir) if err_msg: err_msg = extract_by_wine(game, installer, temp_dir) return err_msg def extract_by_innoextract(installer, temp_dir): err_msg = "" if shutil.which("innoextract"): cmd = ["innoextract", installer, "-d", temp_dir] stdout, stderr, exitcode = _exe_cmd(cmd) if exitcode not in [0]: err_msg = _("Innoextract extraction failed.") else: inno_app_dir = os.path.join(temp_dir, "app") if os.path.isdir(inno_app_dir): _mv(inno_app_dir, temp_dir) innoextract_unneeded_dirs = ["__redist", "tmp", "commonappdata", "app"] for unneeded_dir in innoextract_unneeded_dirs: unneeded_dir_full_path = os.path.join(temp_dir, unneeded_dir) if os.path.isdir(unneeded_dir_full_path): shutil.rmtree(unneeded_dir_full_path) else: err_msg = _("Innoextract not installed.") return err_msg def extract_by_wine(game, installer, temp_dir): err_msg = "" # Set the prefix for Windows games prefix_dir = os.path.join(game.install_dir, "prefix") if not os.path.exists(prefix_dir): os.makedirs(prefix_dir, mode=0o755) # It's possible to set install dir as argument before installation command = ["env", "WINEPREFIX={}".format(prefix_dir), "wine", installer, "/dir={}".format(temp_dir), "/VERYSILENT"] stdout, stderr, exitcode = _exe_cmd(command) if exitcode not in [0]: err_msg = _("Wine extraction failed.") return err_msg def move_and_overwrite(game, temp_dir): # Copy the game files into the correct directory error_message = "" if game.platform == "linux": source_dir = os.path.join(temp_dir, "data/noarch") else: innoextract_dir = os.path.join(temp_dir, "minigalaxy_game_files") source_dir = temp_dir if not os.path.isdir(innoextract_dir) else innoextract_dir target_dir = game.install_dir _mv(source_dir, target_dir) # Remove the temporary directory shutil.rmtree(temp_dir, ignore_errors=True) if game.platform in ["windows"] and "unins000.exe" not in os.listdir(game.install_dir): open(os.path.join(game.install_dir, "unins000.exe"), "w").close() return error_message def copy_thumbnail(game): error_message = "" new_thumbnail_path = os.path.join(game.install_dir, "thumbnail.jpg") # Copy thumbnail if not os.path.isfile(new_thumbnail_path): try: shutil.copyfile(os.path.join(THUMBNAIL_DIR, "{}.jpg".format(game.id)), new_thumbnail_path) except Exception as e: error_message = e return error_message def get_exec_line(game): exe_cmd_list = get_execute_command(game) for i in range(len(exe_cmd_list)): exe_cmd_list[i] = exe_cmd_list[i].replace(" ", "\\ ") return " ".join(exe_cmd_list) def create_applications_file(game): error_message = "" if Config.get("create_applications_file"): path_to_shortcut = os.path.join(APPLICATIONS_DIR, "{}.desktop".format(game.name)) exe_cmd = get_exec_line(game) # Create desktop file definition desktop_context = { "game_bin_path": exe_cmd, "game_name": game.name, "game_install_dir": game.install_dir, "game_icon_path": os.path.join(game.install_dir, 'support/icon.png') } desktop_definition = """\ [Desktop Entry] Type=Application Terminal=false StartupNotify=true Exec={game_bin_path} Path={game_install_dir} Name={game_name} Icon={game_icon_path}""".format(**desktop_context) if not os.path.isfile(path_to_shortcut): try: with open(path_to_shortcut, 'w+') as desktop_file: desktop_file.writelines(textwrap.dedent(desktop_definition)) except Exception as e: os.remove(path_to_shortcut) error_message = e return error_message def compare_directories(dir1, dir2): files_1 = [] files_2 = [] if os.path.isdir(dir1): files_1 = os.listdir(dir1) if os.path.isdir(dir2): files_2 = os.listdir(dir2) if not set(files_1).issubset(set(files_2)): return False result = True for f in files_1: if os.path.getsize(os.path.join(dir1, f)) != \ os.path.getsize(os.path.join(dir2, f)): result = False return result def remove_installer(game, installer): error_message = "" installer_directory = os.path.dirname(installer) if not os.path.isdir(installer_directory): error_message = "No installer directory is present: {}".format(installer_directory) return error_message if Config.get("keep_installers"): keep_dir = os.path.join(Config.get("install_dir"), "installer") keep_dir2 = os.path.join(keep_dir, game.get_install_directory_name()) if keep_dir2 == installer_directory: # We are using the keep installer already return error_message if not compare_directories(installer_directory, keep_dir2): shutil.rmtree(keep_dir2, ignore_errors=True) try: shutil.move(installer_directory, keep_dir2) except Exception as e: error_message = str(e) else: shutil.rmtree(installer_directory, ignore_errors=True) return error_message def postinstaller(game): err_msg = "" postinst_script = os.path.join(game.install_dir, "support", "postinst.sh") if os.path.isfile(postinst_script): os.chmod(postinst_script, 0o775) stdout, stderr, exitcode = _exe_cmd([postinst_script]) if exitcode not in [0]: err_msg = "Postinstallation script failed: {}".format(postinst_script) return err_msg def uninstall_game(game): shutil.rmtree(game.install_dir, ignore_errors=True) if os.path.isfile(game.status_file_path): os.remove(game.status_file_path) if os.path.isfile(os.path.join(APPLICATIONS_DIR, "{}.desktop".format(game.name))): os.remove(os.path.join(APPLICATIONS_DIR, "{}.desktop".format(game.name))) def _exe_cmd(cmd): process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() stdout = stdout.decode("utf-8") stderr = stderr.decode("utf-8") return stdout, stderr, process.returncode def _mv(source_dir, target_dir): for src_dir, dirs, files in os.walk(source_dir): destination_dir = src_dir.replace(source_dir, target_dir, 1) if not os.path.exists(destination_dir): os.makedirs(destination_dir) for src_file in files: file_to_copy = os.path.join(src_dir, src_file) dst_file = os.path.join(destination_dir, src_file) if os.path.exists(dst_file): os.remove(dst_file) shutil.move(file_to_copy, destination_dir) minigalaxy-1.1.0/minigalaxy/launcher.py000066400000000000000000000167421414231301100201700ustar00rootroot00000000000000import os import subprocess import shutil import re import json import glob from minigalaxy.translation import _ def config_game(game): prefix = os.path.join(game.install_dir, "prefix") os.environ["WINEPREFIX"] = prefix subprocess.Popen(['wine', 'winecfg']) def regedit_game(game): prefix = os.path.join(game.install_dir, "prefix") os.environ["WINEPREFIX"] = prefix subprocess.Popen(['wine', 'regedit']) def start_game(game): error_message = "" process = None if not error_message: error_message = set_fps_display(game) if not error_message: error_message, process = run_game_subprocess(game) if not error_message: error_message = check_if_game_started_correctly(process, game) if error_message: print(_("Failed to start {}:").format(game.name)) print(error_message) return error_message def get_execute_command(game) -> list: files = os.listdir(game.install_dir) launcher_type = determine_launcher_type(files) if launcher_type in ["start_script", "wine"]: exe_cmd = get_start_script_exe_cmd() elif launcher_type == "windows": exe_cmd = get_windows_exe_cmd(game, files) elif launcher_type == "dosbox": exe_cmd = get_dosbox_exe_cmd(game, files) elif launcher_type == "scummvm": exe_cmd = get_scummvm_exe_cmd(game, files) elif launcher_type == "final_resort": exe_cmd = get_final_resort_exe_cmd(game, files) else: # If no executable was found at all, raise an error raise FileNotFoundError() exe_cmd = get_exe_cmd_with_var_command(game, exe_cmd) return exe_cmd def determine_launcher_type(files): launcher_type = "unknown" if "unins000.exe" in files: launcher_type = "windows" elif "dosbox" in files and shutil.which("dosbox"): launcher_type = "dosbox" elif "scummvm" in files and shutil.which("scummvm"): launcher_type = "scummvm" elif "prefix" in files and shutil.which("wine"): launcher_type = "wine" elif "start.sh" in files: launcher_type = "start_script" elif "game" in files: launcher_type = "final_resort" return launcher_type def get_exe_cmd_with_var_command(game, exe_cmd): command_list = game.get_info("command").split() var_list = game.get_info("variable").split() if var_list: if var_list[0] not in ["env"]: var_list.insert(0, "env") exe_cmd = var_list + exe_cmd + command_list return exe_cmd def get_windows_exe_cmd(game, files): exe_cmd = [""] prefix = os.path.join(game.install_dir, "prefix") os.environ["WINEPREFIX"] = prefix # Find game executable file for file in files: if re.match(r'^goggame-[0-9]*\.info$', file): os.chdir(game.install_dir) with open(file, 'r') as info_file: info = json.loads(info_file.read()) # if we have the workingDir property, start the executable at that directory if info["playTasks"]: if "workingDir" in info["playTasks"][0] and info["playTasks"][0]["workingDir"]: exe_cmd = ["wine", "start", "/b", "/wait", "/d", info["playTasks"][0]["workingDir"], info["playTasks"][0]["path"]] else: exe_cmd = ["wine", info["playTasks"][0]["path"]] if exe_cmd == [""]: # in case no goggame info file was found executables = glob.glob(game.install_dir + '/*.exe') executables.remove(os.path.join(game.install_dir, "unins000.exe")) filename = os.path.splitext(os.path.basename(executables[0]))[0] + '.exe' exe_cmd = ["wine", filename] return exe_cmd def get_dosbox_exe_cmd(game, files): dosbox_config = "" dosbox_config_single = "" for file in files: if re.match(r'^dosbox_?([a-z]|[A-Z]|[0-9])+\.conf$', file): dosbox_config = file if re.match(r'^dosbox_?([a-z]|[A-Z]|[0-9])+_single\.conf$', file): dosbox_config_single = file print("Using system's dosbox to launch {}".format(game.name)) return ["dosbox", "-conf", dosbox_config, "-conf", dosbox_config_single, "-no-console", "-c", "exit"] def get_scummvm_exe_cmd(game, files): scummvm_config = "" for file in files: if re.match(r'^.*\.ini$', file): scummvm_config = file break print("Using system's scrummvm to launch {}".format(game.name)) return ["scummvm", "-c", scummvm_config] def get_start_script_exe_cmd(): return ["./start.sh"] def get_final_resort_exe_cmd(game, files): # This is the final resort, applies to FTL exe_cmd = [""] game_dir = "game" game_files = os.listdir(os.path.join(game.install_dir, game_dir)) if game_dir in files else [] for file in game_files: if re.match(r'^goggame-[0-9]*\.info$', file): os.chdir(os.path.join(game.install_dir, game_dir)) with open(file, 'r') as info_file: info = json.loads(info_file.read()) exe_cmd = ["./{}".format(info["playTasks"][0]["path"])] return exe_cmd def set_fps_display(game): error_message = "" # Enable FPS Counter for Nvidia or AMD (Mesa) users if game.get_info("show_fps"): os.environ["__GL_SHOW_GRAPHICS_OSD"] = "1" # For Nvidia users + OpenGL/Vulkan games os.environ["GALLIUM_HUD"] = "simple,fps" # For AMDGPU users + OpenGL games os.environ["VK_INSTANCE_LAYERS"] = "VK_LAYER_MESA_overlay" # For AMDGPU users + Vulkan games else: os.environ["__GL_SHOW_GRAPHICS_OSD"] = "0" os.environ["GALLIUM_HUD"] = "" os.environ["VK_INSTANCE_LAYERS"] = "" return error_message def run_game_subprocess(game): # Change the directory to the install dir working_dir = os.getcwd() os.chdir(game.install_dir) try: process = subprocess.Popen(get_execute_command(game), stdout=subprocess.PIPE, stderr=subprocess.PIPE) error_message = "" except FileNotFoundError: process = None error_message = _("No executable was found in {}").format(game.install_dir) # restore the working directory os.chdir(working_dir) return error_message, process def check_if_game_started_correctly(process, game): error_message = "" # Check if the application has started and see if it is still runnning after a short timeout try: process.wait(timeout=float(3)) error_message = "Game start process has finished prematurely" except subprocess.TimeoutExpired: pass if error_message in ["Game start process has finished prematurely"]: error_message = check_if_game_start_process_spawned_final_process(error_message, game) # Set the error message to what's been received in std error if not yet set if error_message: stdout, stderror = process.communicate() if stderror: error_message = stderror.decode("utf-8") elif stdout: error_message = stdout.decode("utf-8") return error_message def check_if_game_start_process_spawned_final_process(error_message, game): ps_ef = subprocess.check_output(["ps", "-ef"]).decode("utf-8") ps_list = ps_ef.split("\n") for ps in ps_list: ps_split = ps.split() if len(ps_split) < 2: continue if not ps_split[1].isdigit(): continue if int(ps_split[1]) > os.getpid() and game.get_install_directory_name() in ps: error_message = "" break return error_message minigalaxy-1.1.0/minigalaxy/paths.py000066400000000000000000000031151414231301100174740ustar00rootroot00000000000000import os import sys LAUNCH_DIR = os.path.abspath(os.path.dirname(sys.argv[0])) if LAUNCH_DIR == "/bin" or LAUNCH_DIR == "/sbin": LAUNCH_DIR = "/usr" + LAUNCH_DIR CONFIG_DIR = os.path.join(os.getenv('XDG_CONFIG_HOME', os.path.expanduser('~/.config')), "minigalaxy") CONFIG_GAMES_DIR = os.path.join(CONFIG_DIR, "games") CONFIG_FILE_PATH = os.path.join(CONFIG_DIR, "config.json") CACHE_DIR = os.path.join(os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache')), "minigalaxy") THUMBNAIL_DIR = os.path.join(CACHE_DIR, "thumbnails") APPLICATIONS_DIR = os.path.expanduser("~/.local/share/applications") DEFAULT_INSTALL_DIR = os.path.expanduser("~/GOG Games") UI_DIR = os.path.abspath(os.path.join(LAUNCH_DIR, "../data/ui")) if not os.path.exists(UI_DIR): UI_DIR = os.path.abspath(os.path.join(LAUNCH_DIR, "../share/minigalaxy/ui")) LOGO_IMAGE_PATH = os.path.abspath(os.path.join(LAUNCH_DIR, "../data/icons/192x192/io.github.sharkwouter.Minigalaxy.png")) if not os.path.exists(LOGO_IMAGE_PATH): LOGO_IMAGE_PATH = os.path.abspath( os.path.join(LAUNCH_DIR, "../share/icons/hicolor/192x192/apps/io.github.sharkwouter.Minigalaxy.png") ) ICON_WINE_PATH = os.path.abspath(os.path.join(LAUNCH_DIR, "../data/images/winehq_logo_glass.png")) if not os.path.exists(ICON_WINE_PATH): ICON_WINE_PATH = os.path.abspath(os.path.join(LAUNCH_DIR, "../share/minigalaxy/images/winehq_logo_glass.png")) LOCALE_DIR = os.path.abspath(os.path.join(LAUNCH_DIR, "../data/mo")) if not os.path.exists(LOCALE_DIR): LOCALE_DIR = os.path.abspath(os.path.join(LAUNCH_DIR, "../share/minigalaxy/translations")) minigalaxy-1.1.0/minigalaxy/translation.py000066400000000000000000000022111414231301100207070ustar00rootroot00000000000000import os import gettext import locale from minigalaxy.config import Config from minigalaxy.paths import LOCALE_DIR TRANSLATION_DOMAIN = "minigalaxy" try: locale.setlocale(locale.LC_ALL, '') except locale.Error: print("Unsupported locale detected, continuing without translation support") try: locale.bindtextdomain(TRANSLATION_DOMAIN, LOCALE_DIR) except AttributeError: print("Couldn't run locale.bindtextdomain. Translations might not work correctly.") try: locale.textdomain(TRANSLATION_DOMAIN) except AttributeError: print("Couldn't run locale.textdomain. Translations might not work correctly.") gettext.bindtextdomain(TRANSLATION_DOMAIN, LOCALE_DIR) gettext.textdomain(TRANSLATION_DOMAIN) # Make sure LANGUAGE is not set, or translations will not be loaded os.unsetenv("LANGUAGE") current_locale = Config.get("locale") default_locale = locale.getdefaultlocale()[0] if current_locale == '': lang = gettext.translation(TRANSLATION_DOMAIN, LOCALE_DIR, languages=[default_locale], fallback=True) else: lang = gettext.translation(TRANSLATION_DOMAIN, LOCALE_DIR, languages=[current_locale], fallback=True) _ = lang.gettext minigalaxy-1.1.0/minigalaxy/ui/000077500000000000000000000000001414231301100164205ustar00rootroot00000000000000minigalaxy-1.1.0/minigalaxy/ui/__init__.py000066400000000000000000000004131414231301100205270ustar00rootroot00000000000000""" MiniGalaxy gui windows """ # Flake8 thinks these imports are unused from minigalaxy.ui.window import Window # noqa: F401 from minigalaxy.ui.preferences import Preferences # noqa: F401 from minigalaxy.ui.gametile import GameTile # noqa: F401 minigalaxy-1.1.0/minigalaxy/ui/about.py000066400000000000000000000010551414231301100201050ustar00rootroot00000000000000import os from minigalaxy.version import VERSION from minigalaxy.translation import _ from minigalaxy.paths import LOGO_IMAGE_PATH, UI_DIR from minigalaxy.ui.gtk import Gtk, GdkPixbuf @Gtk.Template.from_file(os.path.join(UI_DIR, "about.ui")) class About(Gtk.AboutDialog): __gtype_name__ = "About" def __init__(self, parent): Gtk.AboutDialog.__init__(self, title=_("About"), parent=parent, modal=True) self.set_version(VERSION) new_image = GdkPixbuf.Pixbuf().new_from_file(LOGO_IMAGE_PATH) self.set_logo(new_image) minigalaxy-1.1.0/minigalaxy/ui/gametile.py000066400000000000000000000575251414231301100205770ustar00rootroot00000000000000import shutil import locale import os import threading import re import time import urllib.parse from enum import Enum from minigalaxy.translation import _ from minigalaxy.paths import CACHE_DIR, THUMBNAIL_DIR, UI_DIR from minigalaxy.config import Config from minigalaxy.download import Download from minigalaxy.download_manager import DownloadManager from minigalaxy.launcher import start_game from minigalaxy.installer import uninstall_game, install_game, check_diskspace from minigalaxy.css import CSS_PROVIDER from minigalaxy.paths import ICON_WINE_PATH from minigalaxy.api import NoDownloadLinkFound from minigalaxy.ui.gtk import Gtk, GLib, Gio, GdkPixbuf from minigalaxy.ui.properties import Properties @Gtk.Template.from_file(os.path.join(UI_DIR, "gametile.ui")) class GameTile(Gtk.Box): __gtype_name__ = "GameTile" image = Gtk.Template.Child() button = Gtk.Template.Child() button_cancel = Gtk.Template.Child() menu_button = Gtk.Template.Child() wine_icon = Gtk.Template.Child() update_icon = Gtk.Template.Child() menu_button_update = Gtk.Template.Child() menu_button_dlc = Gtk.Template.Child() menu_button_uninstall = Gtk.Template.Child() dlc_horizontal_box = Gtk.Template.Child() menu_button_properties = Gtk.Template.Child() state = Enum('state', 'DOWNLOADABLE INSTALLABLE UPDATABLE QUEUED DOWNLOADING INSTALLING INSTALLED NOTLAUNCHABLE UNINSTALLING' ' UPDATING UPDATE_INSTALLABLE') def __init__(self, parent, game): current_locale = Config.get("locale") default_locale = locale.getdefaultlocale()[0] if current_locale == '': locale.setlocale(locale.LC_ALL, (default_locale, 'UTF-8')) else: try: locale.setlocale(locale.LC_ALL, (current_locale, 'UTF-8')) except NameError: locale.setlocale(locale.LC_ALL, (default_locale, 'UTF-8')) Gtk.Frame.__init__(self) Gtk.StyleContext.add_provider(self.button.get_style_context(), CSS_PROVIDER, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) self.parent = parent self.game = game self.api = parent.api self.offline = parent.offline self.progress_bar = None self.thumbnail_set = False self.download_list = [] self.dlc_dict = {} self.current_state = self.state.DOWNLOADABLE self.image.set_tooltip_text(self.game.name) # Set folder for download installer self.download_dir = os.path.join(CACHE_DIR, "download", self.game.get_install_directory_name()) # Set folder if user wants to keep installer (disabled by default) self.keep_dir = os.path.join(Config.get("install_dir"), "installer") self.keep_path = os.path.join(self.keep_dir, self.game.get_install_directory_name()) if not os.path.exists(CACHE_DIR): os.makedirs(CACHE_DIR, mode=0o755) self.reload_state() load_thumbnail_thread = threading.Thread(target=self.load_thumbnail) load_thumbnail_thread.start() # Start download if Minigalaxy was closed while downloading this game self.resume_download_if_expected() # Icon for Windows games if self.game.platform == "windows": self.image.set_tooltip_text("{} (Wine)".format(self.game.name)) self.wine_icon.set_from_file(ICON_WINE_PATH) self.wine_icon.show() # Downloads if Minigalaxy was closed with this game downloading def resume_download_if_expected(self): download_id = Config.get("current_download") if download_id and download_id == self.game.id and self.current_state == self.state.DOWNLOADABLE: download_thread = threading.Thread(target=self.__download_game) download_thread.start() # Do not restart the download if Minigalaxy is restarted def prevent_resume_on_startup(self): download_id = Config.get("current_download") if download_id and download_id == self.game.id: Config.unset("current_download") def __str__(self): return self.game.name @Gtk.Template.Callback("on_button_clicked") def on_button_click(self, widget) -> None: dont_act_in_states = [self.state.QUEUED, self.state.DOWNLOADING, self.state.INSTALLING, self.state.UNINSTALLING] err_msg = "" if self.current_state in dont_act_in_states: pass elif self.current_state in [self.state.INSTALLED, self.state.UPDATABLE]: err_msg = start_game(self.game) elif self.current_state == self.state.INSTALLABLE: install_thread = threading.Thread(target=self.__install_game, args=(self.get_keep_executable_path(),)) install_thread.start() elif self.current_state == self.state.DOWNLOADABLE: download_thread = threading.Thread(target=self.__download_game) download_thread.start() if err_msg: self.parent.parent.show_error(_("Failed to start {}:").format(self.game.name), err_msg) @Gtk.Template.Callback("on_menu_button_properties_clicked") def show_properties(self, button): properties_window = Properties(self, self.game, self.api) properties_window.run() properties_window.destroy() @Gtk.Template.Callback("on_button_cancel_clicked") def on_button_cancel(self, widget): question = _("Are you sure you want to cancel downloading {}?").format(self.game.name) if self.parent.parent.show_question(question): self.prevent_resume_on_startup() DownloadManager.cancel_download(self.download_list) try: for filename in os.listdir(self.download_dir): if self.game.get_install_directory_name() in filename: os.remove(os.path.join(self.download_dir, filename)) except FileNotFoundError: pass @Gtk.Template.Callback("on_menu_button_uninstall_clicked") def on_menu_button_uninstall(self, widget): question = _("Are you sure you want to uninstall %s?" % self.game.name) if self.parent.parent.show_question(question): uninstall_thread = threading.Thread(target=self.__uninstall_game) uninstall_thread.start() @Gtk.Template.Callback("on_menu_button_update_clicked") def on_menu_button_update(self, widget): download_thread = threading.Thread(target=self.__download_update) download_thread.start() def load_thumbnail(self): set_result = self.__set_image("") if not set_result: tries = 10 performed_try = 0 while performed_try < tries: if self.game.image_url and self.game.id: # Download the thumbnail image_url = "https:{}_196.jpg".format(self.game.image_url) thumbnail = os.path.join(THUMBNAIL_DIR, "{}.jpg".format(self.game.id)) download = Download(image_url, thumbnail, finish_func=self.__set_image) DownloadManager.download_now(download) set_result = True break performed_try += 1 time.sleep(1) return set_result def __set_image(self, save_location): set_result = False self.game.set_install_dir() thumbnail_install_dir = os.path.join(self.game.install_dir, "thumbnail.jpg") if os.path.isfile(thumbnail_install_dir): GLib.idle_add(self.image.set_from_file, thumbnail_install_dir) set_result = True elif save_location and os.path.isfile(save_location): GLib.idle_add(self.image.set_from_file, save_location) # Copy image to if os.path.isdir(os.path.dirname(thumbnail_install_dir)): shutil.copy2(save_location, thumbnail_install_dir) set_result = True return set_result def get_keep_executable_path(self): keep_path = "" if os.path.isdir(self.keep_path): for dir_content in os.listdir(self.keep_path): kept_file = os.path.join(self.keep_path, dir_content) if os.access(kept_file, os.X_OK) or os.path.splitext(kept_file)[-1] in [".exe", ".sh"]: keep_path = kept_file break return keep_path def get_download_info(self, platform="linux"): try: download_info = self.api.get_download_info(self.game, platform) result = True except NoDownloadLinkFound as e: print(e) if Config.get("current_download") == self.game.id: Config.unset("current_download") GLib.idle_add(self.parent.parent.show_error, _("Download error"), _("There was an error when trying to fetch the download link!\n{}".format(e))) download_info = False result = False return result, download_info def __download_game(self) -> None: finish_func = self.__install_game cancel_to_state = self.state.DOWNLOADABLE result, download_info = self.get_download_info() if result: result = self.__download(download_info, finish_func, cancel_to_state) if not result: GLib.idle_add(self.update_to_state, cancel_to_state) def __download(self, download_info, finish_func, cancel_to_state): download_success = True GLib.idle_add(self.update_to_state, self.state.QUEUED) Config.set("current_download", self.game.id) # Start the download for all files self.download_list = [] number_of_files = len(download_info['files']) total_file_size = 0 executable_path = None for key, file_info in enumerate(download_info['files']): try: download_url = self.api.get_real_download_link(file_info["downlink"]) except ValueError as e: print(e) GLib.idle_add(self.parent.parent.show_error, _("Download error"), _(str(e))) download_success = False break total_file_size += int(self.api.get_file_size(file_info["downlink"])) try: # Extract the filename from the download url (filename is between %2F and &token) filename = urllib.parse.unquote(re.search('%2F(((?!%2F).)*)&t', download_url).group(1)) except AttributeError: filename = "{}-{}.bin".format(self.game.get_stripped_name(), key) download_path = os.path.join(self.download_dir, filename) if key == 0: # If key = 0, denote the file as the executable's path executable_path = download_path self.game.md5sum[os.path.basename(download_path)] = self.api.get_download_file_md5(file_info["downlink"]) download = Download( url=download_url, save_location=download_path, finish_func=finish_func if download_path == executable_path else None, progress_func=self.set_progress, cancel_func=lambda: self.__cancel(to_state=cancel_to_state), number=number_of_files - key, out_of_amount=number_of_files ) self.download_list.append(download) self.download_list.reverse() if check_diskspace(total_file_size, Config.get("install_dir")): DownloadManager.download(self.download_list) ds_msg_title = "" ds_msg_text = "" else: ds_msg_title = "Download error" ds_msg_text = "Not enough disk space to install game." download_success = False if ds_msg_title: GLib.idle_add(self.parent.parent.show_error, _(ds_msg_title), _(ds_msg_text)) return download_success def __install_game(self, save_location): self.game.set_install_dir() install_success = self.__install(save_location) if install_success: self.__check_for_dlc(self.api.get_info(self.game)) def __install(self, save_location, update=False, dlc_title=""): if update: processing_state = self.state.UPDATING failed_state = self.state.INSTALLED else: processing_state = self.state.INSTALLING failed_state = self.state.DOWNLOADABLE success_state = self.state.INSTALLED GLib.idle_add(self.update_to_state, processing_state) err_msg = install_game(self.game, save_location) if not err_msg: GLib.idle_add(self.update_to_state, success_state) install_success = True if dlc_title: self.game.set_dlc_info("version", self.api.get_version(self.game, dlc_name=dlc_title), dlc_title) else: self.game.set_info("version", self.api.get_version(self.game)) else: GLib.idle_add(self.parent.parent.show_error, _("Failed to install {}").format(self.game.name), err_msg) GLib.idle_add(self.update_to_state, failed_state) install_success = False return install_success def __cancel(self, to_state): GLib.idle_add(self.update_to_state, to_state) GLib.idle_add(self.reload_state) def __download_update(self) -> None: finish_func = self.__update cancel_to_state = self.state.UPDATABLE result, download_info = self.get_download_info(self.game.platform) if result: result = self.__download(download_info, finish_func, cancel_to_state) if not result: GLib.idle_add(self.update_to_state, cancel_to_state) def __check_for_update_dlc(self): if self.game.is_installed() and self.game.id and not self.offline: game_info = self.api.get_info(self.game) game_version = self.api.get_version(self.game, gameinfo=game_info) update_available = self.game.is_update_available(game_version) if update_available: GLib.idle_add(self.update_to_state, self.state.UPDATABLE) self.__check_for_dlc(game_info) if self.offline: GLib.idle_add(self.menu_button_dlc.hide) def __update(self, save_location): install_success = self.__install(save_location, update=True) if install_success: if self.game.platform == "windows": self.image.set_tooltip_text("{} (Wine)".format(self.game.name)) else: self.image.set_tooltip_text(self.game.name) for dlc in self.game.dlcs: download_info = self.api.get_download_info(self.game, dlc_installers=dlc["downloads"]["installers"]) if self.game.is_update_available(version_from_api=download_info["version"], dlc_title=dlc["title"]): self.__download_dlc(dlc["downloads"]["installers"]) def __download_dlc(self, dlc_installers) -> None: def finish_func(save_location): self.__install_dlc(save_location, dlc_title=dlc_title) download_info = self.api.get_download_info(self.game, dlc_installers=dlc_installers) dlc_title = self.game.name for dlc in self.game.dlcs: if dlc["downloads"]["installers"] == dlc_installers: dlc_title = dlc["title"] cancel_to_state = self.state.INSTALLED result = self.__download(download_info, finish_func, cancel_to_state) if not result: GLib.idle_add(self.update_to_state, cancel_to_state) def __install_dlc(self, save_location, dlc_title): install_success = self.__install(save_location, dlc_title=dlc_title) if not install_success: GLib.idle_add(self.update_to_state, self.state.INSTALLED) self.__check_for_update_dlc() def __check_for_dlc(self, game_info): dlcs = game_info["expanded_dlcs"] for dlc in dlcs: if dlc["is_installable"] and dlc["id"] in self.parent.owned_products_ids: d_installer = dlc["downloads"]["installers"] d_icon = dlc["images"]["sidebarIcon"] d_name = dlc["title"] GLib.idle_add(self.update_gtk_box_for_dlc, d_icon, d_name, d_installer) if dlc not in self.game.dlcs: self.game.dlcs.append(dlc) if self.game.dlcs: GLib.idle_add(self.menu_button_dlc.show) def update_gtk_box_for_dlc(self, icon, title, installer): if title not in self.dlc_dict: dlc_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) dlc_box.set_spacing(8) image = Gtk.Image() image.set_from_icon_name("media-optical", Gtk.IconSize.BUTTON) dlc_box.pack_start(image, False, True, 0) label = Gtk.Label(label=title, xalign=0) dlc_box.pack_start(label, True, True, 0) install_button = Gtk.Button() dlc_box.pack_start(install_button, False, True, 0) self.dlc_dict[title] = [install_button, image] self.dlc_dict[title][0].connect("clicked", lambda x: self.__download_dlc(installer)) self.dlc_horizontal_box.pack_start(dlc_box, False, True, 0) dlc_box.show_all() self.get_async_image_dlc_icon(icon, title) download_info = self.api.get_download_info(self.game, dlc_installers=installer) if self.game.is_update_available(version_from_api=download_info["version"], dlc_title=title): icon_name = "emblem-synchronizing" self.dlc_dict[title][0].set_sensitive(True) elif self.game.is_installed(dlc_title=title): icon_name = "object-select" self.dlc_dict[title][0].set_sensitive(False) else: icon_name = "document-save" self.dlc_dict[title][0].set_sensitive(True) install_button_image = Gtk.Image() install_button_image.set_from_icon_name(icon_name, Gtk.IconSize.BUTTON) self.dlc_dict[title][0].set_image(install_button_image) def get_async_image_dlc_icon(self, icon, title): if icon: url = "http:{}".format(icon) response = Gio.File.new_for_uri(url) response.read_async(3, None, self.set_proper_dlc_icon, title) def set_proper_dlc_icon(self, source, async_res, user_data): response = source.read_finish(async_res) pixbuf = GdkPixbuf.Pixbuf.new_from_stream(response) self.dlc_dict[user_data][1].set_from_pixbuf(pixbuf) def set_progress(self, percentage: int): if self.current_state == self.state.QUEUED: GLib.idle_add(self.update_to_state, self.state.DOWNLOADING) if self.progress_bar: GLib.idle_add(self.progress_bar.set_fraction, percentage / 100) def __uninstall_game(self): GLib.idle_add(self.update_to_state, self.state.UNINSTALLING) uninstall_game(self.game) GLib.idle_add(self.update_to_state, self.state.DOWNLOADABLE) GLib.idle_add(self.reload_state) def __create_progress_bar(self) -> None: self.progress_bar = Gtk.ProgressBar() self.progress_bar.set_halign(Gtk.Align.CENTER) self.progress_bar.set_size_request(196, -1) self.progress_bar.set_hexpand(False) self.progress_bar.set_vexpand(False) self.set_center_widget(self.progress_bar) self.progress_bar.set_fraction(0.0) def reload_state(self): self.game.set_install_dir() dont_act_in_states = [self.state.QUEUED, self.state.DOWNLOADING, self.state.INSTALLING, self.state.UNINSTALLING, self.state.UPDATING, self.state.DOWNLOADING] if self.current_state in dont_act_in_states: return if self.game.is_installed(): self.update_to_state(self.state.INSTALLED) check_update_thread = threading.Thread(target=self.__check_for_update_dlc) check_update_thread.start() elif self.get_keep_executable_path(): self.update_to_state(self.state.INSTALLABLE) else: self.update_to_state(self.state.DOWNLOADABLE) def __state_downloadable(self): self.button.set_label(_("download")) self.button.set_sensitive(True) self.image.set_sensitive(False) # The user must have the possibilty to access # to the store button even if the game is not installed self.menu_button.show() self.menu_button_update.hide() self.menu_button_dlc.hide() self.menu_button_uninstall.hide() self.button_cancel.hide() self.game.install_dir = "" if self.progress_bar: self.progress_bar.destroy() def __state_installable(self): self.button.set_label(_("install")) self.button.set_sensitive(True) self.image.set_sensitive(False) self.menu_button.hide() self.button_cancel.hide() self.game.install_dir = "" if self.progress_bar: self.progress_bar.destroy() def __state_queued(self): self.button.set_label(_("in queue…")) self.button.set_sensitive(False) self.image.set_sensitive(False) self.menu_button.hide() self.button_cancel.show() self.__create_progress_bar() def __state_downloading(self): self.button.set_label(_("downloading…")) self.button.set_sensitive(False) self.image.set_sensitive(False) self.menu_button.hide() self.button_cancel.show() if not self.progress_bar: self.__create_progress_bar() self.progress_bar.show_all() def __state_installing(self): self.button.set_label(_("installing…")) self.button.set_sensitive(False) self.image.set_sensitive(True) self.menu_button.hide() self.button_cancel.hide() self.game.set_install_dir() if self.progress_bar: self.progress_bar.destroy() self.parent.filter_library() def __state_installed(self): self.button.set_label(_("play")) self.button.get_style_context().add_class("suggested-action") self.button.set_sensitive(True) self.image.set_sensitive(True) self.menu_button.show() self.menu_button_uninstall.show() self.button_cancel.hide() self.game.set_install_dir() if self.progress_bar: self.progress_bar.destroy() self.menu_button_update.hide() self.update_icon.hide() def __state_uninstalling(self): self.button.set_label(_("uninstalling…")) self.button.get_style_context().remove_class("suggested-action") self.button.set_sensitive(False) self.image.set_sensitive(False) self.menu_button.hide() self.button_cancel.hide() self.game.install_dir = "" self.parent.filter_library() def __state_updatable(self): self.update_icon.show() self.update_icon.set_from_icon_name("emblem-synchronizing", Gtk.IconSize.LARGE_TOOLBAR) self.button.set_label(_("play")) self.menu_button.show() tooltip_text = "{} (update{})".format(self.game.name, ", Wine" if self.game.platform == "windows" else "") self.image.set_tooltip_text(tooltip_text) self.menu_button_update.show() if self.game.platform == "windows": self.wine_icon.set_margin_left(22) def __state_updating(self): self.button.set_label(_("updating…")) STATE_UPDATE_HANDLERS = { state.DOWNLOADABLE: __state_downloadable, state.INSTALLABLE: __state_installable, state.QUEUED: __state_queued, state.DOWNLOADING: __state_downloading, state.INSTALLING: __state_installing, state.INSTALLED: __state_installed, state.UNINSTALLING: __state_uninstalling, state.UPDATABLE: __state_updatable, state.UPDATING: __state_updating, } def update_to_state(self, state): self.current_state = state if state in self.STATE_UPDATE_HANDLERS: self.STATE_UPDATE_HANDLERS[state](self) minigalaxy-1.1.0/minigalaxy/ui/gtk.py000066400000000000000000000001701414231301100175550ustar00rootroot00000000000000import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk, Gio, GLib, GdkPixbuf # noqa: E402,F401 minigalaxy-1.1.0/minigalaxy/ui/library.py000066400000000000000000000137661414231301100204530ustar00rootroot00000000000000import os import re import json import threading from typing import List from minigalaxy.paths import UI_DIR from minigalaxy.api import Api from minigalaxy.config import Config from minigalaxy.game import Game from minigalaxy.ui.gametile import GameTile from minigalaxy.ui.gtk import Gtk, GLib from minigalaxy.translation import _ @Gtk.Template.from_file(os.path.join(UI_DIR, "library.ui")) class Library(Gtk.Viewport): __gtype_name__ = "Library" flowbox = Gtk.Template.Child() def __init__(self, parent, api: Api): Gtk.Viewport.__init__(self) self.parent = parent self.api = api self.show_installed_only = Config.get("installed_filter") self.search_string = "" self.offline = False self.games = [] self.owned_products_ids = [] def reset(self): self.games = [] for child in self.flowbox.get_children(): self.flowbox.remove(child) self.flowbox.show_all() self.update_library() def update_library(self) -> None: library_update_thread = threading.Thread(target=self.__update_library) library_update_thread.daemon = True library_update_thread.start() def __update_library(self): GLib.idle_add(self.__load_tile_states) self.owned_products_ids = self.api.get_owned_products_ids() # Get already installed games first self.games = self.__get_installed_games() GLib.idle_add(self.__create_gametiles) # Get games from the API self.__add_games_from_api() GLib.idle_add(self.__create_gametiles) GLib.idle_add(self.filter_library) def __load_tile_states(self): for child in self.flowbox.get_children(): tile = child.get_children()[0] tile.reload_state() def filter_library(self, widget: Gtk.Widget = None): if isinstance(widget, Gtk.Switch): self.show_installed_only = widget.get_active() elif isinstance(widget, Gtk.SearchEntry): self.search_string = widget.get_text() self.flowbox.set_filter_func(self.__filter_library_func) def __filter_library_func(self, child): tile = child.get_children()[0] if self.search_string.lower() not in str(tile).lower(): return False if self.show_installed_only: if tile.current_state in [tile.state.DOWNLOADABLE, tile.state.INSTALLABLE]: return False if not Config.get("show_hidden_games") and tile.game.get_info("hide_game"): return False return True def sort_library(self): self.flowbox.set_sort_func(self.__sort_library_func) def __sort_library_func(self, child1, child2): tile1 = child1.get_children()[0].game tile2 = child2.get_children()[0].game return tile2 < tile1 def __create_gametiles(self) -> None: games_with_tiles = [] for child in self.flowbox.get_children(): tile = child.get_children()[0] if tile.game in self.games: games_with_tiles.append(tile.game) for game in self.games: if game not in games_with_tiles: self.__add_gametile(game) def __add_gametile(self, game): self.flowbox.add(GameTile(self, game)) self.sort_library() self.flowbox.show_all() def __get_installed_games(self) -> List[Game]: # Make sure the install directory exists library_dir = Config.get("install_dir") if not os.path.exists(library_dir): os.makedirs(library_dir, mode=0o755) directories = os.listdir(library_dir) games = [] for directory in directories: full_path = os.path.join(Config.get("install_dir"), directory) # Only scan directories if not os.path.isdir(full_path): continue # Make sure the gameinfo file exists gameinfo = os.path.join(full_path, "gameinfo") if os.path.isfile(gameinfo): with open(gameinfo, 'r') as file: name = file.readline().strip() version = file.readline().strip() # noqa: F841 version_dev = file.readline().strip() # noqa: F841 language = file.readline().strip() # noqa: F841 game_id = file.readline().strip() if not game_id: game_id = 0 else: game_id = int(game_id) games.append(Game(name=name, game_id=game_id, install_dir=full_path)) else: game_files = os.listdir(full_path) for file in game_files: if re.match(r'^goggame-[0-9]*\.info$', file): with open(os.path.join(full_path, file), 'r') as info_file: info = json.loads(info_file.read()) game = Game( name=info["name"], game_id=int(info["gameId"]), install_dir=full_path, platform="windows" ) games.append(game) return games def __add_games_from_api(self): retrieved_games, err_msg = self.api.get_library() if not err_msg: self.offline = False else: self.offline = True GLib.idle_add(self.parent.show_error, _("Failed to retrieve library"), _(err_msg)) for game in retrieved_games: if game not in self.games: self.games.append(game) elif self.games[self.games.index(game)].id == 0 or self.games[self.games.index(game)].name != game.name: self.games[self.games.index(game)].id = game.id self.games[self.games.index(game)].name = game.name self.games[self.games.index(game)].image_url = game.image_url self.games[self.games.index(game)].url = game.url minigalaxy-1.1.0/minigalaxy/ui/login.py000066400000000000000000000031541414231301100201050ustar00rootroot00000000000000import os from urllib.parse import urlparse, parse_qsl from minigalaxy.translation import _ from minigalaxy.paths import UI_DIR from minigalaxy.ui.gtk import Gtk from minigalaxy.ui.webkit import WebKit2 @Gtk.Template.from_file(os.path.join(UI_DIR, "login.ui")) class Login(Gtk.Dialog): __gtype_name__ = "Login" box = Gtk.Template.Child() redirect_url = None result = None def __init__(self, login_url=None, redirect_url=None, parent=None): Gtk.Dialog.__init__(self, title=_("Login"), parent=parent, flags=0, buttons=()) self.redirect_url = redirect_url context = WebKit2.WebContext.new() webview = WebKit2.WebView.new_with_context(context) webview.load_uri(login_url) webview.connect('load-changed', self.on_navigation) self.box.pack_start(webview, True, True, 0) self.show_all() # Check if the login has completed when the page is changed. Set the result to the code value found within the url def on_navigation(self, widget, load_event): if load_event == WebKit2.LoadEvent.FINISHED: uri = widget.get_uri() if uri.startswith(self.redirect_url): self.result = self.__get_code_from_url(uri) self.hide() # Return the code when can be used by the API to authenticate def get_result(self): return self.result # Get the code from the url returned by GOG when logging in has succeeded def __get_code_from_url(self, url: str): parsed_url = urlparse(url) input_params = dict(parse_qsl(parsed_url.query)) return input_params.get('code') minigalaxy-1.1.0/minigalaxy/ui/preferences.py000066400000000000000000000173331414231301100213020ustar00rootroot00000000000000import os import locale import shutil from minigalaxy.translation import _ from minigalaxy.paths import UI_DIR from minigalaxy.constants import SUPPORTED_DOWNLOAD_LANGUAGES, SUPPORTED_LOCALES from minigalaxy.config import Config from minigalaxy.download_manager import DownloadManager from minigalaxy.ui.gtk import Gtk @Gtk.Template.from_file(os.path.join(UI_DIR, "preferences.ui")) class Preferences(Gtk.Dialog): __gtype_name__ = "Preferences" combobox_program_language = Gtk.Template.Child() combobox_language = Gtk.Template.Child() button_file_chooser = Gtk.Template.Child() label_keep_installers = Gtk.Template.Child() switch_keep_installers = Gtk.Template.Child() switch_stay_logged_in = Gtk.Template.Child() switch_show_hidden_games = Gtk.Template.Child() switch_show_windows_games = Gtk.Template.Child() switch_create_applications_file = Gtk.Template.Child() switch_use_dark_theme = Gtk.Template.Child() button_cancel = Gtk.Template.Child() button_save = Gtk.Template.Child() def __init__(self, parent): Gtk.Dialog.__init__(self, title=_("Preferences"), parent=parent, modal=True) self.parent = parent self.__set_locale_list() self.__set_language_list() self.button_file_chooser.set_filename(Config.get("install_dir")) self.switch_keep_installers.set_active(Config.get("keep_installers")) self.switch_stay_logged_in.set_active(Config.get("stay_logged_in")) self.switch_use_dark_theme.set_active(Config.get("use_dark_theme")) self.switch_show_hidden_games.set_active(Config.get("show_hidden_games")) self.switch_show_windows_games.set_active(Config.get("show_windows_games")) self.switch_create_applications_file.set_active(Config.get("create_applications_file")) # Set tooltip for keep installers label installer_dir = os.path.join(self.button_file_chooser.get_filename(), "installer") self.label_keep_installers.set_tooltip_text( _("Keep installers after downloading a game.\nInstallers are stored in: {}").format(installer_dir) ) def __set_locale_list(self) -> None: locales = Gtk.ListStore(str, str) for local in SUPPORTED_LOCALES: locales.append(local) self.combobox_program_language.set_model(locales) self.combobox_program_language.set_entry_text_column(1) self.renderer_text = Gtk.CellRendererText() self.combobox_program_language.pack_start(self.renderer_text, False) self.combobox_program_language.add_attribute(self.renderer_text, "text", 1) # Set the active option current_locale = Config.get("locale") default_locale = locale.getdefaultlocale() if current_locale is None: locale.setlocale(locale.LC_ALL, default_locale) for key in range(len(locales)): if locales[key][:1][0] == current_locale: self.combobox_program_language.set_active(key) break def __set_language_list(self) -> None: languages = Gtk.ListStore(str, str) for lang in SUPPORTED_DOWNLOAD_LANGUAGES: languages.append(lang) self.combobox_language.set_model(languages) self.combobox_language.set_entry_text_column(1) self.renderer_text = Gtk.CellRendererText() self.combobox_language.pack_start(self.renderer_text, False) self.combobox_language.add_attribute(self.renderer_text, "text", 1) # Set the active option current_lang = Config.get("lang") for key in range(len(languages)): if languages[key][:1][0] == current_lang: self.combobox_language.set_active(key) break def __save_locale_choice(self) -> None: new_locale = self.combobox_program_language.get_active_iter() if new_locale is not None: model = self.combobox_program_language.get_model() locale_choice = model[new_locale][-2] if locale_choice == '': default_locale = locale.getdefaultlocale()[0] locale.setlocale(locale.LC_ALL, (default_locale, 'UTF-8')) Config.set("locale", locale_choice) else: try: locale.setlocale(locale.LC_ALL, (locale_choice, 'UTF-8')) Config.set("locale", locale_choice) except locale.Error: self.parent.show_error(_("Failed to change program language. Make sure locale is generated on " "your system.")) def __save_language_choice(self) -> None: lang_choice = self.combobox_language.get_active_iter() if lang_choice is not None: model = self.combobox_language.get_model() lang, _ = model[lang_choice][:2] Config.set("lang", lang) def __save_theme_choice(self) -> None: settings = Gtk.Settings.get_default() Config.set("use_dark_theme", self.switch_use_dark_theme.get_active()) if Config.get("use_dark_theme") is True: settings.set_property("gtk-application-prefer-dark-theme", True) else: settings.set_property("gtk-application-prefer-dark-theme", False) def __save_install_dir_choice(self) -> bool: choice = self.button_file_chooser.get_filename() old_dir = Config.get("install_dir") if choice == old_dir: return True if not os.path.exists(choice): try: os.makedirs(choice, mode=0o755) except Exception: return False else: write_test_file = os.path.join(choice, "write_test.txt") try: with open(write_test_file, "w") as file: file.write("test") file.close() os.remove(write_test_file) except Exception: return False # Remove the old directory if it is empty try: os.rmdir(old_dir) except OSError: pass Config.set("install_dir", choice) return True @Gtk.Template.Callback("on_button_save_clicked") def save_pressed(self, button): self.__save_locale_choice() self.__save_language_choice() self.__save_theme_choice() Config.set("keep_installers", self.switch_keep_installers.get_active()) Config.set("stay_logged_in", self.switch_stay_logged_in.get_active()) Config.set("show_hidden_games", self.switch_show_hidden_games.get_active()) Config.set("create_applications_file", self.switch_create_applications_file.get_active()) self.parent.library.filter_library() if self.switch_show_windows_games.get_active() != Config.get("show_windows_games"): if self.switch_show_windows_games.get_active() and not shutil.which("wine"): self.parent.show_error(_("Wine wasn't found. Showing Windows games cannot be enabled.")) Config.set("show_windows_games", False) else: Config.set("show_windows_games", self.switch_show_windows_games.get_active()) self.parent.reset_library() # Only change the install_dir is it was actually changed if self.button_file_chooser.get_filename() != Config.get("install_dir"): if self.__save_install_dir_choice(): DownloadManager.cancel_all_downloads() self.parent.reset_library() else: self.parent.show_error(_("{} isn't a usable path").format(self.button_file_chooser.get_filename())) self.destroy() @Gtk.Template.Callback("on_button_cancel_clicked") def cancel_pressed(self, button): self.response(Gtk.ResponseType.CANCEL) self.destroy() minigalaxy-1.1.0/minigalaxy/ui/properties.py000066400000000000000000000150331414231301100211700ustar00rootroot00000000000000import urllib import os import subprocess import webbrowser from minigalaxy.paths import UI_DIR, THUMBNAIL_DIR from minigalaxy.translation import _ from minigalaxy.launcher import config_game, regedit_game from minigalaxy.config import Config from minigalaxy.ui.gtk import Gtk, GLib, Gio, GdkPixbuf @Gtk.Template.from_file(os.path.join(UI_DIR, "properties.ui")) class Properties(Gtk.Dialog): __gtype_name__ = "Properties" gogBaseUrl = "https://www.gog.com" image = Gtk.Template.Child() button_properties_cancel = Gtk.Template.Child() button_properties_ok = Gtk.Template.Child() button_properties_support = Gtk.Template.Child() button_properties_store = Gtk.Template.Child() button_properties_open_files = Gtk.Template.Child() button_properties_winecfg = Gtk.Template.Child() button_properties_regedit = Gtk.Template.Child() switch_properties_show_fps = Gtk.Template.Child() switch_properties_hide_game = Gtk.Template.Child() entry_properties_variable = Gtk.Template.Child() entry_properties_command = Gtk.Template.Child() label_game_description = Gtk.Template.Child() def __init__(self, parent, game, api): Gtk.Dialog.__init__(self, title=_("Properties of {}").format(game.name), parent=parent.parent.parent, modal=True) self.parent = parent self.game = game self.api = api self.gamesdb_info = self.api.get_gamesdb_info(self.game) # Show the image self.load_thumbnail() self.load_description() # Disable/Enable buttons self.button_sensitive(game) # Retrieve variable & command each time Properties is open self.entry_properties_variable.set_text(self.game.get_info("variable")) self.entry_properties_command.set_text(self.game.get_info("command")) # Keep switch FPS disabled/enabled self.switch_properties_show_fps.set_active(self.game.get_info("show_fps")) # Keep switch game shown/hidden self.switch_properties_hide_game.set_active(self.game.get_info("hide_game")) # Center properties window self.set_position(Gtk.WindowPosition.CENTER_ALWAYS) @Gtk.Template.Callback("on_button_properties_cancel_clicked") def cancel_pressed(self, button): self.destroy() @Gtk.Template.Callback("on_button_properties_ok_clicked") def ok_pressed(self, button): if self.game.is_installed(): self.game.set_info("variable", str(self.entry_properties_variable.get_text())) self.game.set_info("command", str(self.entry_properties_command.get_text())) self.game.set_info("show_fps", self.switch_properties_show_fps.get_active()) self.game.set_info("hide_game", self.switch_properties_hide_game.get_active()) self.parent.parent.filter_library() self.destroy() @Gtk.Template.Callback("on_button_properties_winecfg_clicked") def on_menu_button_winecfg(self, widget): config_game(self.game) @Gtk.Template.Callback("on_button_properties_regedit_clicked") def on_menu_button_regedit(self, widget): regedit_game(self.game) @Gtk.Template.Callback("on_button_properties_open_files_clicked") def on_menu_button_open_files(self, widget): self.game.set_install_dir() subprocess.call(["xdg-open", self.game.install_dir]) @Gtk.Template.Callback("on_button_properties_support_clicked") def on_menu_button_support(self, widget): try: webbrowser.open(self.api.get_info(self.game)['links']['support'], new=2) except webbrowser.Error: self.parent.parent.show_error( _("Couldn't open support page"), _("Please check your internet connection") ) @Gtk.Template.Callback("on_button_properties_store_clicked") def on_menu_button_store(self, widget): try: webbrowser.open(self.gogBaseUrl + self.game.url) except webbrowser.Error: self.parent.parent.show_error( _("Couldn't open store page"), _("Please check your internet connection") ) def load_thumbnail(self): if self.gamesdb_info["cover"]: response = urllib.request.urlopen(self.gamesdb_info["cover"]) input_stream = Gio.MemoryInputStream.new_from_data(response.read(), None) pixbuf = GdkPixbuf.Pixbuf.new_from_stream(input_stream, None) pixbuf = pixbuf.scale_simple(340, 480, GdkPixbuf.InterpType.BILINEAR) GLib.idle_add(self.image.set_from_pixbuf, pixbuf) else: thumbnail_path = os.path.join(THUMBNAIL_DIR, "{}.jpg".format(self.game.id)) if not os.path.isfile(thumbnail_path) and self.game.is_installed: thumbnail_path = os.path.join(self.game.install_dir, "thumbnail.jpg") GLib.idle_add(self.image.set_from_file, thumbnail_path) def load_description(self): description = "" lang = Config.get("lang") if self.gamesdb_info["summary"]: desc_lang = "*" for summary_key in self.gamesdb_info["summary"].keys(): if lang in summary_key: desc_lang = summary_key description_len = 470 if len(self.gamesdb_info["summary"][desc_lang]) > description_len: description = "{}...".format(self.gamesdb_info["summary"][desc_lang][:description_len]) else: description = self.gamesdb_info["summary"][desc_lang] genre_lang = "*" for genre_key in self.gamesdb_info["genre"].keys(): if lang in genre_key: genre_lang = genre_key description = "{}: {}\n{}".format(_("Genre"), self.gamesdb_info["genre"][genre_lang], description) if self.game.is_installed(): description = "{}: {}\n{}".format(_("Version"), self.game.get_info("version"), description) GLib.idle_add(self.label_game_description.set_text, description) def button_sensitive(self, game): if not game.is_installed(): self.button_properties_open_files.set_sensitive(False) self.button_properties_winecfg.set_sensitive(False) self.entry_properties_command.set_sensitive(False) self.entry_properties_variable.set_sensitive(False) self.button_properties_regedit.set_sensitive(False) self.switch_properties_show_fps.set_sensitive(False) if game.platform == 'linux': self.button_properties_winecfg.hide() self.button_properties_regedit.hide() minigalaxy-1.1.0/minigalaxy/ui/webkit.py000066400000000000000000000001451414231301100202570ustar00rootroot00000000000000import gi gi.require_version('WebKit2', '4.0') from gi.repository import WebKit2 # noqa: E402,F401 minigalaxy-1.1.0/minigalaxy/ui/window.py000066400000000000000000000147741414231301100203160ustar00rootroot00000000000000import os import locale from minigalaxy.ui.login import Login from minigalaxy.ui.preferences import Preferences from minigalaxy.ui.about import About from minigalaxy.api import Api from minigalaxy.config import Config from minigalaxy.paths import UI_DIR, LOGO_IMAGE_PATH, THUMBNAIL_DIR from minigalaxy.translation import _ from minigalaxy.ui.library import Library from minigalaxy.ui.gtk import Gtk, Gdk, GdkPixbuf @Gtk.Template.from_file(os.path.join(UI_DIR, "application.ui")) class Window(Gtk.ApplicationWindow): __gtype_name__ = "Window" HeaderBar = Gtk.Template.Child() header_sync = Gtk.Template.Child() header_installed = Gtk.Template.Child() header_search = Gtk.Template.Child() menu_about = Gtk.Template.Child() menu_preferences = Gtk.Template.Child() menu_logout = Gtk.Template.Child() window_library = Gtk.Template.Child() def __init__(self, name="Minigalaxy"): current_locale = Config.get("locale") default_locale = locale.getdefaultlocale()[0] if current_locale == '': locale.setlocale(locale.LC_ALL, (default_locale, 'UTF-8')) else: try: locale.setlocale(locale.LC_ALL, (current_locale, 'UTF-8')) except NameError: locale.setlocale(locale.LC_ALL, (default_locale, 'UTF-8')) Gtk.ApplicationWindow.__init__(self, title=name) self.api = Api() self.search_string = "" self.offline = False # Set library self.library = Library(self, self.api) self.window_library.add(self.library) self.header_installed.set_active(Config.get("installed_filter")) # Set the icon icon = GdkPixbuf.Pixbuf.new_from_file(LOGO_IMAGE_PATH) self.set_default_icon_list([icon]) # Set theme settings = Gtk.Settings.get_default() if Config.get("use_dark_theme") is True: settings.set_property("gtk-application-prefer-dark-theme", True) else: settings.set_property("gtk-application-prefer-dark-theme", False) # Show the window if Config.get("keep_window_maximized"): self.maximize() self.show_all() # Create the thumbnails directory if not os.path.exists(THUMBNAIL_DIR): os.makedirs(THUMBNAIL_DIR, mode=0o755) # Interact with the API self.offline = not self.api.can_connect() if not self.offline: try: self.__authenticate() self.HeaderBar.set_subtitle(self.api.get_user_info()) except Exception as e: print(e) self.offline = True self.sync_library() @Gtk.Template.Callback("filter_library") def filter_library(self, switch, _=""): self.library.filter_library(switch) if switch == self.header_installed: Config.set("installed_filter", switch.get_active()) @Gtk.Template.Callback("on_menu_preferences_clicked") def show_preferences(self, button): preferences_window = Preferences(self) preferences_window.run() preferences_window.destroy() @Gtk.Template.Callback("on_menu_about_clicked") def show_about(self, button): about_window = About(self) about_window.run() about_window.destroy() @Gtk.Template.Callback("on_menu_logout_clicked") def logout(self, button): question = _("Are you sure you want to log out of GOG?") if self.show_question(question): # Unset everything which is specific to this user self.HeaderBar.set_subtitle("") Config.unset("username") Config.unset("refresh_token") self.hide() # Show the login screen self.__authenticate() self.HeaderBar.set_subtitle(self.api.get_user_info()) self.sync_library() self.show_all() @Gtk.Template.Callback("on_window_state_event") def on_window_state_event(self, widget, event): if event.new_window_state & Gdk.WindowState.MAXIMIZED: Config.set("keep_window_maximized", True) else: Config.set("keep_window_maximized", False) @Gtk.Template.Callback("on_header_sync_clicked") def sync_library(self, _=""): if self.library.offline: self.__authenticate() self.library.update_library() def reset_library(self): self.library.reset() def update_library(self): self.library.update_library() def show_error(self, text, secondary_text=""): dialog = Gtk.MessageDialog( parent=self, modal=True, destroy_with_parent=True, message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK, text=text ) if secondary_text: dialog.format_secondary_text(secondary_text) dialog.run() dialog.destroy() def show_question(self, text, secondary_text=""): dialog = Gtk.MessageDialog( parent=self, flags=Gtk.DialogFlags.MODAL, message_type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK_CANCEL, message_format=text ) if secondary_text: dialog.format_secondary_text(secondary_text) response = dialog.run() dialog.destroy() return response == Gtk.ResponseType.OK """ The API remembers the authentication token and uses it The token is not valid for a long time """ def __authenticate(self): url = None if Config.get("stay_logged_in"): token = Config.get("refresh_token") else: Config.unset("username") Config.unset("refresh_token") token = None # Make sure there is an internet connection if not self.api.can_connect(): return authenticated = self.api.authenticate(refresh_token=token, login_code=url) while not authenticated: login_url = self.api.get_login_url() redirect_url = self.api.get_redirect_url() login = Login(login_url=login_url, redirect_url=redirect_url, parent=self) response = login.run() login.hide() if response == Gtk.ResponseType.DELETE_EVENT: Gtk.main_quit() exit(0) if response == Gtk.ResponseType.NONE: result = login.get_result() authenticated = self.api.authenticate(login_code=result) Config.set("refresh_token", authenticated) minigalaxy-1.1.0/minigalaxy/version.py000066400000000000000000000000221414231301100200340ustar00rootroot00000000000000VERSION = "1.1.0" minigalaxy-1.1.0/requirements-testing.txt000066400000000000000000000000331414231301100205740ustar00rootroot00000000000000requests flake8 simplejson minigalaxy-1.1.0/requirements.txt000066400000000000000000000000221414231301100171170ustar00rootroot00000000000000requests PyGObjectminigalaxy-1.1.0/screenshot.jpg000066400000000000000000010654621414231301100165360ustar00rootroot00000000000000JFIFC  !"$"$COx" k  !1AQ"#aq2TU5BRs$3br%4Stu &7CDVde'6EFc8(fvC !1AQSaq"2#BRr34b$C5D ?ї EoW2 tHDHSiJKk `Sm)#!N{APYZ(>'=Tuw9Tj oBJJm`%H#"C5>G* %V(⸺ h>wfĉ R H֯rQ44K!?!z3FJ?d<&OY7 T<8CS~^wO'^',2}6Uϑ>J>S OzhBw2}',|њxL|;Gÿ44f'',2}7 DŽÿ4xL|;MFhBq2}',|њxL|;Gÿ44f'',2}7 DŽÿ4xL|;MFhBq2}',|њxL|;Gÿ44f'',2}7 DŽÿ4xL|;MFhBq2}',|њxL|;Gÿ44f'',2}7 DŽÿ4xL|;MFhBq2}',|њxL|;Gÿ44f'',2}7 DŽÿ4xL|;MFhBq2}',|њxL|;Gÿ44f'',2}7 DŽÿ4xL|;MFhBq2}',|њxL|;Gÿ44f'',2}7 DŽÿ4xL|;MFhBq2}',|њxL|;Gÿ44f'',2}7 DŽÿ4xL|;MFhBq2}',|њxL|;Gÿ44f'',2}7 DŽÿ4xL|;MXGH|].*bawf k!qM/ƇNjJ/ ΕVwf k&wf ihN<&OYdo3B h>wfЄd<&OY4!8>wf ihN<&OYdo3B h>wfЄd<&OY4!8>wf ihN<&OYdo3B h>wfЄd<&OY4!8>wf ihN<&OYdo3B h>wfЄd<&OY4!8>wf ihN<&OYdo3BȖRے\#FW'=U5}B(: U.'=Tuw9mYr\??$窎'=Um"\??$窎'=Um"\??$窎'=Um"\??$窎'=Um"\??$窎'=Um"\??$窎'=Um"\??$窎'=Um"\??$窎'=Um"ꢧe1+HM|wf!.6֐ABZ`k[|FjA&55'8Ԅ-Cs~IUM HB@ HWU!Aw9꠽pd窧5Qd(}Id:A',sp.A?qu8>wf ihN<&OYdo3B h>wfЄd<&OY4!8>wf ihN<&OYdo3B h>wfЅG鳣;I+*Tm aWvR*(嗄dVA¬:+'+1w\laCcs$պ:+|n6<- g."*:&A"#IQ*8v.U7egn80]B9 q OHpZ" Pys[`gLls5`U_R $u,oRz³:N;5T*C-@Ω=TF5YnZr;$l3`YrzI$] j2ՆT~!{I'%$>BKW$;G3#좀, Nv3ޛP;>'(?C[ן:5pRqnm<[WAmqEB\6AA2T@+vqC|E1B%ɜJN0$ c$;ÓnPn}Җւi՝Yiݶ[nͳ&%nDQZaIБ^(oFH/'ű,AmqKJJΐRX$fܮ~g:Tuen6wJp[}%Ǹ{iP#ݜ-ednqsp^vi]bUխzxXXcIs%6J9L ~ȣº}^z{j՜ooHqg[T3kE,%OLkmwl)u*za.uڟz![S*ZPX IQ'*#'d\%1fλ.B* }Hk!X'r3̍w5vϞhquzϞh^>z3BϞЅ>z394!zϞh^>z3BϞЅ>z394!zϞh^>z3BϞЅ>z394!zϞh^>z3BϞЅ>z394!zϞh^>z3BϞЅ>z394!zϞh^>z3BϞЅ>z394!zϞh^>z3BϞЅ>z394!zϞh^>z3Bꎎb_ nЂR[BU4D<'EeIN/l^DqĎC_};{V63Nnqek-xV ,Cd;!(paSsNEc "*)H#9p ܮX,γk0j1qKd#U{ ;įO0b-ᦞuJv}[,[Jzp 4ĀJ*ƠYC)ٕ AK}i/F,~FKq4[_Hn [ >4X)R1Ù;[E3N]Z£5?cPJkNEyJ H:.YLbJ#l2˃Rx}2 `Ps݃E,*˟*dqy *ܤ%$J5GR,` ~Ɨ+wR}JOyѿUƽZ߷8N.$S3NS2"| Ʊ<#] |g^sFk|g^sFhB=לњgF|4f/Yџ=y |g^sFhB=לњgF|4f/Yџ=y |g^sFhB=לњgF|4f/Yџ=y |g^sFhB=לњgF|4f/Yџ=y |g^sFhB=לњgF|4f+O }kUQxq/J MȫkiKfke!/=cTє"|xIXĕ9t \' ;o[ܐ̎#I[IS̅k#N=(]EQBEPQE!QEEQBEPQE!c⿪*<~/.RjfN6(O_}=_ӟ_mU\kO|cVkjggNvF8W.zиVmw&Vx\L]j~ᥟqƯ>v㚢]/uMܤDD+nxm]uPP$d٧''Q^3PR^>z |Cnnݤ!]iCIVe>6q`wP3=[855(۱[EsNH:t' q'zϞhT([W:xbړ=+-# Ž0R7lj?c!ţ>nR`I.c~bsV/Dqs"KDC !E*5 oL8O_@n0ݧFz395>zuY8mŎ9YA\t\՜F؜U5 5mcv˺x_C2XNpۛPI n1@AUxw\fm1i%$$`^훃Vn$}0e_AW.u`l2'lՃ5e}|W\]I)ZVۘ΅XԲn$ )~&Ux}T+;Y>>s¡JQP%zċ+ v% % Է֥$A*Wb|aT]K8KSNܭ'zY7kTG?6~&U5zE3x=2JZ}(Of_&}t~&U5zwֿm V]粛x|o_~&UBw3M<>7/jQ W;5z߄ɫEНOKTx|o_NFi%M^<>7/jQt'y4~&U5zњi WKT] h4߄ɫG%M^.4fx|o_~&UBw3M<>7/jQ W;5z߄ɫEНOKTx|o_NFi%M^<>7/jQt'y4~&U5zњi WKT] h4߄ɫG%M^.4fx|o_~&UBw3M<>7/jQ W;5z߄ɫEНOKTx|o_NFi%M^<>7/jQt'y4~&U5zњi WKT] h4߄ɫG%M^.4fx|o_~&UBw3M<>7/jQ W;5z߄ɫEНOKTx|o_NFi%M^<>7/jQt'y4~&U5zњi WKT] h4߄ɫG%M^.4fx|o_~&UBw3M<>7/jQ W;5z߄ɫEНOKTx|o_NQM˜`gVu.Szu WKT]r-D mnDkbmϿ:)3d0HRz:vamfފ߄ɫG%M^eL.ALšY$M=c'8vHC`҈WwxF>7/jQ W=\}m..ڤ<sKiKΡM@?-- WKT]NFi%M^<>7/jW.OKTx|o_NFi%M^<>7/jQt'y4~&U5zњi WKT] h4߄ɫG%M^.4fx|o_~&UBw3M<>7/jQ W;5z߄ɫEНOKTx|o_NFi%M^<>7/jQt'y4~&U5zњi WKT] h4߄ɫG%M^.4fx|o_~&UBw3M<>7/jQ W;5z߄ɫEНOKTx|o_NFi%M^<>7/jQt'y4~&U5zn*Brⴂ ؟MH! ~&U5zA8U읷Ov߄"~Y>x|o_~&U_~~d'mB'%M^<>7/jQU읷Ov߄"~Y>x|o_~&U_~~d'mB'%M^<>7/jQU읷Ov߄"~Y>x|o_~&U_~~d'mB'%M^<>7/jQU읷Ov߄"~Y>x|o_~&U_~~d'mB'%M^<>7/jQU읷Ov߄"~Y>x|o_~&U^[eKL]P!U)$'Ni/KTx|o_u,ZZT[WjV^tˈO5~I^P%zċ+;Y> ߏMW<*z$U}}TbEK}в r1_sL`)W|o_]u;5z߄ɫEНOKTx|o_NFi%M^<>7/jQt'y4~&U5zњi WKT] h4߄ɫG%M^.4fx|o_~&UBw)%M^(.'QkWܸGsS ((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(("((B(]~JTE\įM.q?ZJ?TS\\O#X65!xy$Z !#ՐdOK#$fi?ޭ~T:YadtH{ fc90ldGL%XOwd_ti]B.mN ?z: 8燚m#sO5OW[T)\ ERɴW&{ :`]l\CԳQקTv֯h*9RY *?[p;8\RtC #t]g# :WOQo.Be px te)Fsǣtxk $Qr'Dm~KWYZFފto~1{Ttc8[$glTd-{Ԑ ^E7oT*)Jظ;q^:/Oln"tRZt׀s5]O.GMFͦ il4ܔ:7xK}1N3ϑ7V tEҊ2|Je%J\0sx'z;`1 ў Jn#%XP IkIyVB]C (Fq:8j$l9oKdVz{kQ=YWu綾ǐPoΖ_:/О:YWuo}ҟA@'5'It_SJߊ̓Qy<<Q+MGN*|St:sH)G͛y XIxk9 N9WI#R0@ sU?5HsWJ'FRURbKPs&m 5coK:>eiΓxopK7NԷC(Dy1)}d;bE{Zn&*8C:ZWOM'#}]^:;M|2:e ҀFcX3N)'K9 d?ZU>=$=eAc\ (h(O:YHW+MHɊU:%#%;2wJ!!!wg㍻R:Q~l8)88"JvBG%;=꧖cVϡ Xr;_K]"&+opoM=$`Iy>m7Q.--nRwUgT jHүgѲm`Zmߦ.Z8FնF7[GN}.Ip'8;~'=^**嵦șd+ޡ%^4!H Q@)W=KT8.>ܝ-4zw":3E*}Nn 'd(Qy$lP3_uVY].xd|n7Q^g3nlXQ"q -7+F\u}gN."a;uJ>a鿤D&.nܛb9P{IjPFI9}@ `+M]%EYM*P1wbDİg9:6:`;M0z d~j^ خrf%F+zVntH0eEGtb 楇L]-sjcBJնg*U?a5+%JZOdhu4d\.5.m% )_WdKn<-! }ΊPav8J̑in֖ƣ(gV/f'?#dO pO&(!̅LEaXG[v+Y.J$ٸjR=`"DqNt-$iBg]Y81ړan}#f+$'6ޮ|SzAo$QW# 'l%)9d@w,u=e'.Vg q Xf3r~jn=0,q񎔛tB1꩟.m 4-.[[ $MWTߍXq,rq6+86JRӟLuNBq:/T*10U_$0i U㴅%t;w3G?h(_hDtͤaVd_L9Ց># V޼Î('FNG-{$cc_bOJ=$\-o#5G#O$٢y]]*8i_HTaHN{*7n8 Zx-J6TƤ`TZq[:ʗd'𓝒}s6;[h[Um9,JsuV9IW=sɶd\w٪Чtڛ}ʢ{}byMG'|m:yTV|oxQ; ĸ)Ƣ9!9&/D\)֕ZnAX$(\Hۥ3ϊ;:tx~uj .)[t8Tii) ǽ?#9)۳ >ԕ+O"&8MDwF!Qkx:x#^dt A=VV$-O! (R4rrioϚMvE@鏍8SyXB1dZ*I`}#?YmVyԲJ$ ]ySt97IIC<jnŔ-E$HrBe$b3ԤIj++O=kPChPuZ?JsuߥU u* IlY'>.STL1H]+EON,-ZQDnh?Q J+9IT "u-FyJvWVR{Swdޥ B~K]88HFpl# v #AzSe@18O$XBkʞuN6M}}lP mCR1i;dc$nb&z]%@Kq`~˙dvfƫW [e[JRugWSq#\'mK ,)DD*ZVFGlhuLa #dیem.ʁ;ttq@#/s-(>2k*Gj\*l64јLsZۥjdl$oN\Iw8ޓMpR%n) ՝9*]7V%Tƪ_nv- CDiNACg)PHpAv+ђ Q HRTq>-,F%<HeP38 POSR<,įܕ%y9Q]\!т:C%#*ՂIO>]KW1 QEgQ\-Nzy=ezt0?WhT?pR; Q]A+𝿣H+[uV@qw_Z*sR[Iƀ_c>[S Y 8$% VǛ^>X6i_#柎L6;ra]ZIC B$nI){jr.SUds< qnl&&WS9Q\mM)E.(2)$AW*W#ӆ')Dܷ[!isd(d)93qm˼JuH>nlsl@Q#5T`k.n"B=R;n{,0VǗl]TZ1[L9pBy*1峦2qԡ:jH)A<"INd[:J C!9=q4GXLZQ;;pbn= ;_w~N^nn?xuP;RWʟ7t"8 KY,Z} Մ(Gig<)=zbmk%ix-kP(.ٚђh0`2qJfRAH;>u  XOn yLlqN)եEH QH T7n7\t4Pa#;)%]9_~8]\g0]'Bp#fT+.CdQEJ+`M8VFBx?|Ztupn=[tMo_v)6("+4T5y;d<)VNN9IACm.GߣVG͊pEpi^sqIX%^|jNA]fY-ȏ&2!)Ia!S>2{\)*ΠJ75g)ZFo^pUۙ$!) s#5+7%/ J>WpLڗ1͎>QPiUϜ E bJ S 2ˠc|m+O1HRHd1ԷX9v.ף4UƓۣ^frڴid<;tS./PڭVRH5r" UGJ0VǧE(Blv';BCڽ%rpӏ)m77@A}('eJF <%ke϶ʖp PoUCZ_ |F~6[qG;orS.8iI JBR; ţCRR@=ܫx<@1uD+* ']EZܧacpYUc!bD˂F)Oy4FP#qwJ+] uiR6VTTxNk%$_%vq4/ZI#k~ܣKݪE2RH H6&\ncׂJ!9.y8Dq. + w}1SȐ|wO~:{7iCcC>5dbΑhuEIRR@' ૴c8wKs)$|Ki5vuʁMkŤ0=YmZIR5|U{PBq8ϼNCGkQE2 *Noqế}QGCwc`UOvw H-(XH*V$$VD9U&IJ;l%VTRĖ0×3t U-W)M<F3M"%k` jRBԝ Pr+KI&ZNڪx՞b!Lẍɵٙ ցܕשn5XI#% c;ޢ晅le;1kڻ .ܔ(\#I$.N e@7ޭJK.W{wQE(.vh[G Brpuc>)+%g|]!OY#Y׌j:co=s R5Ҧ6`P $oJʂB4hgsyhue(= dƗ4{#RQI(qX>~_.+Zh˳dm811sG ?ȵ0.3ڝ n2!C#CN7iNY,70\_ĦDRp-dvU7,Z_t-6 JM( {3)t=6Jc %8r{纜 9$6P>3w:DD+;=S />#j r58 WeUstA* b28!`d3j-R$(1T{Զ< IviqO:GQe1 A)PI8Rq!\T 54ӸDDoQSHR )n[ h i896oj- RȦu0Z-2ΟOi2|<4VI<<@2Km=/cΨEl!)ZH߿JЅtpeAqtp}NDS\^ܫVX$݄ = AI4aI+K2nVZIV#t=9^$Lq8U)(v(""(._W.r%hu}ˉ~4.'QԂg5tiXY"tw[ϳ]/Z |Ea47vV0!vu ntN **ڴrp)>ƩK$ S\ZA̍XsL|gdI)ʟuj҄'I'Xpwٙv֛yΒBk)-#,}zN ׍naǃoLb8pa,.T,|bqU"8./O#fⲩj"*@$\mIԕ$c*z)2BuA(s*^FRA|Um17I7{aXJA/!CZ|`"Z-zx-l+➣ZJ>gK#rhI 7, I IL Au4%@Z͗%\F[VcXVJOh iH{la\V)($@:+[U>@04hî!8mRITART)DS8 9wC;|.us )8eݠBGS- !*qds1HTX5M6U +Zz 7[Tu!dj}iwXr\&{cͥH- ?޶d0(r+X':;7Y1I n VHqRt*t'||y`ӑۜշixū3jRtg4TuOk7c@h (mX;Y^R8"(+,d%`*.~jvqq7ӷ)  j/%[ ]8ף+^!8QKyNx:ywWj_-EZRGo@XVݔ;UBr)9R >ө(mVRwAf~79.]x7#2ʂuc^/I7(?IQ3nB־,j^EE>\(& ^*V+<_ Gi,'J} Kx=[`ݢGZqIJ_xszS2tE{㪊g^RdGU* Xl7Fʦ-}VˣĵXNКp5m>KmK Hr@;QW-j,Q?(;jE7&Xyt3 aA%ZJsD p֭M 2#[ylEIpopN *Pp 3X(XԬ|YY>K`~4Ә(Bő򴶕BN S5SvJ>Aw;Vat^OKDlnO5 BV5~Zpm5ԯ$q*Qco㨏2jWř(d+4@eZKT9_߸]kEWQEPT=*񅹇EbR1%dK"=[`%Cާ8z5q<¯8/".MNhjIT^9`_65Α _[*t폾Hd([z.hVpA/5SOxK;Ve)O-Ax| -Vx ؋N[+gHZRH::J0Ղ:4t7AtkrZ }0)(IFjHQa,!ÍJAH\DE×a3@KH؀!>b{PmɊY #q֧]ӭa!O "D0h׏)e:>s?`ppnn+ppd ԊeSLnjOd6ع}N !ȍFet4 o얈ӚclGJ^a8! 8%%[w; :ytan4,Ʀ!\ia`rҵ$>`td;#sH\K)RNqy֛3Zdq'HBv] %ttkpeX2@__8Cg[O$YڞpvBٔTuaR V2)vX}SONsZƶgvW(I'`X=W6aEuBˈ eD|f[8#H@KHQBJF!:qdwe H^~ZZmQDCIh6Q#`-R3N[kJ8 L5d($R@RO,D[xtHccut)[!=$#݌D\’W<= RlEb]@Dg۪m( ]s#,7$fkp\f+=Ke/O~2>\TcL.'"ՂF{ GmvD}oMuw!!@?ͷuq -1 [dx!eLX!:2r;vb+nC"JXGk(pDN(7 ISℹPu 4ٔ=d̋/Ĺetr.dWh5tU?ˢЋf68iT%8zu`,n1tS\/'2iQmY9QFnͺ׀?9to.!I-h}-2P0wSY)yb 3TٶK' 75ƇBMxݹl'JFwV^ cOJR@n@?h~PjleR{dn_mɧZG.Ǵ^R$1/H]SYyQEREp/}2p/ޔtl 0[ )\s|>R(P6##j?"DsD~Eզ:Vl0))UӈT:$PUЇ9$I$ z)v{Zé bd +FwTfxV;ABd-)A>0X*Q![-[3jJVq[= {Mkk.'heĸ:Hl:SyuufL6X%&F IpR\ZP2RGXiDp] MbpXڕ)jX${k%"gܦ]#Xv JWֵ֭6ϓJV6JJOEFv7)+jߺcEPcu N3"8{)%‘)^Z}ƭX9-IS,JbmW9SpkJTOUu Ukv/H<<ס%eBCBq9'aاdi&7*:g}ѧ%^2HySzI%^8o-A* N|UDv9qRcFxۅ2Am!cI/s |⮋-f"&Q \cO*Ko%!: (8دrM4IBkyhͻK?\<|{۠81y ;syynf\)xxr4g#FCS>+Lx֩+bS:m* Hԟ( h:q۳77m $\ 'P2ҲZ7 =eu.!ٿmUUf3fMOZ8DJh|p9ϛzx~ZPmzP+9v/0npiHT3lro6nfGKdTp=FJcdK;v$rw G!=AFՄ䌟S 6]%O\J8)rJB܂ֿ~d2o ԕx9mԶ Z-F7=ٽ\.;^ ǕS4,Vc袊izVklgbiU,2=JA/j/J&7.\PK(qw&;aǛ·8VѲmYJҽ sw4+Ŧpf2ϬHӠr"mHxe@pq7S|(Bg#PҳB K+!z7=FuҤZw?%T[nՐN12зoJ m 8RʝZ[bT7Vhz*$'_)F8N4$cJˀ$G^e$-wI?;>JpYbWׄwm BBw%Q8}ցZ7 4[怐 ?\ uL}kl>,\)BWRJsȔ6C)ġD TU~cI>)[S8j ^=ܳPmȘ[--5PUrIQY'V\M'(_ 2\M𕼰N2N9|fuR# q˴\˘iP +2d)G ^ޒ)yLBڴ:H#Qm/m#R3Ct0BD7ӣsⓒَu%q:TR._) ` }sB6m;ږW?U(OiyF屑oN&ۛ\Fc&.WSAKPQ/tyz!3\cJ['OIA+98;z9֓9ݞb[ݶ\ 9!ŴBKmSFt|c,=lS}ngR\H!$!'e'<.ڶ6\aI\]qA~鳰&^ej:YBRR;̏I NC̢@ӷ3tDZqFz\[NIuY syTAOFVIpPWs4y/7S3QEIR#cʀwQO!\s!4]k`gy558uzUb[gҧ3N- .7R>rjѬ1eM>^`%0JZpGmHZlA+T }de*8I*IN##pwVm[kx=GX԰ ;s9NRl íLUeQ&n_K~pmSH!}Tt B}'*i ۣj$^rHHNg;nmS2v,>MUqjJA='w{bUd.ZYBC$W PRt|IlКT %'$ *{;{{ ݚ1󱭏8R J4WhE{o1gi Rq%jԥjJJKeC;dSWdp9s0an&3an$ 9:R qAiݸwwLY# 2ܪYA5/SJqHIIIY#ĥ]bdN+hj՜aG> ҡ1/CwO+Q8qʬEkjnܦYKsDJIF<0%̍,yHZ  ^)'v٬w'ա^@PZRH~3{0⤯Q #oZJڧB G'_[ ugrElV:HԮJ#P_ :Lgս9AW&.\OYXXET \įM]~JTQrQj(QNi\OģE9^ W%=&Ov$g>}qs/GLv?$V[lKLp$K+HO:QHG0Hׄi mHݳJ7t]u$r8]#|g F74\8ߢ8k'1寅Km@SPK)RRڊRtt!ѓ7X]#YoS&4Sm-8N #׎88 ,bbGr,KGX\Z/>1y >R!T@|C`te~"w?V)N ~0O!C̡Wat0d,ݞZ=P8Z/PeK qa))@s$@ 3R}t=k;UqLr^;iR•ԧN(yRb"u7 ů4/48.S,lw8cq#Jv5!ۉXFyˎp CHKvLi: Piʛ0̭nln=mMSs/l]|!m8TXC줥>\S) MJ$$nA 50ebJˊYKI;@ /2Zu57׹hy:/ /<57|#|-'> 2Ԭ>ԕ9UmÜak=[n{!lJZ:6<ûx-4cLem֐z}@nﰡ1Q((=aHԕI '?S{,¸tV¥.)[/ ^Q :2[]"RN$*ܭJ(NcLG{+Uc#%nljo.h 0OmY˵*iꇊAP$s8q:8_)yv\Mc1JO)s _$9!'.g쟣P@R=kEO3VP5疹Z0vp'cӉ㺋jeM6)p}Bbc.nGmnX0b2 m*ןrymcwȕSK#4ꕻJ%٘ nSBe F~).([s[?”U✤Yk|vp}, 9)JSE?!(6 y-g\' d8yoKKf-"[~-ΩZNf-{Y"Tx<䎮EyyCiA*߾λ[!o.iSIy-%>Ib[_!٩t6qİu; II!naLmn9VKR,'H ?si&KqBRpGxbxĐ_aQVan;g wQu|HCp;M퇈mWF_Ĝm0eZ@(䑧3Kp\2KeŅ-)A.5bI1j D p y7[<ﴇmcKnŝ)Z"4T4'őZ3 l0?k~Und#w['mf(R<1s^ܧy!YXe:ylCʮ2r0?EE[N'Ofznʠ%1j l9Rupݦj97HVje $tJΠ:n*}tˎ.<9q۷:iN5H MΒtHVy LP+\Z']:Bxu  ;Y@FB+\/J79|i3QtK6% A%HS:O~Ri^8c&}N5MOaŧh\r@{6!ŎIgߟ%Md 9jޫ|a"x,T,4qo^i&Qp%ld؏^o|1 غ&!&B %%!8my+R@f>mtJP04:IU߈Jo*_?NG-J9+̋!sKK'IR6RE_)D\պ+˙>tr骊JeXQwO|f$Cfiy@ꊚW;/.m7W.eMqo!-!%+8'ͅU#URK)Dg5 Z o)+JZNIVQCZZHt;zIvk캂]k?\>"=vqPm˱B?ƗEQT\)s+Y lG}xk[~Gjl{ iV20qN[4RƜ*yd,IRR냑O^13Ok+FPK Vb/t Aoq":RIAI9_"*j\&0JrR{7Kp-1MpoAn&PICnS[/We $ @1ή<oDęSS74%NIk8-L _  .|djKX :%dL/ERAiY Bq:o/.nZ!p_I6ֆն$yj  Gkn⬝Xeqp& kRXIJH=^Ppw{> ϴK!iRj-d$4ޱ5p7![ׅy..eLJ啾s~C5o\;pr]ՙW.rŽՍK =Տ& Q-'z9~!n ;ŻGu^*$9 Pڪ:D>9,& 0r'RϒӜ޳n+%熸 L"R·R f20j4 %g[X*:.O@@$'%r"tO'o!=t^\Q>ZvE4$'A#Jt3XgqsˬGh}+CZԢ:А$cήoD2S(rr|R#V2{+'b\81muBe/83CnmNC5Q;kǜslf*%^o|i*N+Hr dQ=ӹnUҧ\.>38G\&ˎ:CgpIJROoIqQ-T+.m-@A;sZ9*J+Nݿ* Qb(KؖNIV9 nQE2Y!}q"I i+Wī_MT_d?7.q"E1}U4Ƃtf3^@Y{e@lJpұsW0:j&:u4ELp(}Y骦p+ {J~*E ^6KIۿu][h+t;9lw:g3ָ m88Y!dqRnYK$䤔.Tl\\8W9Չ0̞>0.^18'#QjyDz6cU|6a)v(:eoZ# ?X~]ۑW&dtPa%aVhSk6ꓝmA vjH(Un^nLJ[Bin*=y–ִ!JN\'0Gn1T-eYR2=ZSfr< q:~6lg$W[Ye:Oe3˷W{n=S%H(;քpҥKBVqiՎD?=CH{3oچ%.ۗ1ġXNT(763 $%|ywr V*jnZS<h U/ITocTDg1R\t:­$cӏmrh1҆{u1V7vBJuֲ6J|~|65@*,(Ke!1e7ZI>ҖbrTh#aw6Msw{yf+#Vچ23fzSqc8-|c02vܞB3oQ{RS)Q #ԩSKj)N% l)l뼮=tCfTc*I aaH)ts⯵z?A|<ԆӉcfSd //1=QE Ϟ̲cpiNy#fإ3yvo[MuUϰ] |t$oJW}pO[܋oɆ$pss?Ef-7(ܹ BYC`J*; JtLiީșZF)~qX@9`','_КXmsٶiY${C!hu RuGb ge4 h=)D2:!XJ T }>O*%clu$|]bBH X{yQ:hx˳a3L-<)u:Ķb (⤐T!'pڳRyo1VPHlPڒ|&W=[*P穝rI r:|D8{tcsS2@Z-wxY q5X'1$q?9UGKMSHNLZT<J-=?[,ٓ=6x3n2[R}֢/&`}nErm'|rP<SO=lv'5v:ep8/02SqbBC\~H9!Dnjij1ҒBTR Y9S+Jj^z:qpi77%FD~:ˢ)୚^ƈANcGH=δ HLkG|a TrU UG_02 ><'.U`a=QEu"]~JTE\įM.q?ZJ?TS\\Wi+ W"tj絁Ea)Qʷ #iI ׄH rJJO/AK-tu0I- ̨G'§+h,B6;Mh&.rJDRˀ`)$U#H-cugWX$7\C̏":µm`cM8#j޸S6KPc8h.V}Is_\OHYѮ)V1r72|9 V%!Yh= p䘌dgk˛ZSnM&-6_mĄjS: J$$t炠p珬<~%dHL%lTPEnM[ωH/6Ck>  q`Nnu3>#>& s:eGX=\OlU83ZrB͘mM69$ӴATv ?  ~z%ҠVVnߊ)M Y ^f@HI!7 L{< %W'ia886n2 :X񓓂ri6uJKiuGIQta֜4i98<+þrs1dɅ!2a~+퓡\-(83.y%7+RΕq)I1T{ۙa4ݴJZTT̞tF͈G_+w螽sIvpPPO:jI B|>v[ F*-{&9:|gTkRtS* 39W.73].k=s9UM3ؠm~J{'Zk+ZӡK*N;N1毁IS-v@5I5Щp_DXN{Rm hB"RaU*=`KBF *oR] 8#-Be6@[Cjos`keX|4jÙu,QQ mm f7!&mTyiM^V3we,篈CJ>CJ%,UzU{BT(g$p|b)?\׎)w4%=h~Ug 5y=1؊BGoNQ\id*&s*(n(/ϞYZ:Yo%`s]BNJXRX$ ZR}'qI/2Tڡ㔹onRQTܑH#w^ug~ \3I01ֽzǣJ/MUB$ d0u))WqUe?EJGp_ Z.4XHJHk|&qIZٮcIXZΜp*kr]uC1uBFZsG$^D@8TQSf!U "c >Vof%DTzNyu2ӈ-mqSMqy ;+I=nV%6icfd\mB$gGl3@y96k:Y]F+ 9iPQhlG€$N4Z2*ˊw.6nmJrڂ[8ymnDnq*t28ʽH؊q `# N㲅,|JBn/yy:i(4^}tu:wucʮLc۴D%*!E[jp0u!;p(*Wts"\U9l%VO^&*:rKzœPklD>7<^7JW|!ka/<)ee@0NuK4$!¤tU2sXJH;KaRV,Z#$Kra$aJG#QIf4DF5(yyMz>I.8A!*1F7IY;JXmCIKV(Sj?PrBU|UOcJeo]{- 4M>ᅝ[(!`vڣ|% SH@S3PXZ2RHPk{ #X(C 熓jc֑ 73,6K0[ej4>u>_'JVcUQYxqneEݰ;j gq1A#`3eƕpr)t su%ST?(_);+pǴ [RCI]ְTVpIN*_IA^|[nݮ m(ŌXqHH$'%ŕ;XξG)~CQc֜cBJTJF;r+~)vqԺ !Zpz⾋ŮlPj% Bs5xk]e)WҚSύ;iy FyRrIQ 4ѡ>9B@ٵL۞qzG٤n@i}#9:Iاۋdp̖#!n9Ju(BAH'zغ{z~s t8}$#)%쑷g*Nyn)jq2wRIԯLLJhV; kI*ܐlʵq?Hki"JmNnZPҔ?<9,pݎvM 9Ete"I +YgoĈ 67yw `m){]6.Q7\Hڒ' Β3zD2֭YQO8ڱ.7c9l'K- 9";Q>֛ Bi lծ7G qi(:PֵsO*lLN T|q:RTY嚌+^UUmD#֖=XJ9P޵oaOiCU^MSH KjΥwZװ@+e>wiGдQE6QYogĿҙJegq&?Қ*q|m Tci9hKТ6 +H+鎄>J;.R|lT>v7<%:rqKYVe2t~ZcZT,.mι['Y筽ei璄K(Jy|I'⬿` YޭJDk pRʊwOKqRz H}5:Ưq{&-@?OR ݥArRmG!9>G]Oڽ) (%8O0FA*-2,:LۂVmR^tn% $+ IqoVL,! eh!82\[`)>&q'k-*R#qѥ$8#'}݅]Z#U˻z * %:x4)@%:=3q㔛Uώv5Nxpd!}h[AQ~*{Cކ-Q&׎8>@G)F‹  Nwj]<4)N$zϏBML4ϑ$20oIV/jj‰P氣%&sdz *\WGO5bVKCldTmTǣBܛ% Jgd ϘyÄjOU)o"ty1mBTH,?U_'uk2|i-q5@)K$@ 65nG[q$Vn %N,TL ^݀ ./4( He$T S'$Htm~awanҲqr2uWW)M?qLCAiʒqqP<5fAbP=q-#e ByRq禙502϶"N=R?9I6$Wg _ԃ'Oy4RL@jFL[(Rk Ɣ*@V{X.A-@( Z.ɹ+K~E%JTiZX">"XBZNe5j詛b$#Ӛ HW'm~k㯔2ABK*S;>:Ł ]־Z+-ֵ(e%:$ nE'Jujʚy+JIl RF`<Km2qiPCfZctטFMiDRCO4@Ugm>zĻ[۵K:̧֨Ρ$ 'jmEb㈖BQ^tz{ES$E]1Z-6p6][^BTj *ؐ 3PZj2 łRCy0h(>+,#ʔrSU;t8K*Y'iW88>$dALO\Pՠp Ž-0*KT\a )e9JIvMWPJU_[~&ln-oƉ6mhZӥ$-Hw.c8ǞDw]/SR(wؒ3ۊbV@UJԝ Is\ysdq̒|V*[RO|UZWZ4!^*NVݲsQL(u`% Qء*0qyiEPV''ר*Z\Vim3ug"[qZ͂H\ոNTRvH<򪜗%h'%(Hϣ$vX"(i$+ >MIkn(¼ K˲昶-LPXnc^h]5ອ\$tGTG;MCitvTNjA'M$ʝFqkԯrͳ5-jS,րs5UpE]KKlxxUN2$)䑾ߞ`{299Q3_JTeL51ds^Т0NEy $dU.Әw>R)GRHrMKiWB~ZTN^HuƕCjJNwТINly*5Yq4KRA#xC2vsښ}<)eN$8JC2,PԅeIXү6{ĀM+qzqźd9 >TRNFh$9+Ce>!@IGHkooW<+vdEQY W '#;~mǕ!N+ ςWtW'8'4 #}?kisk}B(#{gvnj8%2=fhm>Y QҝSVԬ}q$ܝW9AA;S|:uZӁ^dKbkbfLRViw;u}$U0+Olu$n~cGRӹG&]iu R{ [u )F*T= J%!ݟoTyk8m84-gR_0מuUD)IŠ{O ۨ,^0!;WPZ3IUYvWTfHO'3nHBsJ]9Mxz)f8K5ɿB7pG}"jYлDׇ2. ЃPʹ<둤nHP;U=h\JJސ9ϱޜx}!$N293K_Vc'ؤz|ҿUV1C+[+u+ ע( Cb(Wy Q8r,GŃC&JS! RYe8垹`b7BP’u+#1m]K:4GWu HuFTpuh~UOdWθJEdt=:7rExRRO!E_r!Rh(5HZ9 n)CX!CgzF+2қX* [DKQE ۘ?ν8PRsɩCH8R[HKi#QLn *c. eXՔc`3Q(dy퓜W\Srp;$9,ae8mk33Twf78CCiRJI9OpyWRd˵ǐԉ(hIG$g<,B$-VmR[o^HHywdf1<ʹU`)a#JI氡˒GƪB2 +BN(J[{4G B[gl vdvm NH JIԬmjr9 FzRROYQW:ڒՄDw9 r)R9ɓ iq 9P޽I|!;~`;KZSKAPV, YI!pR.!͊!,6*iG{;Åg[:𠡜"& ܄#PwWyF[ϟpwHhS7[|'eCa C MX-ДCmP;;o -rt(jB>8q.-K `+' Mc+X)ku&{:6)]y}{DzjΪ7_ C[`(V=cZ[m2Fs##z !8l-O5 c𛥵vM;26Pla?ir3 7)~pjB%T ^w .SjS3%2 _XϞ}]ILݾܵ ZR)$n8VZpM W[~LpFY1kfzޥv556$hyҤ=To[%'=3 x1h-=v>n &wmԤ) 9ۅ-KF 2X =jn7%NEnse%ìhRHO`KN5vF%I;n}-B )ϋx)»v+Ah"ey#%#_MVYuWoi|0|Yd-c۞*086$yAM7 `yMz,M~b%qG ySb Y,:;i~iiB\cΦTᖸu%WUjܷꪜn,S0ZSeƸuȆCSjH8W3se6˜.2甕TF)U>U:\GßrZpu]AO9m&TF9响 ynGTՋ\KRo\25 WI]L~oVY_${8doVT;)7jQETW쯸1%(wI. gF:\p̄/BN:5oٍ_ !]G{ksKgp1|u|.ŲoNtYKZ[Qҽh1lʸڀ*'U%Մl)X'9A,Z[a9y ҊcV`w^ڐ{9|U R#iC HH@\_HJ)U}Udϑe7Q%G6T}"棚nB i!R$ OVYMHGzҤQM+O X4o(I6˗ܹ_*.]j-_r~%)6}ˉ~5 nWH\q] O+kz^.о% _B_x;SFUߚ& ۚ֎~z2:a!XHUy$WεXble)OHJJNJ*Nה5&.P$_@7'u^ ^+XIʅ!9;n$m}I'sC'lTu'#n] 9;_X(J1z)2w89޻tI4j8AlѾ20kK^,5xI ^9ڦD%԰JvlڵvLnW5~BسP`FsM;e d%h<7Il9<E,N$szGɰ4nMN+5QaYS6ue?R/pQԷݨzc珊Dc Xכ*k2t=*BN>2F>3Q!,+cVEȄ(}*JRP'qXX`jxyF~T[U][\F{MÐϷUwj|j2'U|17mE.x8̌,!H 5"EDxݝ.ˊLygM%{ jNEL(棩&*XH}ZecP%=5N馬@"BFYp4gY4LY_5WЯ=,t{ia_;XT54i%G =SzdڬrcC(ojG3zN޳εbozCoW&j*B~NFQE|zQE!p7I:LI'ɩ>uH*Kmd$1JPJ|T(PRo3!uG jg)_fL8IMQC8 ?@eYA)Q~:%ejKP9imAhV5MޜZҒmʕ.$Ld$?NHJu;MZ@K2W:KII VsgNsQ( 4tlE\^ll5(oU*.|޾J[iA* r^ǐj}9KGXJB;P8[2ܚyrtר10[ddkBHwCZ:Cpd"9^FHD̕*M^ :!yp:b qwO`Hlm[-ѫ5{Mɮ`v cv9Fڏ1Ձ wCYBigGqz/D'f7l b1RqRJJaϘaIoJmC!C*Hv{DzZasn7}y ћQE;ҒiRUIyȮ!$$`͜V`%_uoMLzFpݒ{)VTpFw"훇eώS$ҒUwUF}rR;hB~!鬨w& S3L4[Bs۝ZR1ɂ[+XN m7U=o!+ǒX$wzXJلn5Hg#(Rp?MO]VK]w)WPH[*| GqF޾%CNTdd+}{dyg kTG`&KrDQʺحjR,_%,@JJRNA9􍥽rU)m IԭWXJU{-–~f>: ʡl$g|1ęvYzT7UxmaG!5k˕[$ABUR8QXI[aO(|vӶ8V[R>; m.7 mFJgW3QkJ=R\YbuHZ|M!#$;^+ ’;P;beh!`u, Gފ9 <}/3ÝpaeXfE$wL2GVqU8:J᳑Z"ԅI#pEWfTz ]T6{2Fmہ\%YS*Ozhe׾Twe;g'O@Nuq[R@L8fcr*umy) _*q-(~w^ǎ* R(nXmuȬ%IR2N5ij+l%QA1+5EV}{+գ%Q_L֣YWKf (+@覀`c⯊ Da>S & LUY@I8X"jLǜNՊ{@ͭj !!H"aIơ [PQJ;Ad96%=D͆Uz0FBOTW ܤ=Yα.P?E yD 2^N@T9G4(،הO8X5;i ###4r-jy)ᜠ6U$k*`響s\ v'zC„Rb:6\Xڹ9ێ^N:3N7dU6徐:ƆA2H5񦔜;e$vi@h 3ΙQo).A|)9:Be}mtƍ #nU_ Ny4cdTQ& E鹰5)"Pq';`sP%<4JjxTS˺#&V*TOyӏ#ċ ev/8VM%YHړF%gNMbvY(]UQȵ:2q Q1ov)GF24oM54۫ QӴ0^p0Kb譃:GpUn}WymΫ/i7p^- 44ܸTrM|SE mIRv ;T:/ո9Ѥ2S}0 zm␠@ ~\zk{E("]~JTE\įM.q?ZJ?TS\X_*4qKuii>0sYGO#Z46?Lz|v$M1jڲ8վzW{'͑{'͑ꤳFkWYW{'͑{'͑ꤳFh||<|K4fW{'͑{'͑ꤳFh||<|K5!:~Gi+-p5 *H'`NF O|Q XKA6M<|<|ָ}˓ַGeGrJԄpvH97O0/3s Ԝ UٍT#\ۿE'+/q?%h6G%h6GQĐTwэmdgI#8pi, pQ.iJ/{D=Ty/{D=ThK\RK>lUK>lU%3Fe+QRY4`RK>lUK>lU%3FeZ4˴qԢDccBC:68Րq@88;V'W]U= ]ˡx'B((r2gNl N p\l%h6G%h6G mnd2cq u)DJмdxKםERۊlbC)qDv% ZTc!'-i8Wict{'͑{'͑bgS ܵ`Rr*HǺy2ymE+N$lFA A"i#%QQRY5f||<|K4fW{'͑{'͑ꤳFh||<|K4fW{'͑A bN)8o)mK dDyt0sҝGvڑ5r)ϑª;*+ 舣#B,zwKDie6P4 8$k{'͑1?uLl X}esq'yJ/{D=Ty/{D=Th3*1O#GO#Ifр#J/{D=Ty/{D=Th1O#GO#Ifр#J/{D=Ty/{D=U I&%+#R 8'fN%n\v" o:̺6p]hbqWGXe{]E/{D=Ty/{D=TED5͏n[P8!uZ‘yWnj~lUK>lU%3Fe+QRY4`RK>lUK>lU%3Fe+QRY6 7nn6ĥhNQ+ `3 n'd\f^dz^dzJ5P] Dƒ @:ө+AԭЮiv"xD\n_$%Jy^T*H㇚(ܛ/{D=Ty/{D=Tۛr^ u6V&)$`u di7SJ/{D=Ty/{D=ThOQRK>lUK>lU%3Fe+QRY4`RK>lUK>lU%3Fe-Vq͛k U9O5f/c8q?KՇM;=žjI/mQE|{UW/GI\SR[i$HKe@HUE .!og>&BKV8B5]iV-ƒ((~3^<|K4f#r3+QRY5W{'͑{'͑ꤳFh||<|K4fW{'͑{'͑ꤳFh||<|sz0$@CΨ:d2J#;g .l(Nr{iR ԲNz\vRIO#GO#Ob"Dh괸^H0^#JвC#)*mY$~WI^3 o#}daAq̕%h6G%h6GV2^dz^dz,њ0c)_%h6G%h6GF2^dz^dz,њ0c)_%h6GiĸLm(25LpF3u7DYw:dQʗո‰$$UQz_$HrUZUJ~}(Lz bay,7sO$ ò׽|}L,;W4l8 x]#%||<|K4f0||<|K4fW{'͑{'͑ꤳFh||<|K4fW{'͑{'͑ꤳR _U2$'#=`@^U#V1I| &K>lUK>lUI\,r\a3)A !*#R 2s˝4kFTɷ<Ɇe)D,p*px}Af.ғ!QQ"<_zí):y+bp"\ Q.iJ/{D=Ty/{D=ThK\RK>lUK>lU%3Fe+QRY4`RK>lUK>lU%3FeH/2SQs(Fz9yJq' uR qdkWfo^Ǘ 9 ~W(rɵ\įM]~JTQrQj(QNi\OģE9ΞZfKK8A mBR뤏R~Z˵Wtw/m\$KjU#Uet5R:Et5R:Et5R:EtqsmGϋRң"q.!jRJSIQ'NU8Nq$u7K *\ s<(iA]b zA*N†M>:z/Z:;v7֠w}ުs|In; R R5%X9cigl.7;A߯ojR5 SS(95R:Za \IKjU#U.]-T5Qd]-T5Qd]-T5Qd]NpZƶZ\ʸ[q:6 N:;TO]9Wxg{fz( #k/c;UԵ]9]*^ CBO'Br>4WK뿴*T5W,UڨHUEڨHUEڨHUEڪW )szaĸڰpv;ڮXZ78]"\- wwK 8RXX^%Cxہ^lOp+Y|.=׮}H1›V^uRuN\9ZTd;-msߚpm5kFZk^j|S%>HU ֯&%~KmOս B QF;8)fDTMQ5ڨHU5dڨHUEڨHUEڨHUEڪСJ/ڤ꫷A8Jvu6\+NOƤڂSk9u(EB(<F.@Ecouxn_d/N)I? u H/`/e+-T5ST-T5Qd]-T5Qd]-T5Qd]Y;őĀj)C88 ij۳zSeC,-#e$,'`UtBTGo!E![)%*؂9)Fj49lꛊ3oEw=m9IjmŒ9 פ-%$! lP׋l==Ŕͷw%"H?OKNU>Jۋ[uO% x nf;5 A7gmܦ+k [÷ƪ5R:ZVH-T5Qd]-T5Qd]-T5Qd]-T5Qd]jӞZt]sǓ_J ijХv[)|*i?w1QEW[K˞FWv?Ev%` ֎JW;YWH mTjuQ[UTjȺ[UTjȺ[UTjȺ[UX_E"j_[eiA[BwqdUSsCDGp!2Y,4ۤn7ڨ`6 Do9kKsVe76RmNۡK)58H8+Z *%Pk3#-α'%IQ*Ӎ#JqTTjŇ1:OWKoz\x4'Bm,1?ʟ&Lhp)-AQQ7$SmT5?"8}>T7*AQFfʋQF,QF,QF,V\9ğĉ^SUmŖR TBUT'[:OyֳVEW׾EQ:{HnuGݧVSԬؔ(@S7*ȿtoi?-Tju 5Wkt5R:Et5R:Et5R:Et5R:Eun4][L\ZVX:{=^lga ڤ>ʂFZ[I cVJbMS ڛqpx2/%F $<66;\Mwցmw[}պus!-mHҍ*%HIRd@\(ң-( йXN;RAV }#4tLs^ [==!3%aSo!U#UdڨHUEڨHUEڨHUEڨHPȺy?Qiz,%uO-I? uxm%}UTh"(KQKK,5oe+NjOJ WT@UV'{:?;o*}[UTj,QF,QF,QF,Usm+]۫EMJ\떵G(H ƍP$'g&p-M2Pt a#aΔ.l3mh+x+S,C.C L^[Ll! 뒔@/N5Jvͅtr5ͭZZiuiJT!ġXOgeU9Oo1 mi -%*FvRٍ-q_KI9׹/#4HUhG@{\wQFnFGU.FGU.FGU.HWw?Ev~WܐDvPVB9G`k[G:?_:K_hKԦ_r4Qu/+SEE˭E\OģE9֯q?7𵋉"5Դ6J*%+A{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt>f-(jN8ZAJsZhWO$썑,*4Uwx+MlnK (t-MB*EN90(=xpik}%'+B 1Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{MtT[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|^EƲ[ڈ.JYTUs'Z,`(1ی2LN6|zQV4Ql&H,YGJOQ5>QW_Zy7V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|GC]2~<=d-ɷ!32Nt6ddd#EW-T HGi%Y{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt~౩e':]>dA~*\Ϫ裧c$2v HJ rRQEV;W[UoBfdeDr 7wG􌟬 b*BJx7{Ag]#)?YGGJOVEY}kcT[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩MtEz`quF8Ÿ`m`isS_CI.u >hJ_n8Jr}Z{5aȋN4HuXH@Ҥ)NpU6Ccu u%i8*+0~S.tp =ӑq_"Pj!$`Sb<ɮ2 }msΗVtS *]ִeI 1+wK\[1w3Ai 44My]Ժڦhox~ᛏZN2]w xCk\vʀŲe#9dok=qHmy k%uFK1Z.k?xRR=4a>"OQ>/W8ݽM6:R(?SY) UxKtO j\)RCZǡ9<; Q'+TvwU?q8?hWZ8[#^8,'PrBSDvGG}8ŖZ&nf;4Hy7?4|Ϫ3;!'o'QHYio->QNTt2VQ01yWq>ݺ5:TR^⣳'(4oʆRd$1[L6!%tպ8T^ 6Ƭ-2#LtÌ@V Qۗ-ki%ӕ7W q}V튢 *ʂu">$`zjS CꑷTqogP&L%A-^8:'o6oceuaLJJG,Sg VUSZҸW+^\b2%rZKH 09 l/s)ST:F&X8(+z{s.rcq/[C w4jڕ)G*Q;dF}rcdU.S4LWL׫'E&N/|T {QDU|&[G^FכFkXpӯK=_o'MӗL_m@_c"]EkJ[yJv;`z҃JjWlYK@hW׵tҡkС_| 6! Jj2u-)S`Ӻ1d:{x,ŤͶ/aubU.IƔ)hbw52s>T"F$Z^B?ػ _ꪃΧ >u_$CX^;BUr LHįCtŒb}UF̼ĩA@rEN5 SGp?6'R!]RTţP(e SN;E=ml4xvTZMGO1ؿU^J<]~Jx+ ƐI'4QA^dUbKL-O'R8]mx10TFr{1Va:֝KCg4ThSt.8-ڭ:yy@~I+YE)u]?tkV~E)h `ziޏ-*A:2yb ޫ};[[%HAJx]ys :@{![W(:bfIYmj:Uy$<ԡ2Y' { :\RH*G輿%Z@]0t=*XlWAф%G*沅p$)*Ekf_M<5#RtI> TZɁ-vZtQEI&(.Q㞘:ABq- ҄8O.M]-p1CT RO?T•_tP_TGvC#E/Xi\HՃ~( ޡ+F\)dkH]%ȟq+a;63& '{[mj!1xw4u_ N"Z]dE×숷 Omє/k9>i[vM_6N?}*78ٯٯ'26kjHG̪EI7 { c?_Ss՟٪@iHy/V HgffZ_t;1cff+4?Y) H﮶_>kƗoSNtƠmyjSw:I՟ب9Na:͍`I8{Me;4XH8 h m矖tҟN՝Xh1N?6ئOts6?b_˕zkf )k|c8󭭰()*;6q\v skUt^wkF Z,,EWVj+gB{lOZ9I/ t L[KȮ~j 6c"v3*f8̄#l}jE7 :lj.q"|<ϗkX["#a/hw1dMFAgȘUX6IYo!R*@#XGiMu =(&&,6ae•yu#[,Bu8sWnnlYqG'RBOɿOieהe\ÀMcamB&8{OE/6|XGTuc}w% : d`;6 –8#p|DzW{RPsN}3|Յ-tO҆ŀ{S^%a8#T+@i(Yo䌀ہΫ.!Ȓ\#Ki$㚲9&aۀ4%V7Np)xjje~#ʾxi`.N-2Űc-KV7ikOۓjFtC*B-|R;u%>}".Eŗ6S>myL)Z 9ҭ,jh)d~3@*NI7nkd=Hlds"ك]򧆎Wa N2~.Us\C|u j:vŽ 7krur`"AAYpn JGw1ʶˣ!HqJ*)Oӿjd;nnd pk;mQ ѕ.`)s@yjr}bT# \Fez8##)b;NqVMyd8r|wfGWhnVdU4襒I&᮪ֹh@p[BxzeB aDnRTFν:{ 8X\wKُ!)~JRpsmdqEٷ2 (BHˑ )$XD [5uCN rN粶cB{.lyǀ3ԟ^ߧu:xpZᄧҢ>JNwhrU0OZn3ʳhwGzQZ^w))SYKuJyHVےhHh-i w<\?OWh76U92!#uXߕQ$u[%\2kBc!CRTz*XJi:-{%zk~\?!޾?=_Y t'ym\8ji@ ukˮhHHYV^ sT=^ \JN#5aLpܟѽ#O%jI aCTU u`sᒄsC5#.`?48 Lffk1%ۥ)lY&lN@R^D)\|Ob[Au]:?7sӞ郌qmRTa:BSd>:r *'uI$ʙcZnؗt)'p率i~;"xockvu/9q$>?q_  Z!ldkҐr7GfjaBmgm;!GXߙ.)|7r RT m#U ʆ݀*"mhL@PJN65 7{4]nKyl< ,62UsګI @FٓQӽ"ݥ ll 흅ŽUC\WV$TN} Ӂ`6x8۾:tq7WVd{-nf|xCeǖ̏Y^]Q񯬌~EҪՋiD؇)!ҞLe޶[by 5̤ ˉKDEWR~B?=`8A%*҇cL&p/:cWɯ+]U<l6[)iN$(pIR '?($$ &m7i`oiͩW#aSv9DyqgJ~ ohFexee)܂qHOaASs^HZYB7$A1ʽ%~DcT@ pTy=jR+R );מl\=ena![nYjurހ].4Ag; ys4$ iO>H#?sS;? &Ei}dsV~~H<-؎gfUak@e+Ks9`LϤqWW/dO <3mM^kC?Yt8![6޹.^P@1:Z~S63U,.K]kq=g}#}]ZkNc&̞8qLXғUՁm +qH;At7Ɩ.ՆT !Х9oY;Zn)l`s~$eMG]gu $?2͍T~)mN]^ąFm4ЎHRTq?6*3s\G} p+|EmJTrpwqȝ`'_ų-n!Zm\>') q#}^x݋Q$%Rem y}soAhyVjCxpwN#qUI@ r+ݶs~Мg>ҙ>PIelV\X?*q})e'; 9 :pS8_iVG`6Ɇº*A'ts[yaF06])Y$WI7Eii%( x'(Hmn$aZzm&L_q( ~:խ\mƥA.^?HN~4 ԠU~O~Q vʪn)0$cXf{@I5IS#oLuD񤷟5QlEvG`mMR*Rxcs\Vmq|n_8O=.<ŦcA5Ƙ1QbL(޸eo>cQt({MK84O{gF-U5 >Kx:11׭mR)qKO$23Ju%є @ob@uGtEżIx]/vLK*[@ WYol.lCSYjܧP}#⯌$4E60HJR.W9"}N=<9BmؽӧI>6o:m9q7WX}(sSťĔj;Y1ve>np2"#e.R:r]3X oa^+yA۲Oٺ0ovjfֹtQE\įM]~JTQrQj(QNi\OģE9>,qX)7ʽY;v؎$w.[!B+'{[ccvhu-D5_b⾒; Td055Wr}c+L 6piOjv`si@2\'@3Wʒa%1Z&AxG$%iP0N>*6yj$Ca&N2RRx g.Q,i c^Op?]ĜAl+ JGv|9.ߦv5|3mvnrgmet;@)|'7嫇l.9}"q^m֘aa!">I$ʢj `ޕ%DXN])KᴋUFC`*>_Vm\EĿfkq$Rê8'H)Pd +UW3rRQ6r_mPݫ߹)tɊ|>['$HVr>:ObNI T[.+QtvVcntw̆ mF20S9K p5lȝ*l{j96]ЂRTƔ^01C637;ۜT)foQ=-϶=°~#_BTyvN;q櫏ExYd[k/$8\܃{U+z;ͶĐyliLCi}kOg{prl7̒w,ʲOadmrV5([Us 4(>WyѴG1ljEQOW$%]\um|W]#?ҕߵhlc@KRRRXqP| RNBRqIN6zޚI*є6 !Y+ Bܝlj3_[h!cNGWBJ@2*Fe'85mcZvEm*HPO C\Jԕ*U1%;9$Pμ!9Aҥswyo2+ϸjo~DQiCl8~7h]Z+H=ļ⩻uw `'*}- I +Z. o_6>7|UpM<"#Ӄ)R{>L Zh"&Aᒁ.9"EAb 4FiiV%ġ4N$sN5mƻݭkq cccI'twQe{SḜ3sv}1[ D"= A*J6Պ]ȕ"q!< :VR;qpk1嗻#4Q]G,NB+hRd6ZH7Yw}e@!v*y,{Հ3aIqjrX30J '˷5HIZt. 8rwp+,͈%LVl7h6 67ņ=6s2HJroiH;AZֿ~C.'?eT f2)r4NX-TN>aP8˫j2\iWGS_^tUVw+rT1νjOiZ8H2lצ['gV*&V]܂vq?I~z \xaGIv޹"J}b9=]¬H+^d +ɎX$4&eՍKWHzƶ;tRեI% cUgClmE.!ӥG1Z)qH”Q/).MˁU q˶aaX`r߂\NʡU1xg'P#?yIC%cKd`c;1KJ5z%qVyYS:&fAnϧ{$V϶,K뙮s1G t9_[Uє ך۶f(E~Ful<\l$8 m_U)KBLcp:j7H#s^ qKpŕ(NM}#lNZ' Ĭe1 E[tKNQ=Y OzM3ħb2Iw?{nEZ*V |bH 8}w۸62%JZA'mOzbc-2Vm#JVjFD+t٪La܅熌BkIFgޟEKcGFW)(1V90~=KVenr[MO)-!T;r;`Oq}]k6hak0lw<4h8/wH]Ŗe㼒=X*)ԜgpNF.\z*ZRTR);7wWV%4S%.1^1[ci;~͂*KK؍5~(JYJTոlW׽͍ɽ"d.ur%9?i=f-5%`:Mt \.,.9pHHRI3>zWɫ5n9%:)ojlVürn Bx+d) <;deWQӬp {>j}lp!u)]=Ђ;V*쒵K\Hm. e:I*Ɲ"O i)t)BZĨ ex) BrHQ8Wdo1p[oqJNyDyzfD],b n`yrXI2JS|ةڒʈkXJ› nʪGZ[Q Rt8Vw0mf[,(\&rR~MKx*;O*^] vQ₤̀pw <n%]xIRkp($Sƃ%<qC#Q<ݛ˥ r=kI汱5+`T\zsںpGF>ke$BbV;EQE UkS?zZCWFU ߐ)ZኖAr?|b/s=aJm8U'|xۥ(xx%̈q[ #`8!9;$|aq ./?QR7R$()8A;;3*l夶++;|@OZ'"jr#dTMς-1[w[҅*b<#߽ձTW͞WEeR줜CFƩ[<\mY_ɛfx"Vc(RpǼp N͊Ҍ +5:Zo')V1#i sYH<^ˑ8|%{OR5+ؘ^.9ҮBHH /WQչ1Q d'Vv ߸Cn;TV2|]+Fj/qΊިy廡j8F@8^ ۼM3d3%.\_֋;.vM\]ad`I8 ?Gk6]eu(Z6HCܐ2[ܤ$>7>}m)yZIq=VIHIHX 1myC ܸR5rX@ u)9'8K(b$TҶȕ# Q0kxe'h+m(5 3Z]zȌnKk%cH~ϩAFhǞХ!E,dܘJPbhUvWw:,Mxɢtd-en6li F;j :JeGSnM)IEv7:q [dBF)$+oYʐ\$ەml \d>,T`L78MBSF@''jBm>]M܁j #3嫶st)pY𵲠 \*.#~խ9&"ltK=ZҔ9rs\ 0i,lmW1KA)RQWlX߷1ZTqH/b Ïzla#+Q8SUB=\']:OH\nGXX _kPFcc 賦QE4YNdh^8'=H mwq)1:KSK{ gt_B\%h*oLiS\b씅(f)ؖ6elei2Zo ;֐G.k͖SpQqk$''&zqU=a'>aV8Λi]̤-AQ:rI1ʳi(excoZΥuL=Oӵ3P E)Ncleo 2-[ GJ~\ EI 6KMVL:2GW"kziOFЩ=S`Fr6 ;`j^-Ѐ%CluP)nӡZ:agt :'|`c;Pʍo%țji 6bTRBNSW+GE֬U};rdu,rduS9pM3rvl"%̱FgRt ;ָAqJ :|M~U#>aZwW !JT2tN:4sLzfIŠviZCm65vizBo`t7 SgI('Gܶ3W2  te%_e+uGXqU 1PJu}奅"Hm- ry1PRoF*X4w1 2$ r U!*-UqO{vr=CREiֱœdr'VX=褛^b# !) n~:q^%$\$x3s?+x1}wcbkSf5kc7 ފ(+}n`d͚ʮ.J:QӅN6R"OlaR}ʝJU Ͻ0YjX] _dV6EΆmSM&:M1Qg v*гrfַ؇8!RXtGդClj3*_fZZq'irؓs-%]ZT:ri Ͼ,Wv?I hS7X)N43j4LgK ҅$(9x (xML=XqHwS6OXR̊^ *]K{ڞ\PVJ rzns0x@pNZe+tdv PPAt ȩCT7&'Hn#M?xbN*JJRpCiR@)n*Yw \p%RHN sJ. T Nۏp[*ۑ\RӍh%:AKug8NHH&2-,&d8~>9HYDe\5AG PRD qN>:ʭpH)_Rˊ8Wh.}+xMַ۹ōlŵ˩ː|1ȈP sB(_6$1``L)ءPџ!o-!O? uĩ- '΅j;x6!f|e[y"< a ZS69{E*d]$h\ٷtS DjHVAZIWLrJwIn佦+n6X% RA ((, K:%JC"'*`bCV tk2IJq)>RnGZX2BvV5VSM&ۯ8sGq'<ۑ9M\cjذeoO?jQSH5u ր݋m I#EQVWbT_u E lO|lglҌKZҠ?#°O3'Vڭ89PoNpQL2YJJHub pj%X ,!M@.'H??+r5Z:tQE 2ޢPo8 ֖\F}5eHBiKhycJZ߆ZHi.:8P!*߶MSklD ,)nx5g6 0 }[*÷ rTq!bp`x<°>*E|ϱU-O\P۵J3QL2XmI>~rU.}c8uCɍK~蘌$&TfP*Yҥs+03f xFYQʤ$lTPYΞY$\˶ xK$0NpG`B8z=`=6rCmJ 'Qެdk$?fTJ2.nnp@[i.% Y4 +9'=p^1 ƒJRZJI T^3G0*Ü:OC >:EI'(;}j$@G ­nlI[Ue[ؓu$ ? KdlMx噷?M eQCIr4D ( m~K^kJ߁in3U4=D樞᫓|DsweZ ܥo:];R|=%e||DL/8Z;gT9}K GOimVo6,t>U7JԤ%u$  ƑnJ% YN fbiqOHrU0ds6-Qn"2. 'owwΘ2;2۷X/ZKa;}>JhM7I<۝8 n J'd)1JZrҬ_H}>#pۥC}n@ b'Emm=sK%hH|in3HV2cP;jIle(ee )J'y#jTG;䚁zʕ'iO!e8.({3W[peW,3FZ  G*̥J.1oH)@=^r*SkRzfu1d.sRTϡ]ZVIܬ;n0SY%;GYhAE2ZMrl-]RhC))'q񏊠IeI(߽||5vЉň(l \I`dh;v*мI iA^3+S/)*+Ci a̱y_<ՙeۃ[Yw]˅TQ @**H7#;WDZxmC :e6D>q˼ˋ*ʧqGYuN A9|tR8BL7Pf’ JbYAq iZZ{5Uuӽ龤fF n+Oeе"B h@똸~T{;v$$-e? OC@NI=~G YGJW ߇ JR^L#DŽ Pr8BxM̚{UaaԨI g$jjjyfrÞڍ`òhmqC[&CV-Dy +H(Q8.JLS[iÍ>38}yN!޳{-u0i+-n3/x \#$֕i%[RJh }>΅*[Ôn)G$cy6CH/օ<6ފlЦhVG)AD3*k.{Gb EQM*  `&J&'V9}mYk5pu^?zSJ3ݟXeNYlQn+v+\[l@R'C5TTC C.)sobc:^ Q%N c\qM!J}Ftl&Eh[JR9;==ddy^㐶gTeJGiG^AJxRo@4ް$JTܾ nGQ|ů}ݖi=^F5{oCn0T#Ɔe7֕ӐRTdtpf,VmlFRr32C;mDc' Zpt=, Ru.,,4bs3|?3*'BXh.2#Fg󓚤KpoˎF=ggۇ fGPvy'piq+ ^9O=:GN;B*@mȒ^NTw‰(Qvgcnq%&Mz%2YBZ)J±DeH'Nw t..1kc@!jBd9$y\e? 3 v\fvnȹ땗@9ǨX´%n)䐝d`)DdAۖ{"TV,%uo!I9B ّ<^:JkָЄՕ6ͤG (}ew dl"d4n 93doZ:hqň\n\$["{/s4g 2' o#!zVUz-];$]pV$ !Z?H68#Xmw $=E@c հ]Vf|O6M,}LrYlπ璌E*J 7rYy^޴Hrcm**h[zOj|K`bN\qq.cn:T^mkFR+ ۰Uućn-Ȓ[pۊ㶤 K}!G'P$a66RnN^p䴣KLʮWO~GKfx3Y'JKNƇfBŐJ* grv/c2e-쩎 ¾qVV$@=U/84'ZurCd_4%{೨ĎP0q)V OE\`Bm5RKr9)y9( mzwy-lsHF_eϱ7m8 Ev`im R[o3S$\{Vum$t7QEzmu/+SE_r4T\ZJ?TSmj(QNjAqrdz?ķCcՍt0i V6يGF|o-V Uo:ш *3J<%jyԗ7t#`PuCjЁOSr+v.1A+]FSI4u-IP;O?I立# 0`Dyx)JV]J%`n 5axbVJF쪯ld9ǢŝJȎZoNJ5%I k(` "qh+CkZG%Pgzֱ5>ULr]h7_`;!5=CΠqA {ڽpUWiMMS+QZH![n+lr4ɪm ԤŠ!cJ3Ȋqm<3. E;*9)=5ouӱb^.!r>Y Hߝ/zۯtbar#pt )=5Sl[5?:!-J}+?)?đ˛sxMT% dH#I3Rtmo/cHeo7)Zfqk|Xm6Nο]u_S1:0f,MɆОPT=TӉӀf`޸jiEP3w(s Xoe%'y 㶠v4SI晝n7yl*Ax6/$` Msx>?_^MiIAp{+O;%`һ(((B 飋BSx o:U?\*;تׇ<.#nx)Ȑc:=\uPAqR*P9>E`qICȨҀ*))"65@gR_9DO~0jBf bjMǗuĔHdAu.)+X!:Nh'Np냽]8{+_˸U%JXhKiK)qu-N% H%G}d[w+tJQJrPMGnxaS ͎b82.Uγ ̕XbG]z>81Mf;D&VPl(d$>cqCc=ߞpcBx-xODmFYqLu+>&jD;\H,>,H۲# kqk) u'NjJZ]cʁj[B[IDE8pX'rC&(n,O\5xC~NeIi`5*f )Xեo('dUSÜm<3–GڑHu<*Be+(אۨYRRIO"j) 5m#ÊIildiq-iKšY!KH2E%.-ƅǖ4J KL6)9Ju60TIٴRx krS='aV 1q*uv2.zp!T) Ӈb'@eX'IGIqX7]dJ:ꥪ)m6OzʂZPg_W%='::%!e-hcqWA8p;seqplrrum)n;Shr2uP:xޫ]a kDd!HBJrR zM\fwK..)QBs2;O\Z:krۗѕqYgЅ%cCZ59nl.BkbpW)u?N侐g~H8S^":J U<4pτ}X7+,CÉ[ua^U]oG(32k $WɸF"׭M8wJBDf!~,ȐM %)uRT $ P3&62X.ߌD;܂^krW!-!|#9JX #r 9QKq\6NG42A\l ('n͵׉? uo%%iVRmy@F>.h 6(l8:M+`(g I+8#NA2Qf&%>mSc" eJ$$d-J.-)Vԝ*+rwo[L&c]J)!Ԕrh:%G!"8JV R2d =1X.-Ttj`EQV_W~F㗚ztvn~zrN>*@rVkl0;iYdR )gtl{rZKL7D#]xO?`X$V<.rE)Ő9$KpksZJ ;um?%.Hm-49@88?)g?-0i,r}~n۫c„:o38J!s.(I| A+>H"ǹ6A(G7rH>mor6MX5 ;T|~!T7ßߕ.v[30|U)n0nBf~ NN犐l7.Sxo))8*9+Jp{D̩"#ˑ'$N vp1qno?dJ6%[s*;pߦ:։N!djRu-͔4v]z(qUu،62 p0 ְ֓t?Uۤx6 oCAiiqI#X':Uٜra R5( d g<A^2Үo^jc50ćXl/|168JY,q\،#pͶsi[҆\J)ZJ TBb;+=$*rQ,% ((yJ p䑧 HUvXpϪ>ܹ9+՜$ /v3"*zbW%! O|\c VMgԶ%:4ݶq9M`-gTSȆN iIi3Mrb$kgˊqHK v*{x4 쉶*v X'kNy 8ܑ{GÜGh?1Y*B:% VS_ A~ U"S-!s`KeQ(Tʒ9 pGu1<;V`+]QLʘZp{.I0N}lruJiMJ:_mVu'eG>)8SWW8 kq-dlZ WFSx:oaTRi :5cL\8xY e"t@S~:THIa!t&yٓ|7#68Z`$^,[wGh.e4PYP!:5!JB7vox\6měOCat\Q q,.&;1[elHK+J;BN{QRrk]ۮ7U۝aԲی!*A<\⩊:|#[1-$6fSpi9.}7 L”setlJQ6WHSrô[-\J[iiՀ vpx}XXp{g+xjoĤ)#CI y}FmM-N.H;: qDnZpU' yK  s:É?Zc{*{4sci E -}/|"'1/d٥'0zAyaVrݽ)ֈ-uzPliJQΖt]y!ŭ@>g~jj7;c[6ʐ#H 9$}turQp]X "p߅]zS&y. ܜjv, ĉ8Hͷ%NHBCd@ԲKDT"fLN;y{GS):Î> r<\vc ›ڸ ZF<XH.sdTǃfG.[ΰQd%Np'tUc1 ,:80?/Wwxh PEsz;W!- OXަ8': ҅)E ߖIp^ u Gn;ͨ(kq%4NRylv9#XgY5x})q7=թ:|@ ;g\m\chmnZwiU99|7'I<_e[ov-]R|a_VGp]OqG+yHoL`A @c+ۑyv٭bK/υ ,dHm -h@ :rJ>[KWܦDL2䀤e[L1HFI%nEtw*i"9ApGqWͷȈ3crr%EAi Fy·8+g hT<$`㲾BīCﰫT{7-{p zᙒ.I.J!(eLdV36C_֑m[3!uT2`r rw骬pkV]0mZSJ̋KS@~,VYnK%ƕI;k٥8[82TN|l~ ~'Xgr1e$ / $}<ЮM FtdW-ct⹮Gbh1ظv<1 ی۠|f&BƷ ) '$KM2 %($0 u06G5wgx^ېЩPiȾ;㒃`2H@WC3 P]3[^L6F<?QEBmu/+SE_r4T\ZJ?TSmj(QNjAqr IVU,mlcݩ9Jga+&[3_러A*a!P3lնK i>’J(պ݁SYjB5rk,b0i$$yv; &-^R:I!lFj1Jm%9Jk7ŕdQNM*)kuH5N:$)n()+.v"!Re%a @ Fu piqCTI̕:8ac% y FIwG9uGR-sc/u撖HRwlf8s8n*w:7ܭ ]i2#mnZ4+JRFWpċ9ސ3kW^Z\eFOcc:D`Āi)5djKW"א'^1!C/rnJ[je5<Ɇ[~b;ǐGp_xj̹+8}V%KҐ$x0[C.B256@[͹ԸYz,I+GV(X=R;pk] \ 2:Zƕgi -is&9ۋ%mkP呟=^߄?w2SJX1pZ3݀7ި}3 tUx>ji_ 9ѝ@cnG:mS !\3Tu9Ҳci4\_M_%dqUq4IW.cL-aJR}5WKj4# .J}WԿ YI4|* jD=^PEJNE2Kz *,z@>E~Y5u}'r.1dnVJѤmQESiW{!uΟ8-F6j]\ӫ鯈d0W-ħU&iUV,J x#d, j>LkZ!!HOJpbx'C@EMp$H: k;U=tGY Qq$k7nufC %$ϕ aR`6 9-{D ;( Zw?-EǼcM)H:A"Yxmvt̒r)uӈNumJ W9M1QIIN k}!![i&CjNT*Fdel,q tAzKLvM1t/þ,=5T+"N2XgcƔQPRVw`4AliMORP NUI-n@ .vmZWEW/psͼLVL%))IҰ1Q_3N(| '/Zh({cQ5KQޙ%:$ 6Ai8 ~aSl{ #]W 妋 Z]x?-z\WW^*Đ{;ät_}}<`-R0֭+JAN6sʤagIgeKSz*gC:^C<ڎZ1\6ڈɌ;]9oSǼd20۫h8H#ʼt;E<1lcLa8- ) `#sAmAơ . F\X!kNs<˦,x>x$^崲,x)vgf]53Ka "+35f*ijNq1,V]w [؍˹!ҝ Nuzh\ڈ$KS}wW״V9zWә!)'Xf3Bl!$t0├3N!GJLPaCj^"`<epkdYd*g'&ObpIZ Džo+FjWKV`8xz'JBD$ RDC{mEzEQBqLYéMFI wJ#XmHc8t (s}#~ :@o=>'0 EĜb:bS/ ̌_VCw]5E^X'򪄔3!@VusR/Ȗ@}RAȸJCAąxqIN& sS"jg]e6J`֩9ըCm$Tt˶-ϺPSe ܔ C;wZ\SML$%p%YVJl4|20BSXcTm_X()Cz^tbqe!%>b#-/RԤu5;x%DjVzډ%ɁqR@OjV&U xƷ*yT)nbZT()%Xlr1X(0j[:n\<9xG#erʲPrIIHP Yq\lIpͭ\xZaUR tp*lnǹ;nχ4]CIe$8 SaVjˍ&" .5,6QB BB=ТX!rb\7E9^ۙdYz~+9c&N2L/K<.Jaʌ VHGN79*E\hT\[R➞# 8)hNGXTүA)I>-zs9LbJ[$KQbPSoi̊͂-c\%2z,HijO6[}IJ"(JPS K?ėi7p^|Rؗ)䩕:)/%2HJT' ھj$<|]U;nwƭW&TqjnLi b&RԤ([gSB␥%Io $7dk wP %Oh >#%)ѐY*SIa/]r U ;S2>Enn3<Ӥ㺧-=4ci4!Ї E~cBE[ czи[[#.ㆠd=&@'NRRFyӕs29_s/ ݗa6LF^eYR.%Jn+:${ٶ=K-Y7o1&b]yK zBIִdryI>VG-Wa`1Vrh#?_YV3U;Hװ5~Xm}~~!'C*%OLaͻBP;UնD˄I- Zդ+;mʶx$_n"-' @JA<酃-Dq}D7mG;$|V#+֚8\o~{ɶ٢@u`T v Ҷ !*P9*br"J-Nʐb9i1mGh6 tQ{G-B:'TbCf1U-=b0q%@zr?!$6$8z8goq,Fԥk@Ry|]mϖ9K]=y⫮9} ;Uj.?R֕Z#'Q'$UXY蛄ZUٱ܉Bk1Ĝafu ]S^ I;mpX}%CP18Xn^ivD01K6i߽jUnpE|BͰ?ZJY[u2 >`ʫvkc 2P a)lyruÉA*XȈ5SR0+ĩBJ~˖76sH'vvd7 - q^nWs 9-'ZVNr;@(jQ9*99ޖmJOW^r7$t/I7 ɤ~\ #Zqϴ ZvaP $(I%$5%TĆVi#Vĝ!"GFΈ\shJa`yUcUdS4>ţOXjމ&@Em.JNJq*ǛRMZ0*l Xӵע8\KQEbOfsIq1m' JQ=}q2-7.(p xRc}`rIuvU^p&MxKJ C$HPv3YN]2`Dątw18)؍]LpAF_ŀՋ IG*ųTi0Ĉq]+B ;y b`[vdE)I|cil7Yw{|Sm G Jm|qam$}gU}O[JAOjiue4 PcvWnbωn٘NP"?@A*W#>LJԄ~‰^14b@爂rDd8kZ-EO6g|I|CaD# n_"0THߖqL;Cڦx:o} m.4;vm=%pFM׵fWkHr /ǵh]Jf'Cg2NI%Q҄<$|q<ى_^o VsYs+,[,l_ޣ2ZFPHjS(⫅TiM) {ILcfdf3DV?Iޕ%\7-Pkcmc<A]=AW Qӌ(9oT_q '?{C[[Py n7u3MۊIq:VҒ:Nw ]pTBz[O09|W;< ا+ic"-krSgC>2~7W iCהc MzRřBTi";d$7N ?,%"}fmg8Ji '܁C%"+ jVDZ[;o:%2VZYIKIz.A~:kJV 6[ P=QmzZFr-6޼ܳ?!c3ZBؔ]ѿYN[aqB'0`%}Oz sSn-;jB V-KGܸC=yWS{J#{Z.3cDb4fˎd%#+mf R|@@i8ݵnʈ1 Zj2:Ȣ+Y*]~JTE\įM.q?ZJ?TS\\xҝ?߬a)'9٬zT^ad)<Ѣ erILޜNX,D9\RHuڻM[0iܬ p0j`cS÷*t߉HޚĖP7}aQyxSr!-Y B]K]`FJHҟ$+`5cj0!Zն *Pp(,)DN_u$û<RQmFuY2)o9[a@-’{<ԹaPAGN˱uH$vg'@#=fȨ:mQ,j/ߟtd{-imajS1F74{'^[:^n5BEb c Njjd!TO%gqT,bggc[jrȴPUNs+#)Hi?`]'b+[#V穦ݟ "/nj?MNۚ$+ $:2Jn ՞k AZvVܢA)C6 6[;#zKAqA]By+!*$H:VFhΦқJ-l uHuО xe*]JFX[ZRi+'ӿuScxsVyg-=c:>Ғ7(䌃 VLc'>r4{J}W1ͿXK? pn/z#7jnD 4mMP95)nzWf#np@JC.'QYNI$1Y:!QOvskݙjΩ>SmA]:1zzg?vS `Od3K`!J@qY|1>GG[lמHSWqD*8+y vbhۛ!R֒I+?9Tݗxx+]韃- )㍚nMp-,9%X7$Nk7]K ԃjG?^v^~X u Xg+ v{S.2pfJS܍( 9FHjI!rM$9fE98~TΪ@+lS 6?-!8 ^|+;LZӆуT:RN|SGUFUdw1܌AeuJ*Y<s#y3.~Ϛp\G.U#5W=K$!rzX\J?c,'mp7m𜩼9;֏Yη?;Z zJbL,.dhkQEU kx+o+EфBvO Ɵ\ 1ԾG EeɁi9Cz nu7$.1+2P @ǣ:zŒ#IGPkYB҅lVvt2SwrG*\+Kh:vT|N)i5궦b5kA夤 =F4Iȩꮹ ˎϒ8*WSpyFv6PX-<ڔen jӱ=9;U-HƲkӏ Γ`lV5EH$\dVsޣNZ}:wV0;k#G@HN!'aZr C?b*r P 標/8O>I))e4S?Mִ] s@O͎Ҵ*/4=7%(|_|9֣Ya*qJuD(dg^hPGKlɺtu-Ej'QI*OniKr;`{tu^ Enb -D5R)${UtWؘIϛoMMϲo\vj)_-,c;?*5poEQ[I4._W.r%hu}ˉ~4.'QԂ?fV~ٸ=,[?mXrM: TkÌTA{oQ$LmM<fiqM{Rg}*L}/M('495sX YII]a$2krJm4.e8};((N9UNy^^$A T^JT{+AB ʗBs$ځzijJTv7i:+p8Hd|NShT)b+}6S>Ⱦ)CO)) ތ]~v140 :"Kx4Z:p rXy %-$`;D O λ81ٯy֔J[dnQj4r/Ӝ8sq'i-;} Xឹ{ ))nCi8@²sNX{:ڋI`IY яO*B#ԢJV[ XZ\bYV 0rC{,[mt jKt,xĄ~AVf[ H'U#%'=DOM7Ai6Kr> cRU|q` ێCONIr; \槠_:hH[!8OE|q ZI<_U #M[XKNP P7?b{!8a R{X9G>^+sV ERdQE!~otGKeCR.-^~!u҇7 ''oi{AO.t*5E(yes=.S((明\BZCrր6ϺeՍiY DOZpS?5-bR؁P,V,oHЧ OLM4$`\*aϿHҢΤ 5+{IÉ朾 *HWd5Fw(As:෤DJJB ],.QcI/ EmhH*9g& BRPpQR$ū9*Ӏ}9\F{h.SkSJ+I) :Ó4ѶƬ(V?5zBV) u,њfY(#c΅}%zG MFM/a[탊tZ \@Sm@ܜ%BԐy^O^rc=[.xA7e~OP/." }v\s|!k[t+qR9՘q15~kt}oWA4Wነ0RGj\pG>ؑ٥{ O's-)igQWكXÏ3?oE>< in hVN @'_> Ufio (0.N{y{+ %;LF?;[Ȩ׮ڟ'\;F{ =fRꓐP@۴ԕ|F|tfey1獹S1j p0ԭ8c7M#gӹqn"!j*;o0Yk%*)lg못2Vwp'5K j:@j48fv/A[mM O▋10[Dݎb tz%>6Um܆'Ɇ4+UԔ nRw;ְ21j[C72 >ډV=>6 rO2iɈ$R31;+Ŵ*TdH[-ԄhP#bNeWe8eR ʵjV eޝژmјe=\HF #^NT@2 Zf!'8 ?o9`迄]d['ʾ/#*۪BRFQkYܸɘ-J:uA$OMy)JkA8\CW.&/V2wOgp1ֽ0#H*K. AȠVA)]P:3ٹEC0{mR{Nbdo i*u!C84_mh(|p#+]q^uE.(U"_dq7JLtgSU\񻸨Iġ=@Sf\9'&Bw&뮳,H&G;T2NFj*Y;ө.<郤~5M*iHˆO*}J['Hŭ+:qBN|( 'ׇ\O}#`$Hޣ/Ӈ2C$j&&NI4HՐ:w'4*^ZP6粞۔[Sk)XP%IC#dG'Z2}yTE$r4$bPQ+;0;e$u vid1LG F9MdH;E;H:ƺlW04\}xͧɌvڈuj#| e⌅E ݹ]HiNҡTgYyƏ4(DԵx,}7$cC|~JӴE!B63Dl7O@#V;jE|*~ ;."4 -z':vcc66IJiO{'͑{'͑Ty1$*<c[j)%9H;;9K5sC\TKlRK>lUK>lU%3R1O#GO#Ifр#J/{D=Ty/{D=Th1O#GO#Ifр#V/2ii%(16Ї5dd+*N?cxOjkga2?+{:^ Т(( +sLǓ8UiQySiYQIث+HtoerL)߿v{-_Xq ~aҋHV^dz^dz,њf2^dz^dz,њ0c)_%h6G%h6GF2^dz^dz,њ0c)_%h6G%h6G)Hn4fϺ2H'\-h+ě{'͑{'͑H<9t7[|[0cLBee QR/!+v84=5QkԶ\QB-XIKs|!n;X3^dz^dz؅<p-e'X  0qaC^F[QJӨ+IH>HcqHTq2y/{D=Ty/{D=ThY(c)_%h6G%h6GF2^dz^dz,њ0c)_%h6G%h6GF2^dzed>=le˜N‚F@5f bcݤ6Mu~7pxʊB"(좃Ѕ=%^ki )9:rN2I5Z^dzCOe]EfGFVez\IRK>lUK>lU%3L e+QRY4`RK>lUK>lU%3Fe+QRY4`RK>lUK>lUzdIo+ԬN2@ 3ٓI[zs&b]Ȃ>N.Md%h+AWfAE{oU,-^Q~K>lUK>lU8bx scۖT!N)Hd!>]V``U6ۚ0/JohルxDcI1]aZrr>K>lUK>lU%3W e+QRY4`RK>lUK>lU%3Fe+QRY4`RK>lUK>lU%3FekKs,yjjԅ>(䜅 +'=!=lk+n l7R QE`uG &y~y\ΔU׮{\[kWF6Ҹſ+F4F?sQRY5p屔O#GO#Ifр#J/{D=Ty/{D=Th1O#GO#Ifр#J/{D=Ty/{D=Ti;ۡ[q)ZTJrv?&<ٺ|<|bFBz$1m.Ju+t+q^WۗI RDW+d!++@$ 㾩mDx07&K>lUK>lU,ܗ9>]s͕ɷdi# I$C&faTmK>lUK>lU%3SqO#GO#Ifр#J/{D=Ty/{D=Th1O#GO#Ifр#Ke{D=Uo3fûC,Ƶhk#6˳32%Ep%TB,ޗ3aQSXȑ:.#% :,PJqaURpW9'q2X_\s%n{'͑{'͑ꤳFjU||<|K4fW{'͑{'͑ꤳFh||<|K4fW{'͑m:q.4--')[m% ̤Gihs]M%]dΩ.4rn){I T^??|R_FqulUK>lU%3R1O#GO#Ifр#J/{D=Ty/{D=Th1O#GO#Ifр#R6̻\CE!7ҠjI9]|\Y(w&lmkpq@NBߕ(2mu/+SE_r4T\ZJ?TSmj(QNjAqsD8ֽY89L1Trlp3o ]_?mJ&CoD\<PWXނ:tsJpOδ޸ć֩k3ά=A݅Mcnwß&#R[Be5ԽTIV##tXY) {nnu -{ڔz}D*T뇽J$i T5V`hHnRڨHUv˗KjU#TYKjU#TYKjU#TYSֱ?"r? }丕(@W`U཯1^ٯ_ފ(ZKu-rNmJ8PP$|U=?p=?}U#UK/t5R:Et5R:Et5R:Et?BjJz&F^q.6$㶫2N78WH e#*.#iV׾IP^6W= z6 u}o?8(R pA'$aDTSV(&jcg8{~AuіWĺqϹs'uɀ;p_RSo~nǐ8BFTQNq m=o =n|UTrhd5R:MY/t5R:Et5R:Et5R:Ett(sҥGv:cN;ҝM5->=Jӓ#6Nl]J9Q@D#E 8X[e]D^=m8ۨ(W9 SRO?BjR >5JKjU#Tŕ7KjU#TYKjU#TYKjU#TYVndtm}iiZZPzg#9UmT!LK. A q*!2X ꮂQÎjլM͇S,`J|MzN2Rfni\wEl[a-4JRT|<> 4i)4.FԠjH/r&=d>'$y»lOii_8IXdcw/:HUhY't5R:Et5R:Et5R:Et5R:(.?+O*T~q- u]r=SRO?^+G:rC4>Ȣ)$GsK5jJӚz@A(R>0|ꯨ{7Ώbʵ`FGUr&mTjuQ"mTjuQ"mTjuQ"mUzmxvSvFA:QA %@#IYq:tir\ SL aHo9*iyw }&`䁰 p 1-2BP) Ӎc$3a]8-<p3ku֣CZR`aq(V0@NmLGoh[aZB IJ;clK\ob~m{6iNjuK,6>$%"R:Z#hh$mTjuQeQF,QF,QF,R]߸$ЄjQ펰/WΒ~W(R)\įM]~JTQrQj(QNi\OģE9 |-bx|- ʉJO2$'5VyIIШ#&Bn{@YGJOQ5>QVt_Zs*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩V^OJ:yV('5{#dc b(M] )SkCJ Sn$sƴyQSGL6=c^0\,k}%'(yIIШzBw}UʛoYGJOQ5>QGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YVb8ҷJk%Xga%eD M`"(袊(BOG%ij:iC^mZ娶U>jk}%'+BemLma)wRMtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{MtQGHU97V W|1q! 9RG"(+&h{0ֆ4X"("x*rv>̓%өŲ= 9ޮTUM$Gn *䉒 <;V{5>{MteMշ,k}%'(yIIШ*|ʛoYGJOQ5>QGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{MtQGHU97V G􌟬Y-v rmLÌ ''>sHUU<{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩MtQVt_Z7V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|pF\cpfH}׊zz(mEDI)#=dbQER6˗ܹ_*.]j-_r~%)6}ˉ~5 .xl|c b~k 8RIt3Oꥺm?ڱCnC'ORhQw5*j^:ЉWۻ`):6%3ˀde'O!zTBN6;ds#NFPp{|uS49H ZZAh\=G)EN 6>3]5LqHOPOgW9qg885-FEÊ;*Q''$vjqLRBp$=YI9I5S{{F~[;}5DMprOAJqB[)~jΆY)h%js0䑱upGrK8,la(+ $2Lx4ӡIi B|eV\m`BWԶUN5ԓu] o{ $@&E}*p ;zJriJxN1f)鯤?|7VqW]xܹ׉sJl{G0*c5rc-4V*q x1E4Ӹ-Mbpxv1|]4@ G~gk4&?{?}r9jM,H=KJYH@=wY=eF)$8kHJ:N#FzN C/y:x>iV5-M:@?$v~zA+L""$־ Wv`U큮]ʩ'[.:Vb"*KrH1c+US-2]-i|1P%:[1zqł;ߚ#aa|Q4nJ7ޔb/}v;5gn rSpF7ZO "PRahk.e:Ub,?yO%_ +.&wC='QGzS9c7luVRBV )*p{#uS(nN*t'~;x6I54684ټ.hN})?WS1I3.=\$+@iJ1NGhnU=V \[n#=`Z7XUd{`Ǫˈ[Ia`I;j[S}&e79]&;G)Q:G,n1X!pMzȤȖ%rN$B$[ӥ!2; cv'58lwkϏf\3PL8nhj C=΢qr/Jl(F ])Mftt6CēAAِ~ CI2[i*N7% #V&/nvtq%pml&B9mgsrwV]>Ϲ9K#{*fEV] 9x\Tn(:%CB;+oi*\ c}]C^/7$^7gi 0;Ӑp9{{*̧QHkF+KfG 07D XMf|oVM&(ā^ouy[4.VkG]5ଠ+K+P(nv=qjJ֓ii6pR|'~gkRJ&_Gv}QJ'EP\o۸nEexJ⒑99闤$cStú/r"}g@(ܴ%tfwt:SG.'aꔕtCF.˱=ؚ?Ek=86\TԱ^-n]ާ/#t>56?bX+y%g*~jUWϝ1tg>4W٧q+?~R8cSkwG U?~(7U? TZt$Jh!Aj?xƗH%_SƜLf|L?fq&%HX8RT0A" 楉T1S6ږnxy2B>N[1{\U>4 SIAV=fkxY.)+i+pqyCrq+Wt(!-r]i:j%Βx \hJ'+">M4!DTŸ$)Ԓ< qq/\53#gZ$s3u]G/>e^$ 4Y!ģBpr"~Zk +I6`7[eTV{nnQETV+doLQn?ȟU_C/W}M"bnAY,=0v6'VII{RIHN5 124uZН0C؟U^S}I.'> KKZ;Szcs榡@/ckhprx[n/Sfxk6ظBI|/>lx; (,Žo𝙰8e9ҳY)2A#l1ܴy.<<û2 z[Jrxndo/L+((U'*v#*i~4^UdKl_؉?]쏀'~i_9΄*\/`8#?Q1(@ ]EEV:ETzc]l}nI)pc]RRO!'e97n'O%/.Jxg?*u'vcZZp\܏xX^zX)!\*b7MJQr_8%ERlRM,-9U\8~p!)<#r>+ wiS|n>-澰BLnƏjj*]o%ql'姖n Kq-%UE\l3!W7b-tdmvU9f(iC,:zY.x=}Vl;R}k|Ņ-C d^̈>^Us2ۉPIp+tr1 Vju[So-hd?S'mgkW5éys^Vx(qG*Xo.$^ml xFwƐ?n~#qvvt&QK]C( _fTy],[0RvNjx "nkloRACk.g{mG8 O_ED^0 rӾy&Z$\pcl@M^'O3&z-`xq.)]KyN\~oXDտ)d9W7;olye+[w}eGM|XRMp,y*zܺsäŎw) m"mWiQ.AZƖ:֣ WpoF= 3>o{RV-(Z ؊ $v~7Yl#;;J8ץ97u\m0 i{#zM079 JUA2}Uf fxCK%gt2|"o t%xi}W>+Bf.Ro'Mw^Ӈ%u NDcd|yKq(8'n H}FMS8:e&CS/:tw-*KJKJr4C>cN|Oجo|x9~.'bp 7%^:TYq w c)mfR:TW-[z\XRqNpS}>Ezn.3bF5#?'}-+ZAi* ܴ"AmCH-(6`7X{Gvsp i6cY@}43##;u%jKc8^Jg4$ wFp: gaM٤UÕ$@JTRymSFcb2Xu`M)&\}Lk'{['(T(n(qC>h<Ei$ qlwiqMdD  )rVҤ="9~T[UT'̾^'ywmYՅ\gЮW(ݕ^\Y)Rw#ӫ8[.2$;kjm.*I/"nV,QXҬ)AzTq[<֋ĜAMw a )H%I.yR^w6'VZM|p7NJw6'S}]--ou攊+ 55nxotzTq~|og8+o<q|<1:ڭ]zS.('WNN=((iA^+GCs0t{xt9F3Fk_zi=춰۪Zyywzvc$Y!W.&XW"ZjgKmᵐF67~."F}MZ w:[RHq!#^1YU *rqE +SjmeQhQ#N.]9IG 7e8 (CcL`N;IuN M v/c MӉwݭsˀ[FCO"3H҅nA+o1Z5YRڗH:2n()vW:Ւ`U[4T2$y[IBENؚXEW-K{0VdVG*FX~[K6S yL8JvaJ 6)(JSܩjI"B1mY@ AK9̊jZN(wUWW!E-I=Sej’R{iˣʑ[zfۂ;iA Ï6iqtQFɦ d8o$dl}88IRƥ#y M_lǹʤ l6**hl:⒗8V jpfXb;6=ZUT;q+i N|'`IHJ-+ E)Д>6ߧuuΚ*" ( lѤ&K)le)u8;c/6%DkD/gɍ@'ZkTu9@ n 2CqOj75njDC=Aު}2$-@HB[:ߞU%(J-!);o [kN i[fuIqq-=N6l0vjO>T1.4 !8QÎ7uXKH1 d򩮷+ CvQEi=;L/<ں)#cAK p\lHmL+invs 6ˍEXt}yve:):HFug}bW 3qZIaͽ)#8+"}>&$R)RV r ٵRzKG,V_mkZS+IJ INl75a$Xu\lj=Ŷ3!pV\JY(o[:HbWm>6*xHRH l+p.\v1kBÀ&iM!9l-Fx:BrF%ZA:S*0;4[@W Ee.S$'nV]_;uJ*JJu twUjK ;=8~=xuCO5֥-xn )bx.B=-0#KsyG|jQ3,m/,uͯhe'!k_w-rd~| >sKT;Wǚ(a=s*PO wЗ$(o@CۭJʖ94;Gk \vڙo`A.*kqŨ$9;d50ae@k܁嵝C'"K1k3,rpkJX}|K'nͫRR8Xa{[wKB4`WZc?4O;=䟷<:h]UқNETi/m˷qF5QF{x)ݚ5 Ő2JRZ,W 0e VQfy^N1G$Ud>$E~qTcXӯqZնk0Kn1WTվ[n6rr9:Σ~JOFRݹ$Yz@Hrb!wqZcE@8ҐqgLz䙋\,o{UO)?j^ $] C<rK;/wFP̱6.HBxfE b Vݝ3Us;C*Vpߌ W{g`hxwKw_>NN [Kuo:9y$| Gqtnv\f[TXޠ5ҽY5۸1!.ьZ*/Xkbg 5AH\aʏ>kVh$ 6W# U?ղl ԧFR_Ůp%1Tu!ä!O\j$]!#u{0E)wnd:ud2$6VLuw%fh gx.6EujUꎂ7q^0#<[>viL d3nGrGWmWkБɲN J^;7́mBd4BneIr8TyWo[0~ TYkBSJylfK/0ٷ4ږJӧw$skk7lmHt'%l gT+\)m$2ڛ*Pʇ#89Ǔޫ{q9E7Ѳw.ʰ<2St[@t]gwDt}ye2 g:dy+;i $T+*^܏G#7(.Z^% w1WR`T%ub_,n\FhP܃4fdFzXU)c%?0,H ]袊**K7E u3${!( 98~8\ϗWg Е-  =c"Jn|1螧ӫF| )Qvdq]m,Jyv )G%X/@.lUe=g6/Z_ӑ %)_d. 1 S1XsȜ w쮄 ߰giKq0#|  h?.ܢ2Ta %$rqm>v3Fָk$ {3'fkjIQ)ӵz^2?mOa6hJCdeלKi؜d'ZLn,ī9Lhi:]dd+[S'Eds⹡G}~ˑpkNTS"kT)CH~S'[ncb-)WHARJsxgze{n >ϾZ[P8 u-nܞ0ot}r:.dpRTR3F=|s&, Ba.DBe\qž@ !$o NZUnQdc=#P$27TK# 79.qk4怪~5Ϟ}~Ozoʭګ2INs %GzbUJKs[an-+u)Q!3f}SQ2q$}uti *hq*->Ѓa0ʇ!d%iМ X dIzH{OxҖیtߙCy*iIE Hbk '{+x}|-h/11DJIX3v Ɲ 9HWK}|c70= -@$`*Zou}侷XdlIhqZ0Q,x$CuRhNnvB۫rc)$@p`: S )$$ j&fbܕdȩrOԅNTHd6P_\pc!'`1jȒJztB>z:D?/EU\qQE._r4Qu/+SEE˭E\OģE9֯q?-B>CB4Vڂ:=HA7,ݶO8?X-<3.R0 JrJ[#l-y ڕ'T++Yo @:sy\jmI*mѲ Ϟ_ R%I$%zFt;~zb7Yn&*|ӌwR4Vq5,Geu`iP aU6f\ !8FJpσpRQ0KmSx8|FS]i\Ì)xaA`ό4OZ殰k~ 7iEQI'Q\UyMt~R&) I6c9;kteXJS:; ofie+RR xs F@Ԕu9+܍A`+M3uoh>PqF~R̅/J# < |AЂ6V eҝ_|T1}T .ѡSoCTui҅/ CC 禱J uĔU9p}ZThRm%<ҕ!):WdΔ:6q+8I;ΦWk2ڴ>zY!'VGX0>iER< HP BfM_0]]d:Jн`eɝ )xi޻2(TQE!pwIﺎxJ^?,yqitIڤzSO83/rꬱ.)~ L`81@ҡWГ N͑n d[@TbR3Zr8xtoKYia+ i;kP',fnW+Kicyn-; ł^qH-8.7;Ë4Ũ%(m8Oܔ3| U61;V"H8jV݅(Z:ܕj5fР vT 7[]Y%?mR5+;l6\u:fTBR dp>3HyY#laZ9fZ\<.q2W絈ds vbpŎES_Y; r9̃Y'ͤ[UF΍'[k(u) zAobj7-NVNu{7n)Τ[@|U&\;f"Jon-A-̄G(lh9_x[m"MʹGO]Ce[ǚӯxo2mjS)()t8AN8U B#3;iiF9B c|{:clDFR]U(Se%(JTU$$oW8AWGt4CH^䪯mRNsn]*&)7n8-KrCuJ@B9$%G,Up9rN/Yo)|gz-}IJtVYBnqT=ֿ]+l%QEqi"'_54-tAڝL|QN mLƪppAcm+nJns+բ#d ^JBʖ|7:Z,4.-vdLŧTXJTYM;eSN͎gTXKŽGcs=KqUە2#֜dj'섖ʰ[,LHHޒGuV3C`>1H)Βƭ&0f-pTsrv.%Pfޡ *, *\eĢS ^8N3.n܌IyԔ pwz8\hb|4:^yUl!4BԌv|ּ&4FOSrsJ$@8 NO/Ow Ycs3=kjFFFDY:BT/:i+;P8 u)Yt!W,cOԞc_)]>TuQ^}k"?eAFt6MVYײT~ՠdlϊsh{ og\ME7- s!Id/}^.Ш))Jj~LJ6H+KRp/iu/$$SdO^ kI(*jj8Rd~"5F>BA8{R/p> 7aq }um \ultpQnlĭ*窔 [}p%-8s)XZ29 KjDzC ؒ+7o+"j*reLiɺ1-JLke :N\[n$#%c rx9#̭QX$=|n! 䴷RrWfݕ"n~Wdt6ksm0nir ؏ݢC1>;Vocoαn-:{TOmH^>[[ HC'X'rBn3ea?eEi1XJUȺ2BqJ5ޝjJh (j=㙩;ct50rirFNQ5dyiN3:ҟO08pyj&ъXlARIPRsق;Mb=`Z8ɹ+i@%V~^z#bJe)z;毚Ib4E%u~s퉸Lvt+.Y?W\xJt%+e6ƪ;5"X!-ZBN2w\8j;-MdJocIv"OW- #4ۈ9rk:HUmlPU' #ۢ|X 2ҾX @VI.#=O\b(|wt>_Ÿtq2t5r(~.F]?~tnSk.4t\Rcݸ9cR}!^ DëmJqÁ|^(j+\}C(oWcqI5E]*Զy$ Q LJ+e\1[/.1bBqj*\mBV|`AN綘q*} q %k % HT| oL-3 "*`)';諁M.DT-<;?HE@#j`3'P!*-IqՀ 8L;lIR;n붻c]DU8Tڴ$'ro\[ \J6;i8m'Y_Tz2z{ʓ}jTlg$avwKYFzp&A:h6P(90,Ix_NĎRi %X 8T6Ke=&b_ D9NE-Y i+!*QzQ\9*֥rСT7eS8Cl5ZѼft / ޢ@lwYP+i`~HqWIz9rBa2RgqrjKKyz.r(*^]WVn_ꄮ'QyriXA9ww;F2em|5w=1Fu''cku(Z5mN=%Vxf nWjC`0yw$ro[ g~-m7w]”%mrmE`;*oW! 1؞[R돩S8oڱpݾ;ϰΏTɯKupࠦ]ݭobKl;o۳Yv䭹#k "Dpg.<*5 Vn8J?mWp<ń+HljA_uج\V6qe !*)#gͲiCɑāluo)vd&4{nzvR5r!4HIU9s˕m3 t䯬  5;uBTnq-_>ZvD6ˊnG}1]{44m3VTm82!w[q#)-%ԥK$('$E^d|9箲g[{``'mTۅݩ-xxSO"bxxx;aS#*JB ^r^+wcc+Ou.)P JSZ(q N9dlGR3i*(SJp{9wy$'5ݕ>9۩vѐƴ#3 xuQEmu/+SE_r4T\ZJ?TSmj(QNjAqa㸍fڥ[AAuCs:rCcc8@=Wn:+:F@*H~uG>p&A> g'm*xp 5Nzԩ$A Rv;`SA:Uc;g*#]GE eN`z$J#R|dVꮣt-h}+6\% ?l),n>v<;|7U*)TIIqj2.qI ,kBР$(cH8j3 e!]a i-0TdaAxz۱q1M; kOrѣsYp8ԆX'8o8$fzF +s^T N0U7رsLNRK%+ P;Wz뚙)JCxܟ>0IkƄ/3)]M#:g)ۯ63ͳKoSJגHŊx$˹(\^(J\QSH=1i!ia6nYÁg`#U^a=RBNe|DxRh+ :S6&hcJ{pqajpڣV,NP֖U-RW %wH;'~uU< + QZG{ZRd%ERiW{'_qM-hQLtG+`n"chQ*V1oi1wгˑ`oR*$nZWl 2R7zsʖdm`IFXR5gNgɹ!}5Gq@=ݔ1£-gk9uAUT^ˌ $TA7>Y{2Z5ڇgR[{͡ܒ NB zE'uͫHl#rE;s5 ;m4@kBrQd#8V0rG\Ғ|)/ޥkP+8I۞3Omu@!9 Z8-6(SxA Xӝ3[bIaLiҬ?b9qOMdl1nns6ɹmؽ7;je,܆C7ȟ -cwSnvٲN}x>wN5,+$3]+{`aZ\Fx-@vrL]Aտ.X\KJlGXZ |)U˘qY|ݦᐹG2kUUA4TRɈ.Z# HUʝjmKeNCa297 gR-!mǞˑʛXu p+ JH=Iܶ›!16d$8IZN:>zom?Ʀ^:f[i҇ yΖ1ԸV&pFwQJQ{v~m$fqk#qW" ǃ\}=jjSS C9J+$e'R5VdwP'#PРoZ8"ͅ52[P[*ym(J4poQL׆cNgK콩9:XFfy'wgnQlHm$:[KXLKRA ڻm+VwnyW(!p!F&!MJJsݑ~*3߽/N\b/A4GN?FqGYJqs o%r|Pגg>cq}#>,MK2RtD(aZ~ # q'͚ϒHFF~ ˍ_X\NJ;MЕi lcm!V PQ rryӈ*N^@%%hmv6+_L@ݪPq \9.?DyjJ|<;U5J{=kغ(UR(/) \8MX:RV:N˪桊vN+dPsV.&{cnhQ ֣ ։-e~"ÇpwGa5JtvS1{yRhswVӭ5"p RFƳ9ЏVl֕k|tؚY}Fx̔K.Jp@HrO-V8Gj-Ϻ^*uZ6ߝhS? !a.'3ao:6o8GQ095OjS,DJT I؜CcSds<B3;{oXY=FZ诡E9 ]%Ε(saTvJ;.x8ggZI\χu/\U ÑP gX/ےrB%HZH S0T{R=HEp'.R3+u&1E7骅hƯ3B PZ~/| ö3pՉr}/: >.4 ^t7ÎJ~|ǚ8FTY8V0gnK(*X_M$jZgj1PYVJOUlߣɔVUݩќQO|Gum2%-Tqeq%@Pp;M8g2E}Jٞ: BTsX%H$/$iΞ¿Z\WeBކƤ}iӔ$!ᓒN7M&kPfW^Sa`RΦNXؐ|,M$]FV 墾-"j#[a) a4ZД+b,DodpY&t1iXq=NI$$xۂMPl٢Ozmզ:ҕ.Iʝ)% H@$M;K\ r;cJ Jd$PsJ ո4-knG |&h1<,D <Mr?>"~3N!eZk'}ч:f܏oi XV { z˖]mm\p8TB9`X1\7.;έ*աNJ#$ IKljwHͶJSZr:O2Ov+RQu)ZCҥS4T[0]kxLf}e=A`P00ÞUNY#%d>yRib*"{[RJIKN6p |3{bx%ciܤs8"&ʺGѢLx>uͶ]pպ9qr4y+;dv`rkF}2TƐ̆ҠP^JJ9;U>U q-KydZWVbc'mGqYYv&e e sBT2Aդ4n,';.ƧQ!@] KJS@ N)k3:~Z.se+mN--%>hoZgf_lzaP\J]-Jy_YQ:N)L7+bxq5<;mZZA^|pHsqT6nz?+\ NeIRNcQ;cˍ~,&+cZHقTuP7):Z->8!1ӏK mώXT2RyT8y% Q3uǛ^|WXmK6+2Ou)oVN;?[tW8N9]'ps~ݚ/!,2#5+ci 3=Ax%[Y@%CkJhWI+s񺽳їG{)gX!|QK<IH)*Z)G*1 BVړʞƾij^IRDvCn2Opך^:4PU:G :ݪw._ -D~ҝp)l.۩"pN#DnZx"m˭vZJ>%ZB vrmk$Yy,#i=YZIǤӎ? :DHBJ4KFgp4r;ַ /3kf_Q5v&rgÄ$F/b~t5"8y-i<`w!8Z6^eƷv&*IqJgEI ڮH~#y ,(q,OK-')wPZFjR/F;-v˳cXpR5!O͑e{~ii%{@!X7~&hqPr%A2uqGJТw '"_ޣq%_;<ΔS-TU!x-:2#',VDO[c)nVge eX't4E7Olfp eJB$: nRO<]toh2l-گuAaX=2t;Hޚ6!\mSP@QV sR8BUcmF'us\8ru9|sOI*H,mQEAZdf%x9Nq,a=N.*|2$ ѾaDz;S9.~V^8߿MԤc\nw(mLI.G,u'\%ru"(IHX*o<9㗚9qxGg^Ms#! *!Üt4@Z;.۞ӊz9YUT&scp (^ l^Rێue]NǞ2SСiSBs9%.+>ѴE}!2tH0ϚPcDR_Y (IR5*Փo5igaq=~Įx{7p?0Zz3@ۅn7d!Zb\[%4 )$6[wT6C}CNGczg( :?yý.=:*1#|T!c 6*/$\g%4r0wWG,^$-ֈoȹt˲KHTzMᙶt̃Qeĺ(j$wˆ!C`v5ya{\\~)'s]' '#LqL.J0mRƒoCܞUR235Pdg!ƛCO @8=Y#8aU֗8ik QMoHk*ܳHTnا>ű b="'㌆lG$| }I6I/ )JԬ)HVN5aGlp܉_ưɮ[)7ZK`h8VxzÎl"$u+q':czN-sIGv +G%,-:+0KqWL:"I7%۱L bmVTn-etg"$"E G=X;/mn~L!)ԦA ZB)ʡu:]HFPo5_nKgG?6aom)BT7$c=ьaT`3nk䅤sI粎|B̌\sZ00p/f):RP'N÷a\k7 iMC-[/;V"˹LyW)H }Ĕq O4;=# LIvo[ T%Т 3xDd77$3fJ"%26HHsQf-OJ@Bb~6D $[sܮv-yS!*ĕrqƐ(:#Jw #G JȳD,x+XwN;T'ۂP6K.uJN6Iur4aPWYRƢwPCw XN?k=yuwDo* rpڈYSj Q wG\j;C2xEbN˸du{՜@Hש\zZON{F>,:!Ð\/N- \%p,+ 9BtΥ Ɠ)xŊq7=ų i۞Kq ;ADҚp2F1ttskqGHNEo\ĪZOA@:w|Tè?!hK~ʡ PQRTp9yVCIq:BUİ)꡻7n?MiT0刹pb٦ nZu}Xp՝#ڳXSmO!T9ћ3RR J0p[ֻ܎ KIIR\*9>oc6g^]}d{tXnq YpHu.iTꖔ95ĊSMqey`պ ߈o6XbHJT8sOm*ˊNOSӲDqOԤ%_!_%&S,m,y<ՔٌVu/yw Ų6Tq+Q9Xy!9/z;ZeGfv߳jrFg\F#D'Jr:Sڞʂs[#iiӾ3LҤ!A-) {ԬG43}S]_\\ucOܣ|cMuE-VnBbAEQI\/?1_eI>4e)#}zd[F{n5|Aŝq$F[Rn䭵6Yd4% I|۸DbCnkl$6l@-$>]E@۞+lu/ ;%.ͤ0t f=cs1Jx^fZ{ZV԰ ؁f&ʊWZ`)HP<scNoTWRSdcEz?c[]l\pY*^9igT]%c&QI6p9na)RBΤ2yv` xJj\RPp{W.esADm(sO=bF@d۴h榚+;)Wp *׎g7oH' Y ' %_jko$&{Sz cR]Ky^?Y',X 2dݡ[TnB SCԮh)w ;EVEQBtqX]VmS+(`]V +4;* 'zuh_},6V($[n{j10xm*ơq=O{fit\>J :&IyR:e. : IQGy QKq$F!k`XVF [͍ZW y9_b:Yz@ iE@pv_Zk|ೌ:{-7STK9Y {]#JF`&kADjY%;9uXMFג.8xT;Qܤ< K!Y<;W-`2i6FpB*90*0:R!+r+/Z_RR3%A9猍gG,W-{VY ycGװ9'K;HrՆ{l12HnHX*)JmQ@Ҡ4 19Y_p*οNyoTSdkl?/+ 06ZiqB ^c6Td%Է҅9#oھEy))QL^*v8S)JY̷tc8>ߊP;cwm%CCvz3"+O^X C ܈&[; ,TRT@ؕ@糕'LW x)Dw‚@;bK+lqF6ifRJ:TBtvWM$? !sH˸-ߖcQN)AJë+W)8#o^gmLr A` j*"684dvNqZԠߚi $eq5EyX6ϻ*F 0^z*=4:iuEŨPPnU']mbu* f aа 6tE9Xy-8$Ҷ@Ä_ԁ`39} bbu,[8y,xRCR8 `WseHA^~ ![NQ$% J %?Og9鐿f C#,l|F_3kΖv gRKQ'jn#({Q):iڵZZ})ޕcnخe'AjpgZt#RR\-']QE,E~H_ ]/dj I<4 y9|DJU{mXJ-)V)Y >ʐl$tckT TPK[j%HQI=JVsQϧ<4OAOqڬfmR<`4([9t) ⦧C)NA ݑYo]JK`ε \.pío&br hMLr#(GP|NdBR3ӋBHYNtL2*!?#%&ǘ!R&)jCN5!.({jrc,16dh² $iR/DSiAI2z+[9(:3ccpR+Jd.eҔj,plCxi%%J>=ķTky~{UZ*w= ޑ9Ա 0Hة_qU}JYظpz+'4dnVPо)]<Ϥ?Fwqe!XH8U72-K:<}ky=QZ'$+RקQVFy|U5j"F[Hަ(KՒd~ )I]Ryw 5+Cd4g=~+F՟|(+_h #r]ueQ^y<=Ei'h+W\$vj{!K]\^x?͢wqNl뚸M m~}ybrl=5fo%I*Y}ETYWv6h|a}Bhlgw_to-7Ѱ-%K(q v?!P1%{Si`8 *b1eU;ޕu|Ŧkq2$ɑ%L>ZZZ,%ʘV: PFR9EB)IZA\C>,<)X\ZGVhntSwgJJ+RPyo=~U-p[R_%`~ޢƔ<-O,pR+qGTq%qmͭ [&,.21\a|+܉K !Z @v B,ǜ,3)|L8XR]9.hNrO< [룄ևt%պF5fj:}"aN»3m^]R1RTió$/) g21غaW\ըC1-mqK}z\*'=p,'iJuƂN|wqe! W"L/b;!< ɈQ=wp%|'lqԀۤ%Ă@8_/|;pCw!%Im.{<yJq=͈}$!.-ZP\;(yycppFOF;"F~jK / kBYvR=#5\r%Vm}(4i믫 HN.}r\Kiq) Q}[V!l~{ӑެk;kVφ$H*}XɆ@-<3Ȃ9wu[1Rt+,NYiomJO(?<祐qװJK[]xOCG"()dGDRHR:51!Ӟg/*>rr~:ךyq#Ep7EQPV,/`a\3DC}U1H[Nf3,'Wc9{V 쬦J@) /<08RH ExP%<`we[-6+m.i6#@_#9ڲUũOpՑZ9Y%RmQ$aEX9'F7vʐCz3J%]-JED9R[kuS\ h<;heH !<$x5k#sL#7讗%seNAD9&u7aDe%H(5$EW U$M$z1ʽW*L[nZPՑ֧Pq;ȋ* ʼnT5wIa1g]"斜]g$+<ݝoOr) z^|?S͕R֫},D. {r:G^֖ Q!ˆB+mչoXK>eV0|!9 VN[}ǚ{{*ї12&q0%t%Ɖ$RIە}f?nnX0Kd~m$b( [ܧ#ytȺ VO Ht̘ӱ D `c}/fҧ1-[n9Y6Gvʖp^0 㦘 NNt;nطE\(!- z%i1h!jR4 8GJKF3V>nW}S!$UN7*._W.r%hu}ˉ~4.'QԂǺum4ң~.%kQ %J9w s"!c*RjZq؞2ssAEפ%?b{J׆|笾o#[|-n pڹ%I)9 XmVVcuR$o楔Tg#:VJoM::XS\im.M-tY{':AO׋kʹCThjP'|aIګhQgK,97bϼNlPm&+kO-1t[ viR?L}Ց~;{P'h.qJZ[&$wHpނN6.qnG)RFGӫR¹4#OE^U,J WǗ%:AC)%>0үIԯx22n1 tk*HeYN}ʴ6+ПqM8JHi. TTFēٚ?ӌ N* mJҢ<).n2趧B"ޠm9nb!ظmI S_'~4KTL[5(5%@uaU#JόI(*wv$ZL(a'`jWs6 un0T䢕+p;*dϏ;2 `RW ֜eYHOa4+P񎤓_s\I]\1Rr:F# cqLһ VÑ%ec^qNTrZ؊#؁@|g= eJB%)) :OSmA*QRz=5s]nA8Aj c IR) Rפ2;3R6EhpW>\x]Hv*ӺBL ٦-uܸN_AշZ!mCz(Gim=C'j9^ڄi%h9m@`yy,rC9%'*5P~ "NZ˯)4696*ot]+6ZJw#V%`lF2ڌ%K+_z: Tqt`ʝg Lc&<[u AUOP)8޸nlTGTˋ[j[}bU9k>~\%3QfbuG2V) qEnE) Ͻ4fk2ͦ/싉 *NAܣ'db:+ \v7rByJ $A#)}CIS#V’!CcgqC!sRII9$<=-e-y6>3yLmu{>#U[Co>˘L}F ;lHeF)IW4l|ԔT$% YBw8A;s6jLHHGUr _S$sXTo8 '͜Fי9;j(wpo=O?ֽgH+uKijاU? i (PxȮOd`,Į)(ug6Yllb(O""VU_V.TgFWҌp)YLfcL+YWP9ڛRPO"*m7Ӊ# ԕ}ƾD'$fj=z+ \OEK2ƕV'c2 [AOn2Aa^ֶ2b23u^&(oFwڑqS9cQSH}4OFǾHTT YmP%@ڽ;PDĭ9ϢMdܱWg2V9s/ꜿDkmir'0XreSR)`']]oyUQ0(_+ө$ oKZneHr;;S ԃ]2ҼvSBebky<՞mݛJՠ!ެ 9Tm Mgl}L- ,WC\ё2ڊa Xĸk|)7G@}h=廻4ԯF Z 9'g>~=%. 뗶8˚S.y *93IGQIǦ@I޹Oh%7LڋqJS߰潨IҦoAWy&|waH9>"ao/D Z}(iĭ)*jm`c'ӰޫovCu47In>ʑ>7ڭ fҰS:˵Q ]V99j o<Oz] pcf -`z+H2 R-Dofʽ {eiN|/koV J(EaGÜ.@82<5|xK8JD)E %.xy=/njZB3Nv?Fc9hu=9 %+N2> .'*q4S@جM],AQJQ_-9[82z(q㪕[ )̗PRo#JDiNxBc,o{Naѐ5ّ% A=4(V`.;yJPy*%$s(xΖH8ޝ8Y?A !ԅ!o%`I˵H-4T/q^.Og/Nj"4֝u:˩Z\?MEsmIBP_)qE n;E7 ]KisR2 &-%@N 9w'v羙ե$h5rJ@v*-Pbee@ }Jё zSv"K/uSa^ +B՜?6tO)d~d$7FXqMu!(V%vg5J-d QE,Mr%h._WZWܸGsM_r~%)H..Sd1 I \v%sێZ<ȒɆ @# ֍♶NmQYj;ˇZN"@8 Ղx$8RPI$O.|PlDk7-JW-vgI+ݔض[Wpԑ-!֢ҒPmϙlT ۄ Fiix!Iԕ]fҧMg姐Zr-ץ1H!)n.N9cÉq䵫Sel5% 0FaSE$^xoϏi:z|vWnbĝ$KIm:JIʶE=%Z&DpaI mVrP[Փtü_hkq ݣt39';)lr'9Qsŭ)p$OAڒee A#r:MM0 _ۚKt$=F.ƖԜ'AiґiKZ)Kq7l@*C`[8e)eJ KusBPǕ-!-&+*% ~z*KNV]'5kLD TkӖ˰.c(֔arVNV6]o.\.S'IQJ;3&-wgٜƔ@GTT@1:9,KiS[HbSrv˖K<\h7췪R$'R(\Q ƛ[GVX:nBbvtKitudc|n[ag@ umkHijN 6hlSZtAcoX2RPuW5;}µ*mCOSel'p6哟5,r &_oO ȠHp)'?;(z㶇Cd$ڬ  ZUxXbYn%O"$l*P {~%@6hwK+P#;S fk\42dJ'}Qnpԓتj?B+d .[GMqZZmtR:(v9k £M,hNܵR֢6PH# lL%+YS%ls>BjV>24]YQs XyTղjuRHG#IZÛyW{\P~J T04 5u=KWU-(Vޅ{p:(A$W`.] P4DDria7kj9WEc#jY8*H);k\3SY=/(5P"״,@U8\X ⽅ }z ԻT[zN4CլjqRTi~ J-JQʪٻ]zX^?#h{G٪'$"X7DQEJ+=j$U_ͶCzSw[rT>0=$TN$6y()$*a7EyM(q_ߟu;CJ ;w#'TY7R:kMv{2H5 'xI ޗ6W~6X+'Im^=mL*+ZBR6ɮ[pfS, a8Sa y-)G$pސqZkRvrDc 6T7J%MR6Jr<)6rS5kb%ugZe#cLBQWf7R kL88 /Nr0r)t`7$c`O餝9x tPJ\E'Q2{jk xQhڢi KN )c-)d& A TJne985տ{,ycEРqi}W_p(i-V[>q2pGKfJ}?OO?AVHq )h IŻpV78ګsIOex65Y^FX"@^ڽ)dWߠ1"ђ62Z#hHM;r` $-$vAb,s[*ʉ'ЂNH Gmd͸Rl.Hu-qJNԔu#}r9O8vSWvMX7P5,A=}3o+JOhϹ#⯢dfB²NO%$I;IJ֔&A:uRR4IDC d&9eR%&xCIҎ+I:Ǟ^ W5rAkREV-dR5o|cqTZ{Hh@ZNʘ$jhbU|'SZ_@R5"We$vy嵭w+/|W- NQO?}qouߢaIR|o;ˮ\!dXkp*5 uÏue5̪s'0[7* s^p%Rl1 :Fd2WEO+6h~(6'smpGH!+R4aѽ8v Jmԩ{9n rBOb2=<2AZeD8a*#?ޭ^zQEUj+e{݇%d2jY2;Ž WEx*ʩ1J|g#JDJH'W_w]Lae޳tr jm_z?C;V |(.՚:+Y9E$W~U$/P-eUFQEY6˗ܹ_*.]j-_r~%)6}ˉ~5 dUh(0 0!M.)kZ|aX 沏%h6G?diHlZfH(c/dq}O#GO#If֮񔯒O#GO#Ifр#J/{D=Ty/{D=Th1O#GO#Ifр#J/{D=Ty/{D=TjBuoeק* uEVZ$kJTND! ly/{D=Ty/{D=U+s٭qU'&#oʎʎ $Tsnua_gTmթ9GlUK>lUɉ!Q0QI)ΒFqY4*\b^dz^dz,њ||<|K4fW{'͑{'͑ꤳFh||<|K4fʵtiyhKO/DyƄ8u$lq ]L9W"pq~vOȮ{W[;^חBNQEyEQ\ӝdlUK>lUJAˡ`Ƀd+(R'Jx Xcy:\&ĆRJj6BO:[q qܯ&韒O#GO#^)Φk-P)=r Tt; $eղ4:ڊVAZH،AE\GJ{'͑{'͑ꤳFjCJ/{D=Ty/{D=Th1O#GO#Ifр#J/{D=Ty/{D=Th1O#W/S!c.ĜmRpRږ6 5n`;!"kS #Tv;uTWGeF.Y*.Ɨo _\]N hm-iIӒqIגO#Rbߝ+/r+582/LN^dz^dz,њgTc)_%h6G%h6GF2^dz^dz,њ0c)_%h6G%h6GF2^dz^dz'LK|W%IX% 6F`q N9̝JӜ3DaZut/mK!+AZt2 /,p/k~B)dh^dz^dzĈkܷ qN"C%A J#$')xzS}ttkGoXW#Nq+ 2s^dz^dz,њUc)_%h6G%h6GF2^dz^dz,њ0c)_%h6G%h6GF2^dz^dz,њ0c+\:^#dST5TTt- G$/p6V\q9G)DWcY\#p^a\(+k8I57{̻.w&CϒHp Vtg rsا+_1Εf-^g70Y%h6G%h6Gk/-||<|K4fW{'͑{'͑ꤳFh||<|K4fW{'͑{'͑ꤳNm.n rmcJН(V@$g}$AN)4'QTk.(5" %+mituRV[\ӌE5] .ܿHJ$2[$ YZ$T7Kj ;5iQ7^dz^dzg-6!lMk$+IRH$45s oͶ*coĕ^dz^dz,њ||<|K4fW{'͑{'͑ꤳFh||<|K4f[-'ꭿy6%be5@sX)&;2k l^ q~(v{}ؒ;4_[ۨHKWiV^ฦI‘8ʁ (Z]Cth}TMvqmlUK>lU%3W` e+QRY4`RK>lUK>lU%3Fe+QRY4`RK>lU{iӉqii9Ji(P>e$>#MFkgn.=['uN)q/qMHH'V I^ 85'RQE(Y/66;M34YIXo@ 8(Ie{D=U'ßYw5gbhpjGsNjoJ/{D=Ty/{D=Thn` +J/{D=Ty/{D=Th1O#GO#Ifр#J/{D=Ty/{D=Th1O#GO#Ifb"!C0dH+2OTFze9* !;8G.cdA6M<|<|X75Թ-nfRh'BTF$$`d:i"vIny Rn0E% \b^dz^dz,њ||<|K4fW{'͑{'͑ꤳFh||<|K4fʑ^eئnPr) RN0A:G+?i7xkck]O.rTQExkܹ_(˗֢.'QkWܸGsR ='!3uViq7Ԃrڄ%]Ij<"_<ڹVIޖFGUV:mTjuQ"mTjuQ"mTjuQ"mUz`8V95GDD2\BԤ 4IƒNYqr"9HyZPHNO~Rr5eؙcxd}UnjT2z"yP҂փT }u7$<^KYue9Xv*o@+sT1w)jJ rw,L 8\o`3kvv{v1k߿^ԥk'IV:\=Q$sHjuQE@rFGU\[UTjȺ[UTjȺ[UTjȺglqu`muw%ĩGrQEGerMG*_vksmƺT)zOR|i#QiQU?UTjYxQF,QF,QF,T+YX*U- S122>Éq`)' w\o q5rD[,)V)vqSM8J؞W8q\{\yqBc7 9# 2$JD|[[J@ ';$ ݜVvkq\܂o~gLW:#@@oe׍TjuQ[UTjȺ[UTjȺ[UTjȺ[UTjȺ==!;_c;N/&vաJNR>=* tU| lc(<=(~\Kո1AC I ?kv-6ڨHU{{/)t5R:Et5R:Et5R:Et3lOLD*Կ,ַ҃8*jHBdYtiR HoQQ 2mUtsV.fnl8ڝeC>BSkqp}fWB\UKׁf*F[ScNJUF:Jcfuߧt`Lc6Ě 6d<^J4@I9y$mmMVwG8:[u7=-A~xWX5tJC.[b l6TJe'IQG[ILP7F1r0w΃U0@Fi{7Θ[!!9'66ض{b{KNBgrJ#CyFGUB;QF,QF,QF,QFEu]9WӌYhK(*JZ~0A_ 9KEQI&8ßėYkUlVT BOU}Cټt~?vU5R:[Y7KjU#TYKjU#TYKjU#TYKj`nV÷V4B -jPI*O:SӤM[KZe @F|ϝ)SK˸\g~3G$ VVdX'K]lB%(:H^k OY mqk[Ҕ#CB0sn&'b8{B @ZJU ߘ߳bZ{/l5skp OsSr_F5ie!!)FЎ1CF$KjU#U;(-T5Qd]-T5Qd]-T5Qd]zv' 젭N$sRlxluwzftE◩Mr%h._WZWܸGsM_r~%)H.(n+kDk彩hl6TJVy$)?GJOVE1\7 o vCw}?GR~i *|CSum =yII=?GR~*( 1G2{5>{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{Mt7baP{g]#)?YGGJOVE3}kcT[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩MtT[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩ ¼/cላd\)ʔ9)D_53EN7)4YQEEIMcWd.N-gYPmIri"8qW$LYڳik}%'+B 1T*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩?de\xzk[oBfdm8<iĔ NRv RWWxT-G:Z!BR+ǴGJOVE66XWyT3ǐYGJOQ5>QGHU2{5>{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{Mt*EhUWyUGN?ǐIe!Cm6! H)J(+;v x!ZAoTi?YZUS-LHn}?GR~i *|W̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩MtcSIل6H\W- ŲK~PIjb>wfٚj-c1)#;vSvf~~wQT4-8nWZ#="q͗Uw wOV}-hxntS(芒0=JGVY\;#.H5."Ҳx7~+}6# h:Pu$Rr5rf4rme%˕c;[qqJ4#Bdl_}0aH>0 q#:F4Z>K4fU4%(ǍijNdʮwN$U>% K:))Cb8ѐ)I8/b^zhK~(J K6Bv)$sҎh%ǖFmlƳ N8r;Te[x?\I-C 5h{kU pR (9mp> uGZt(2c;N̅}`$R+ qYlke-!f O'H YoRS/j|X}B NpjIA HϸJ+qIBp}ܛ&3!%kY:[D$m3^..0+ˉ uAlo'<vsj澁MAH M;1oF_O8d] e:qxqfepPV4d y \',rfDw0:݂IO;_SmIВJV~ v޳EeN"]#ϪŠtўMyx[;+DJ[lRFRx8zBKy.tBrAc`ikz:dȟUY`{FSKmkPJ%Dy<n. MΘ2'Q_LꪢGlr տlb5m^L`rAOF=}1dO DžxC/ot6hVl~Jj7Av*p=]1\aT}2dO9wljf ,<!Gl+V^ʽUhn6'RCdOe}R=-gwа2F>J^SdODzov"}UI5!Mv<R|'aՖ'"J>jbcȥeGfN/H!vTQcĦxFC1҅ӌ!=}9‹i<2lXhu(Ԡ6QR`Uh^X/hcq)Dtܾ-&oqY^#.&[jH`}Q \ؿO;oD[C_x!Nri'l731EV6_ ħn`9WcqwUlm^#9ҞyQ!i)TFտ[xP9+uzPZ5W(\ERq8o+g:zNГ!Dn;jYs>CBuڛ䧢ۆ4$j ) T|EǍ4gA9 0:R3eZ{LmN J.@@s 닁f|=yz{Q$4PU$Nquä\u kАJ A(FN1_zP*o JGr?RP!dF9P떺I^x~utx>ǴsMɑ־h m|&qaw~d c8S'E>okoBr4f[9KiÏjXg{~Jނ@!xf~#g5g #.{55>kj5c˄%##$ vޘŦ\|ՙũlR; dկ!d̚m.ǖr`+: nO,iN5!q:^iTN2<×!J=+ 4.+x'_H/0xtcQK]buj=IM)Re#,' qQLf9]Uh)ZJRq $߽.+[48ĕFvvk;\e8GH#;Uu61=5!m%)'+#a:E^FWJYmKKJcBD(6 {PJr{G`# *@rg8,*t$RhU% 5!QEMEb^,-< xn&\eiqI,diƵrs۵5bӳwg޺[SZ#ZN>Jm޻ajm֕1hZN T Ȭo<.(nɅҔJUP.mn^c8ɠnѫ4Oiܤ% Y_!2*nIV2op{ zkNTwt_%(|b[#ŦXZB.|AHqWL,DWVGH*RP#[W 6nCplD1ow&;=EdqVV.}/WRB<3u |m9LR~r|-#'C]* Gp65ic-Mu=a+6t҃AZaٸ鿥xt?[uLoF6ڇQSǧ>-?F?FmfS~Un8E"S^lwWl#ޘy6'Q?Fx z+wYwVLGѱ>LTRGlMvˉ#uV7j)lU?-p˭MzcfH6Bmr*td/Sub@]*g(ѡS톙}v*>Qd,fC+O^TGTry92ɧ|?@QQQ7 Bқ6wo.":@ot\G:ScsRPa}gZb4t'N7J.Mu#Ynl0Hk]GGiiN?JUzJ֫nT!2NvRS(iD|잱% *< V7Id?*qP1ƛwڎeiil >~ƧCOZ&O[FpF TjK~Eől9˪<56QR0{j76$Rz'Xr35B[V i7ԡ^64.THNvD$7Ps ;8YA p+%1KDlA=݈!-K'zMqy{\Y,W_8٘]\O&9EQYˈی8bն&+I0EFͧ+?i? @sqJ{*`Ehu 'o5IDn# -݀'o=GGCA)et4(kϾn+c}e4pֹ3K wTdFp19|sMtRܑuLp!hP GYPDh 4Oe'`g+%{ )N,v’ m? 檜k!_.3 8!u[s1;+l<˷ޢ^ -)`N:-,F͵7TG B|H$̏RAHv3W2Ԇ<"jҎ7CC0N `)ib"6&-՗dI|$l6Lw CˎK䅒GnPwڬܻ*(5Z(=[԰\W - Uե 0 +AWdUa\x*_gxBW\7-RsrNo5 oss\nTZ8^-/D\㞴GX|b[4$-!d''s'ʬ'_,U#aHN?XjT!zps6CNjdn-l'͵%h uóRߖ`n aZuF9sX/{S"@(ε Il)Z 0*a udE SRRUqȃ*#iͳz8X.ڠ&fp5gcW~w&sQr~m C%N02@8#C)fڶ]8qdzQ'4]p};6T֌<o:̾{wyM:qIJrWzk2WGaKaK=bmWI4ݪvHYU)&!p#VTy''QK%Me5qJwWWRΏCE]Ẅ6eJnwh/p\bHB;o_WuwhnHAI$!\̜3Ib0XJzT Sj*-֯6ytS!-!NfCd)#AJ`1+F3(\/ qB˥|tl6Z2t;ü''+e [BP~uΒNpIK{諏om,W8} @銅9JǚYO䩋hPJ>_I?"=ˈ.c[qJ lMhYv:bBQq> -׎vcɂNZyy@Kd7kgÍ*;,I3lIuhc V2< #4ߏזhqJʎ n{OO_qXyRRTRt$d(A8Gم@eXs'qZYv\7B4*d;s9b@jtQ6CN êo=uQM.Rm%Y.x `{) t􈅵ܡ![Kp,)jgDe7Kcq uN̞&u[i*[nhQҟuʩ.$Y8j ۼyKRHmx jH) yk%wBj|V3APˬwLI3L*sP)ZQ"Nq`mZEL1  k^B6eoU^1[Xն2MŨ R2Gi] gVۗd7 Cj }HيpF%cw0!6qձInm1tn0)U VMYX5 |I'3|5vfBD`}]xVID~!ZL?8ܒ'85Q} ޭ;kWt~^.R]g(<|a)* rOieqo$E("ssw-tx̨/:9 36*6g/YLX;(n9-?I>~}z%U} T<6yg`I8&& r7<\Mյ2}Vϲ_H]%xӇE!᧦ye>Tk wBܛH#շ trAL+]PϙN8V3`lQ߈?PҢjih r.wA#IUd ƐWý$nH#!gb,gnW s8f:N\!U6ixSчy/ B?AgS#Ie 4IB)*TmF8,Z$`P骚.f@vF'-ӕ"#_dt6PӣIƔ Z|KYWM6`|l?~@{֗^9gu-'Fi.-VdbF qkAXyÌR?qSxiJTt-Մ8v G&4LG,뭶ָqEm-e&BB_hʒB?ūvarO3.:ˍ`mFdC1ҽԭ`VdhȌ:џS+ϥ$|`Tk 4#(PA9$WS6F481.0ed:K8םiN 3VH̭%ԥ2d6h>Uv'43auI#z gȨp8ZeY%ʌ -$G*<Y<,.o5"Q$6yrNp)iOS=ޣψ:X>m?T8r+2RQEnYkC~Z"dACo-Pc-DC He yG>|VeS"D Ob ղzq]I:чBN0'*&Pl 8^ߙ$w.$ NuR[H סu-H i5镨5֊#i¤8SG䴦f[Dn2rt*{Jոy[qm*2Oa9c{)qel@nnc̄J#};)@Wۤg4v(rii:<]:g^H .2^]뭪Fcv}fWweK#Q: hCϛ$S* SXP~;ԔtGhȎH|ڊ@=8"eԧÊSϼ 9cG+ 8}o3zkkM-l~: }C⑁٪Tiy-i񡸅- ڒ1V([=/4|TTF9['ksoſ+ c{iǷ'$)y8- R{M#16U5փhqI 3R%-q 1[rJɸܥr\MHe!HNc>~F-!(:Btr{#^)N wuw-8z˛5",7[ bt/+mQ:>\% xkZ.!0' r(oVŲk'9iә/R!zq$^Vb\3Z=Ө TKkScr@Zm8YJ>.r1{ږKUK(R ^I`WrZm-kJBAҁ˕e:GCi!V%T5yAfIO],$N0{q?OsCr:K w+>ʓqw + E%.%%G# s]˅n,+$4J}?A=S"njY$8cRXMtDc.֚|T`wg|{'멶] 26$nP1p3.ӤQx "jua[9R+r| î)2eL+7;d˚CI܆rkq}hgp#袊+*kܹ_(˗֢.'QkWܸGsR $hqтuCG뮳IpeY}ϩgې}>QUdwniz!pHl @nT.nuN;Vl۬q]6_jpFNOcEi&^.ܡyS Lf[ĝqK`r%_ޕvRla S'SʣEPl䜌f+ 7t\/YN02 a?{.}qo6&;MYNJH 8SA@#W-åܦx$k_W+rq. DS;)J=&l$R ] xm\%-ġ5hy)Iҟn7ZmQWK.!Jq`x=pLWZTJuи\["a?ٜx˄zB>bGӣ`)[󨱅_Ei^%XnRn(oZ6p)m,=!żsnk9EiK,Y~ڭşdsR"c=ЀpƠ4GJ+kmT0E;FKƼn­lܾ۲}J!ۺ)j'a;u-f}bQZ0EA^ F&ՓP%t%YZԀBIjU ]\K?R{oPעk QER m~)a:Xh$s(EhNDuy6i{  $VnkL#T2?!:K3e2$@!cRSq ʴ>@eK{F=W$Əq\BT$f".3ae=kmkm *RN+Ӂ:J21U\IDݷ2ԙdx+ĭD9ne˵IŠe]im'a椦- Ia:$g'cPp?\ J15.)H*N Q#JJ\K[E{ \1TE.r RZTI:Iʇv(u[u$猌nq7Sngݕ=rD gڀJJ]e{U `8;|RkO׎2Yc/\uAj: $iqMIpsa&KklvtDZhKjX^ HPՑsMKZ[mO6%Jy@:m$ 5=f ɾ=:J\[[ %#rG G>T[ Nx}FZvfR/ Ks SRQ(D3یN-jbe\e4D'Zp̅HIsl5"1j'VG>I baBDu7!,Ccyv=pXM"j:HWhn[RnQTyd %I*Ru+Wi!B8=WsyѰۤ3SIJҢ20wSE8o%ZOh(RKk#tƱi7)-]D:▢:LvyuzH5\u$D|x[Dcb&G̜˓#^Dna` XNw{fOqB (:~gs6ܙ) P-BG)=G=bN8QŃ>]?h{}ǂ)-> Ny_[Dd"2&6(.%ym:o{EQZW1R}5 \  gmMoM+)<ފD*q)N6,ʼq4(-) _XAst ,h-I),T mW&kUjKq v((l7}2u4%! Q`9W=)' Nj{MZ׸Z1 I \e7Ib2I P*ܫy^;.0s s Hό0|!('۠Z ܝvPԐGjAWxY1p;?dr!/BL̂WN0 'L. }ݣWeU7QӸZ\ $ODZҲw:@I=?E=k[K͖O\t4 AB73<-CVA^/nc~ش>RTOԢ@LakO[uU\GWYa*veߤ8ȗ51߼)~uNWEm3,Ǒ[mɇBy1ŽmAcSP{l1UMՅO -)!'cnOέ!e.~nSfmuqjB!C<Ҫ)|U# iSZZ*d,N*K g@)z J3uSDuyoRQ~EWTd KKUu t%'?n_-W.-, ;㶟KiRNܱΣV*PYNdFeCz)aIm.G'^0<jB?zeP}Gf%gQgf*й@Df"] fO q݌.T Aҧ@[P>}?kǵ{D2KͰic YtG9q=j F{NiH6D@Ŗ& SCaJ[zP##n2w F} p0jyVX`|Vj$O'S<3˳+$cᛒ} Tłl] ܘ 䥣pd)R)*d6ih2[`IP䗔e)i)l@J[Pն$0 L%/"`,م @]I V@(z;o]^ mKQP!$|T0:~V[tLF39On-0%QbNc2$rYJ3!Gnըo4Hqը--qilM "jb\k xQFvJ)ӽ&*`Y$U}Qu ~Mzix:d[W$W#PTR<#g>tGӒq;kFCm _袊*+ $m}KJX K9bMH)da)j9劚aI_ :TaNb.8:̺7"o\(BUK ĺ!n!JgVj@l8uvWp$Qo+ HlooK\">|TX[k6T`bqѣ_Sm"\ܘ2&πψyU'Tߥ)=ΡGh⎒|>S|Pn:VR ΠM1oxo. >!!¸$׏asp?K<)4)!]Ԭ džͤ!lvKlRG48Wqk)dz=u5\23aCfҖlGC2#JDKQޙܧ"P䖜i:𱂔㶾_:\ k3(rJNO䏋Nv$ZmO>Ph<{*j<s+a c"l[cklqYi]dDCN+>q>- п$sJ  rKmr2!JL9$L@Ƥ7fy| ^ƛ/y_Mky a5Kf Ew=R <@ۤh9"Hspu9+ё5;> :rZe$%''?$ۊзsiyӴd1efv~MQR^w@.qѬQXc9 Tu=r\N ԗp4KKn۰Et%!¢V=JN஦ ݭ.R܄ZGa֛eV6 NôG[jnF\ھIWmJmm,OPC1֠\IvӃ۵S_p%#f: 88º%EL㬶(-$d`_]bi.t?=`d7' 6;՘t 3ۯ')v1f]_Fvֵ&sۊvB5-;yǛs_qq!a58I#GWN3up:DnrT{O3R2=}g/RQ4yd٦ÉZuͽw-6շ pGZ̤$H5Wq?O!m.=S Vqmv{G >gh(Jmu/+SE_r4T\ZJ?TSmj(QNjAqsIucojR-rJT@ 0v&[V] 7❰zpsYBYu)V 8;T`sune*Duʎ\xenu8N# պt)c"xU=p+8.kS(N@;%QvTR{kta%ZO4bB޽ Rm8ks:a8rB5Ѓ ꎴv<}>ϵM.>H$޹{%Ivp?df$S` j=U%O ~#Vjyn%F@z}ϩ}-Bǃ|՘]^}$'gzнQ)=?*={uq'GmgMWGҴQUCG~ Z?YA_^^G~p YAVUdX_#;v3Cr ICEp%>%v3+QyXI>.u(VsSJֲġYbќl/*,8A5Ae|8.BeiKu(gffsM5u`KldԡMa4#Qt˧A!Xi"tV0wI)c<\V>?z`CYQ()%W49:L)ń!_ъjOe}n$1ߞc6;}SI s %11%@jmpz$`R(qJm{ŋ\,Km8ӧHH#NBA_l{8STw. 1}@6} )ޥz%A؁mѵcz]+wArcCvҎ7ۭR%y嶷߿)r$)g|SĶ_Y`aGDwǚR@YIΉ &huI+e`<\iԤjy>tkܤ<'[ @!+>2BAύcp'rU16WUʷ!#@hoI%*QR *3p&"ReRQ$N34_Fx[ر]q'v\Gmam*pi i' 8mG|5&'ao-]Лd%]bYR@8-B^-,#%ky a֟Si Υ$+:AR@4kGtr?(ذRx9i*'r**c{s} ㋬e6tWOIPl-9 Z[#. BЄ>/n#9qէwZ)JIB1S!Ţѹ o|[zQqR[Ԣ;*TeO8-G̀R @?Y^U9NBJH!KNylU&"e֓SZ䥁ȩ=S qUf1*ҿNƽ|t׹l#u !FI8Kk܍K"rh'ױb[ a䃏:J1C[}6qC#p(7.ע+QEQE_]0鏍JQ?A0:v¦za}ƺem #WQ1stӭ9*R(WUǝ.”ꃊH Fs^1&Hn3Are JA#¶Tl1ƇVT%NzHZ,4@! R85Ð9]jnN$sX{^SH67^QCQ\P. ?a~ː#q\dHbpV{ j G婥ʿp\tޕ:{J ' H6ֶ,X0.tRKԳդ+VT25tlb]ZQ !=5_PjVcq;iNw*Ƙlֶ/an9}o>-< J B3~jt/ks?sv˘KMqmH{EYlTe9~յAZ/Ww/߱izuzM΃!'+#;1U*bVwv= L` s݄uƠdU&?>=neHvA qnRR0 Rگs'\#Jq%BBvU8]a;ֹ݄JʐT'(*ŜG&f%ISҲA ]*tdweSm3Fos~iV#p5%-Z q9ۡճp!ctwb}'ɗy\#s VҖJQ] ~jNovt![V )}WTQ%P]ODrJe .@+}V WFiU)e|՝NI|xxt5G4Ghͻ/]bn 68),!ٍ)O`ʠ<%h1xa3&yKt:Rqv]P߉vY_>j(`).}{8[Qx˫"<8q%ă* sZvUf\\ -]{N1I҃F/+ZIB޷5-!mY΢])Js·ZV3$ *8m )a~:Ly9a+ \.);iM2Cl$e)}ES'\]u/8! sĥ9(m{m'N|O"S䍱X wS^p,#} $2 @d7;7[S-LT,-mmaUY_dx[ texNf `M64XJp@IT X~C- ,4:c Og̅"P[o$->eČb~9lvbbJAXXjJ I4l;=-k eZ%එy>zՠ] Ѕ3KF-lυh4TNMhutN]iOEiv8xQEj$__#8_u AGc餫{&iYZ{׶ LpEXuQ$)$`LZt$sx)z䃮)U㞓.gb(oΧ^.B7Wǟٸra^k*]OFqprm=,cGl>\@ INaͷtK: n"l7eP}c ST XܜR1c[uˤ!HqfnKS4Ѵsi\c:Y;b6`#|?wg-eq/uoD8-mV )#$(9qm+môFR=ѪFH*im2]{¤Jp)km R@:@5ywVn-LB Sj:מ]SK;c&k^ xZW7kvz%/9)hF 0 {-˅g^vUcSSurY.G}^t'>6I$QaĐ\Dif&b[%<@Ci*s;syRg(Ic\r;9ZaZz2RhќJ)+Z |`ia'[!S)(*+!K9%Zm'.qfB ǎʖN3M+t>$v֛T۩zRn>8IZV#Ck]9:~n{dخL IܣZSbJ3Zm$ +.gaL$Ly\en"K,iL5CnVÞEdSbQ˭Y$;ϺMؤ7!f A`8F=)lnvmo;? Vj3tP-mncMW W$=hqFT1I@ xźZXl sO3?QquG಑y P< ~ixݍ2Rr $ +Jj#|USD1ǖ6\Vђ3-͒ Hgz %' #ޫ/؎uTKm ;k2+.`HhATz}TւQ-)N橮+zv?]s|udQ}wgC|~E*EWTdq+6Nt'8E Bⶁ`y] nSV^ ;쩧Hi)U ]H A}%J `x$yo:dCCK!D tk9ԗR[@:3)\e]$#xEi*FiR^JN'LQ7$+Ev2TCN0$n2z"K.;S}@:S8q̡ RZ⇣qPɔe$ 68 I8v/ [>扷g\d4|G3,+_};l`_oʑ/Z|g̘f]RYo62HN{fƫFlqrb'F\H奓9Ehyt;Ę mĆl9!i8/6FNcsp94K֐Z%*Ma$jq Iq6h i.eA>Q܄I%Ā 2=LJg& PA-imJRqjUrI%ֿjMmؘ}$Ї{gM?XZ^bតo̝V\.&WKh H o<"kz\\-(Rc]Ԥa!MҶ 9H ;4#k^MHωn9`pl5.r!-hKm J9V^[~!{3F>irsOx2}pٗp"Y} nGQ*@SdDsgee%3vښV5vs;TVh $I¦rbphFTC jձ=j&SQN<){sD0GYbO`pJ*7H$O/kI̝],_/?/QE5َE* k̓}u.8t8u%[rn\S9IY5#p2 IDR?<,do9+1էl*@oeXn%5R,e'}vf)(|+'VrT! Yʕ3;)KA q @㲚|E9~a6EqިBƂH9ߏ먎8u=fn%6}vsU˄#A !lKq;@o!㕥.qzۈi rH$wm|f=,\i}`lmD6^TKR%^Ig|?l8A(J^WF1U:JYC]Y2Ͽ#vnW Cq FiDp{Sʭ00vjHX |{ByuGG|^*E}ˤAX|N*;&^mVt)IVΎ :Iu+ YY$SEKjh BRO-OɊRa2ֶNK:u+zڻnq @ܝUBc֙A'; { 㸌cJYS*) doT_/rgL,#g=jˤV;(R\I[vt5v:k2leuXiI#cȏ^IZ׻ޱJGޣx,uܬ8A/DӖՁRO+ț : O0}KS\z_9}v`==ꕅZf-r$mՊ?ms¬6 O A?N|\GiL&qMإR~̂w{=eZ-sRoz9p2mA!yqAr|eo'Wm,/;^uzv2-';U=hRqy D,[ՃG~ꞲlڏnN7i@NAȥ%qQGM約|͓֭Uu_鴪Kg >~uBS(TPNÑX>e6|h-%Jm5Ъu)O4$1%}B.1+CMG_K7V)wNzIL+`$a@*Éw ׾!R~,,)Isr#& RR VG#H|k{@x$!`疜ϣNW}n7..CAR|^8lwL涗\V_}4LP@Tw@+P:yd1{2-7)(䝀ޡw)4!6%!iQW xqsH 7[e?5`yD}MWӉZB2ΚJoxRn"aVrH @d T-s|*ck% *RrOeQx 6kr7k_e-4 O=~t[,W{w Ra[Lq.#ɂ a*;gaTrx=\&Sb2(R) | kFz7)"gt[}6?O:gF(\A*.\ܢ2azˊ:3曰J(ߗDf VDlVlV6'8:iR\JBVT(i;$lFn_Ŗ$h+Ŋ)ԧBV=bI `Kq/H߀ud(vLf}CzTKBU)Nm3{[}Unx7]čH%>W Oc-?|s!q|)jƵ-2ԀJx䕯$y ˋobͽ4i ml*)NA#pG#tr2po{pn%V6pkG CwyY#s=9sM_:aӗTJ|?ќrqU?O\Mo¶$PjK{BJXN@՜"M[k𽻉- @xu8VΠ $jNFt[6s8A}_53#-aڒkoj?m Ҭ-)Pj7hqK#<;cnjoܖ%:y (Hsj!.)`$o UiUk酥O4)H?0l0q< _rM\CjLav#+[m *ZJS?_xk[}9qs0xkF%1=Ӌ||鼎MKTc  3摖YɍhEH O+LX[ZHj Ya`4PΥg#~8⯳2.ZMպuK +)I #ӃDJ`4; S.$lq ̓5ʞKiYҗըTү4ND7!٢xngmfI]BTl50IFg]&O\˒mR,W-`FݵO905=1HZ!94 [-QJu-r B@]Z % tyǷۄ#Œ$+X#`rПMm*0ZnqYP$;NziJ=ķk_sn$S#.V_ pGm5z!re\hN*pn).2OKЌWOh؊l|3,m2]HQۅxȷ7T&"R[yEXb)J|D$;N)9-ݟLbi࡮2*ܠݹ*XJ_JHm+#Se\Dv{]B)*(͓UټCl-MJR%I3?}–gepΆ:# P\dvM?|"@ }줸{@K[H3>9[^+XI=u@G (6UrW͸lV{VO ۀ kB8EXv^GO *aw75Vk+cת*d5*j0z7xqJB:ҕv Os5:T$5=2@m`\ˮֽ}4 3+fs~ř<΄`Wo6a*\LpQ*֠{+^.;.vèF+xSZ^$`vyCGH\<aSƵqϛR>:&kͺ{Y5&: Z##0y.ay!n)5%n<ڗixZbʵ9 9IH)X s:iP)Զ˅9n,+܇eWˌW q*!|s%>ZR$axb9 }rٓrVN7#&Ԣ76PSrSd'_7Z0cԿhWٰҚPݷ+ ##V\@Ǜ՟/%D]ˣU~tkC$k#<(3~]Jz[WB1RNR@ls3ީO[*3 -0hiBpfSQO.$ojY~@ZDZyqI6qw2X.\q8-줡 9NF0l+bIE *ImMWA_h{azƭ{4F+_WeuG'.{SrI8Ϛܟ7 }}c#;m/Gg=wd)4xXH="BabANVJRT}A *įn[c;T%Ͷ~Gż08-V%p;*BZRW$cʦܐp9cjO'Ϧe++S!,FKؐʘt6`H<2g 1KiLµZi2ܝF;g$0{괃νdi9X.YZ&qgFbF:ӭ<+XRVl(UяE&sk2r`p+XGmy 1.Y+y=#F=v6V8;=B+5zX_A*MQ()d">dd/DfA+|zDfPZ{i$f5WFwYW',)“p1N"$X`(R(h-lmKNH͗ANb))PTBA9 LН88J:s .I:K#}*}o'z Y,k -8>z!i ٞԕ#!H'ƠS)NpNqK0|bsQ{)%$ E>~\pY8VJwl!; ˤ\nJRv8#WDW$\жg+͵xA|uPL4VG,ӨkZtt)0jB^7Ɠ^RhPr}mkyPPPw=G=6X?;Y_cF}xl?ѝGJ(Ub(5zaoocXn#N#.(CZZn9#d!9?zpŶiWhB'PF$jPۊ BֽD씱Asj +V$CW!Yf*9,ʏS췇7Eja5ɍU+n% Cp1ƵFqM%ZVGX~*8?IEjӄ6:׭D6t7RB6HO}gݘ5LWW%p0qzjYsPR :Ov*f@HԌ:FChP;Q7yE$k*7.=lwzh8-3ؑcY͍4 Eߪg%\CtC}-Y`Lfʈվ=X൫BپWH԰dM0qΛO#Ka8l.* տ}}vzjAQ8*2Cz.!_,= = |!ܨYq͞^x2T3R~qHϰ)f$c蚏hs] 7^n>pomtN+9ݟb:- J"D,⥬E:ؒ2U)@gUcIdA!k/5˰ S]xu;6wYP[eegJBH5ZYiRSk\lP:ABGu"͑SʆGTkş}bڷ2ԤI-ln_QۉeaZJQ#[QYe(NHȢ3!YNdy{.O7ֆFk=Pu`ާkC%I3uG*i *ñJnF4'SʄҚ(\&jW,Ӧ{HMxmIdne%nS6Vp{{5=h JjpRBuhmi<۰_57Kt.N9,1S1*^ mӟt4sKIARSVХ&p+HS9 =l [R=v?_R!  s2KD;+%7FF{1q%V\8Mz)^6io>KIՂҬmSD2:w[WbS xqcF%2 X:t'J}4V{mB3aĥ W"R,?-SHJAϽ;{{OuN%Jup>W 8Jy)(!)>6u]LF./K`j5 Z4uOŹ\KguIB;E"CA\%b=4HJ9 J\~K^x:BNg }"ˋɄ T#7S`M8m_T_9{%;\l2 G6|T&PP>2׏Q8HPWDUl`eBObA<:G+SeXߠ~*i"`K#ETkgҔLtpW^An x c6H˔5 ҈Qzd8JTHcuO/rQ DO!P'﹫=擼2:M*ʹ*˝T+:eARiRTHWXE٧,aږKN)IFJp~!SB6v*k E& ˏÎ]I yeTFVeGd=K 0s2bJ FIRJv4~,4ʧS!#T5%׸wۧݙ oWz8sBJ-%c>q 6st6r[[kP'qjMW q3Yy?_nU\-Qa`1K-f{+LΓL%jKNPTW[:'=ޑUW6ĎlxD4\ɼ 2 ԋI+A )"h 3]y߱Xڂl.ynlxi=a\qzr!J[w_No`7 kHkQE]~JTE\įM.q?ZJ?TS\\wR;~fdtj s{7?Zk{'ݕ@S]GmMte* Uj;-c!=B}eH .}/98O4qiUrq #RP!Be ,UYVjJ;B՚paFokY4R P줕ʽW5܃@r9Re: K#M)M#"4PRFqIkBU䪓ZQ^$uq\^z`]Y鋂`!qJj (]Ϗeϯe?Df[ɁPKZYV!AHyNQx Ϧ@8 dUQ @A9aK!K6`j)`N1Ur题#_J˿j|Pԛ՜'akE7YVz<J4v{biNs؈_loƮ|hWA{у?k跺(EeʵEc5Ze%%E @\ʏ.qhsKύE x0u9OS9Yea:NI*//j>^XH) Q¤ -jRUp7$ԣKvl hu#7#:9P٤9u}i;fB° QI: G%Dj\*Th;EW$wZ'҃ I^cO4ln9|͉mPqjN{m :HB#MSUL(W:B|ʈ$!#PmgIм%,N3+ˋJIJ!D N ^x7?ʿ=Z}e#l}Jz ׋_(.TtZGj^Wu?W'35k4I=RZYQ$5+^9F;Hm{w^V2 z7pռBF)' ,^PNpM&|ʍud[ TH S& NI5Q$I\q΢ ^M}i`u% |b@^,2C>(>#B@ HRv Q06 {qJ)gG$x7v"gKS{q=H'9'H[5|V;jfV._C9''<:\‹)rO,dlcLP9=3vWTMQ+ ;LF](Kpmh~ .[TO~]$ l6K!;r؞G v- ;>.=nRQ c{PH =Ƴ|Mp\wi.Dku8À03Yp7Te#K^;;}4ǭU{㭿£h1;鵳1*{X!qЯOV;p6irG{64s 1{>_H;k:RW2O*Ni(3Hմ˜(m8]~JTE\įM.q?ZJ?TS\X_*4qKuii>0sYGO#Z46?Lz|v$M1jڲ8վzW{'͑{'͑ꤳFkWYW{'͑{'͑ꤳFh||<|K4fW{'͑{'͑ꤳFh||<|K5!:~Gi+-p5 *H'`NF O|Q XKA6M<|<|ָ}˓ַGeGrJԄpvH97O0/3s Ԝ UٍT#\ۿE'+/q?%h6G%h6GQĐTwэmdgI#8pi, pQ.iJ/{D=Ty/{D=ThK\RK>lUK>lU%3Fe+QRY4`RK>lUK>lU%3FeZ4˴qԢDccBC:68Րq@88;V'W]U= ]ˡx'B((r2gNl N p\l%h6G%h6G mnd2cq u)DJмdxKםERۊlbC)qDv% ZTc!'-i8Wict{'͑{'͑bgS ܵ`Rr*HǺy2ymE+N$lFA A"i#%QQRY5f||<|K4fW{'͑{'͑ꤳFh||<|K4fW{'͑A bN)8o)mK dDyt0sҝGvڑ5r)ϑª;*+ 舣#B,zwKDie6P4 8$k{'͑1?uLl X}esq'yJ/{D=Ty/{D=Th3*1O#GO#Ifр#J/{D=Ty/{D=Th1O#GO#Ifр#J/{D=Ty/{D=U I&%+#R 8'fN%n\v" o:̺6p]hbqWGXe{]E/{D=Ty/{D=TED5͏n[P8!uZ‘yWnj~lUK>lU%3Fe+QRY4`RK>lUK>lU%3Fe+QRY6 7nn6ĥhNQ+ `3 n'd\f^dz^dzJ5P] Dƒ @:ө+AԭЮiv"xD\n_$%Jy^T*H㇚(ܛ/{D=Ty/{D=Tۛr^ u6V&)$`u di7SJ/{D=Ty/{D=ThOQRK>lUK>lU%3Fe+QRY4`RK>lUK>lU%3Fe-Vq͛k U9O5f/c8q?KՇM;=žjI/mQE|{UW/GI\SR[i$HKe@HUE .!og>&BKV8B5]iV-ƒ((~3^<|K4f#r3+QRY5W{'͑{'͑ꤳFh||<|K4fW{'͑{'͑ꤳFh||<|sz0$@CΨ:d2J#;g .l(Nr{iR ԲNz\vRIO#GO#Ob"Dh괸^H0^#JвC#)*mY$~WI^3 o#}daAq̕%h6G%h6GV2^dz^dz,њ0c)_%h6G%h6GF2^dz^dz,њ0c)_%h6GiĸLm(25LpF3u7DYw:dQʗո‰$$UQz_$HrUZUJ~}(Lz bay,7sO$ ò׽|}L,;W4l8 x]#%||<|K4f0||<|K4fW{'͑{'͑ꤳFh||<|K4fW{'͑{'͑ꤳR _U2$'#=`@^U#V1I| &K>lUK>lUI\,r\a3)A !*#R 2s˝4kFTɷ<Ɇe)D,p*px}Af.ғ!QQ"<_zí):y+bp"\ Q.iJ/{D=Ty/{D=ThK\RK>lUK>lU%3Fe+QRY4`RK>lUK>lU%3FeH/2SQs(Fz9yJq' uR qdkWfo^Ǘ 9 ~W(rɵ\įM]~JTQrQj(QNi\OģE9ΞZfKK8A mBR뤏R~Z˵Wtw/m\$KjU#Uet5R:Et5R:Et5R:EtqsmGϋRң"q.!jRJSIQ'NU8Nq$u7K *\ s<(iA]b zA*N†M>:z/Z:;v7֠w}ުs|In; R R5%X9cigl.7;A߯ojR5 SS(95R:Za \IKjU#U.]-T5Qd]-T5Qd]-T5Qd]NpZƶZ\ʸ[q:6 N:;TO]9Wxg{fz( #k/c;UԵ]9]*^ CBO'Br>4WK뿴*T5W,UڨHUEڨHUEڨHUEڪW )szaĸڰpv;ڮXZ78]"\- wwK 8RXX^%Cxہ^lOp+Y|.=׮}H1›V^uRuN\9ZTd;-msߚpm5kFZk^j|S%>HU ֯&%~KmOս B QF;8)fDTMQ5ڨHU5dڨHUEڨHUEڨHUEڪСJ/ڤ꫷A8Jvu6\+NOƤڂSk9u(EB(<F.@Ecouxn_d/N)I? u H/`/e+-T5ST-T5Qd]-T5Qd]-T5Qd]Y;őĀj)C88 ij۳zSeC,-#e$,'`UtBTGo!E![)%*؂9)Fj49lꛊ3oEw=m9IjmŒ9 פ-%$! lP׋l==Ŕͷw%"H?OKNU>Jۋ[uO% x nf;5 A7gmܦ+k [÷ƪ5R:ZVH-T5Qd]-T5Qd]-T5Qd]-T5Qd]jӞZt]sǓ_J ijХv[)|*i?w1QEW[K˞FWv?Ev%` ֎JW;YWH mTjuQ[UTjȺ[UTjȺ[UTjȺ[UX_E"j_[eiA[BwqdUSsCDGp!2Y,4ۤn7ڨ`6 Do9kKsVe76RmNۡK)58H8+Z *%Pk3#-α'%IQ*Ӎ#JqTTjŇ1:OWKoz\x4'Bm,1?ʟ&Lhp)-AQQ7$SmT5?"8}>T7*AQFfʋQF,QF,QF,V\9ğĉ^SUmŖR TBUT'[:OyֳVEW׾EQ:{HnuGݧVSԬؔ(@S7*ȿtoi?-Tju 5Wkt5R:Et5R:Et5R:Et5R:Eun4][L\ZVX:{=^lga ڤ>ʂFZ[I cVJbMS ڛqpx2/%F $<66;\Mwցmw[}պus!-mHҍ*%HIRd@\(ң-( йXN;RAV }#4tLs^ [==!3%aSo!U#UdڨHUEڨHUEڨHUEڨHPȺy?Qiz,%uO-I? uxm%}UTh"(KQKK,5oe+NjOJ WT@UV'{:?;o*}[UTj,QF,QF,QF,Usm+]۫EMJ\떵G(H ƍP$'g&p-M2Pt a#aΔ.l3mh+x+S,C.C L^[Ll! 뒔@/N5Jvͅtr5ͭZZiuiJT!ġXOgeU9Oo1 mi -%*FvRٍ-q_KI9׹/#4HUhG@{\wQFnFGU.FGU.FGU.HWw?Ev~WܐDvPVB9G`k[G:?_:K_hKԦ_r4Qu/+SEE˭E\OģE9֯q?7𵋉"5Դ6J*%+A{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt>f-(jN8ZAJsZhWO$썑,*4Uwx+MlnK (t-MB*EN90(=xpik}%'+B 1Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{MtT[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|^EƲ[ڈ.JYTUs'Z,`(1ی2LN6|zQV4Ql&H,YGJOQ5>QW_Zy7V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|GC]2~<=d-ɷ!32Nt6ddd#EW-T HGi%Y{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt~౩e':]>dA~*\Ϫ裧c$2v HJ rRQEV;W[UoBfdeDr 7wG􌟬 b*BJx7{Ag]#)?YGGJOVEY}kcT[|}?GR~i :Bw}Q̩Mt{MtQGHU97V ik}%'+B]Ts*nAg]#)?YGGJOVE!Wֻ>T[|}?GR~i :Bw}Q̩Mt~w Kr]iגAX V[Da,hGBi1 Bיפ88K%->6V|x5U)'tS{7nZ"xsOgpMt%)VM(Kqrk^~mc^x*N=]1 UQʂFu'zj x2\mNRtjZXːBnqdΗ&RfaIr88B#[G<:{4K%jTÚNN3۵4K(A׿];tGe8<˶>v$y=+crM/==_ۺ6E!@g޹cMl@r<"@/\sH +Ql+:@OS[s nxMJG'U)#ßYY:^В>&O!Ɣ:pGJgxxq a*SiTWV)Q99.#_ȳ{~1vO?54s.^SO=׃!m;7>+ׇb?r^$2;`@pX;Seᚶ) N=%8>Ҋ܊vRP~c^),/EQ%uHAO)I<6 >? 9<ԜUIgŀ_LׇI'b7)^ 3 xHcU. ''fT27ڟDT- Ra `aD#3TU}rlT5Z;>#JvԛAQ} 'Y#7&+R[9iJ;}ʈO*ZM ˰Z,BxV0F|W#~ꝋ3{ HjpXԙ!YJpH \pFs"KhAU*`T8S| ]eȢ8KMd48*DHs/w7BR hZbZ[m'WXH@zr+,,:Npc%f't,`weڭ g=d; R? r3lcǓ POI?KːXl)7Vfk)(A UgB}UJqQ;N ʪM…2/3؀ʖ[Js@jӊ]F]9JM۔,6HոUș,blxz撎!xuĂ u}C1oBN`7x'&*C2xg1"E.S.2̙0 y ]'3N5+nϵxD͙墿pgKT*uԶkJНyUˤK굟tHy8W殍5#:j؟{[QEVEsD<]MǏq ,E\L~*8NJNJAHZL I⸜{pڥեJajRJ) +NI$Ruo.7d$q8<ش.q (!WkBex-( ZJI8#n|kќ^#qdGR%Q ڔڒ~*P9RߥkĞKZ- pm!K^25dj*\9]%8d9M\7wֽʚ 6Ÿ\ sϞN%pZُd?nJkH;FGd'I>'#rc@$i5*$T͐Yk{ WqgWR:qaa0%P#onHX*VWIML5wJ<ּCz^8<ƚJc{fȑ_¾=]d(?VGMl}[(siK++ v{*Nvdž?r>I$k42wKkK:X y[+M=(<%.97[8xg?S[oNWHt}[IW@U?'5cCR*ol+VQC [xފ(U.3-<:K]^ \JNȚUK%Fe\ -[AZ}G 7>sZH˽Y 狀EVzF^?1ϫZ-)$ Ek=%P%Jmh iøq?o|doG1^9,qkn;OLcH:E'/SiyN%YINYk"Rwu[F|yrDvQY@ϟuG?mBgk  [!^I$'zܣڰ6B^ I *;$ ~v:Qrzy)văK q98e{T q7ʁg3jTi2u`mƫ# I*d(ui;=?-Umnz`D-譃+V>{V!\Rq(FPgR)̖̕1n#%\.h+MjiVUڢ>JNuJWBԥ+~DCjԠP]% _a2Ҵ6I; 6 u*B$ɈKRx 8'hS4:JJzJQ:y%eiRys34 H%m+Y9$+⹒UۭK.PA:1Tc^!f!i8!,HPI)3ڑ1вyJ ̟\:.A} Q$Vq>jd ].߯fE֡0[R A-cNsZ 8:ҖT~+cS̒vi}z[qx)5e9<:1?HÖ.p$pq3+lRY;[rwŰT[!+vU24HsU/~j}e,zBd(6B#YX[%/=iHm{=K\JRK{v9Պ&:|ι-:_  &8hBq:QVA!9=^HJ-CCV,(%?Ils䫷o4#+CCN T0ug'znar*-V>*iy(d^7mcAuK+:qOFUP*¸?PP_ZB)a<iݝ&_18O2\yKjn kN?ِUB譆ۑ![ ðBq0/x[Ma(s5/Ii8rی.)XߵO*ϸ{y)q)+€qLC6Վ^0A9W jRWr\|ɻHYol{xYz Y1N'u)Ǟlt=3t գN6}8k7ms#PRH0ՐNo#Ϊכ qec$S9;~H@[,5 ؾzRI8}6t鿥ωAꀷ]BZpy^KV Jc)7I\Mo=:Mc}]fIH;|u.8m-6iݝ&cW_=zN|#}]ghEXy9j*TPRNAH99N(.?` V=8tyĪ4ɔ%j'[8*B7WJ)h7GM'6:PjNGM^8*ZEWJ_r4Qu/+SEE˭E\OģE9֯q?6?L6lGj:2܈[lJ-$B?| WŊ eF~=eLpmy G$uZ"vCP޴]Dś(yx'`Db.1L`82y֫eHj RӆkH+d{jHޤn;*Y =rt (Q{.rV mm`n\#.%d%#}X;y>Z\qB4;gV'6-W'Vt*s~ACϡ(o#+W,mJB\h-NN^- :vT4B0OBEeD<߿EmCM\kv{+[w%eL8wA|ft} }Y>m$Kib`FЭf3q랣D"mk+Ilj=qf2é :ңuG$0ה!y5yS˛Ϥ|RrEU0{ji)9BW5~n@ IMl"HznWP߉Ȣ)4+}|0ӧn"}˨.Y3C]\e쑺AuҒc%YVk.n4p:>oٵ|~}k|۩߶^&0MS?gJtv`At87H_p) W6M(vqo£~CmO22n'ulOXH?Hyzﶛ1\} mE 8[T29&{U7G,пsgz #W \ZJ0{)щ(H4NsF9‡"G=qltY,ɲ; $1Q;͎&oY5uFdK׫loR8p{A Uxn,.9 6\͗CpYn! V^ ֆQN:%9lϕ"y:X3@<5 ǦKJw&u$}>]O_5$$vK#ԞO>A⚬4)5-}[kK[S u1mM8N9sޒ0gBYL[TVՁ%@W"\Hz8.tH2p9Ж u*j≥O ~WBsAmW2]w!N,Va m Ը!6r>P]#G!`#<=E@P@ :Z ICI%,DBPըpk-hm}Ė<qW$wŖ(9MRp69Vݘ써cxo?vswGZ[KR hjcjϊBqNKBi[{ '#o58gBAA 󫙭زb7)V|Tғ$8 `)^RV<3JJ°Φփ`Usez2%M8R9@jv+-Xn.Ʒ]X$6Gf<|[s@ gF~:D)/L?+C%*V8aU!-!2|o3m?szaU/Ѡ2pDRBdaGmH猍~+c-Z`Ddl'mW2$b聗:C pX /5\l\E")5"Lg#_VRB@Ǎm=eIRun͑JʊE'Me/bd>/u%иG R9*FVy弥-JiҜitR{U[/!gmJgSOɼ@EQV,V\5} "3{jV0Wk$)D%CW[rt[[lɎ'W%`qۖܫ/iذɝiyj1F qH;;`HJ`d,wH$lUl&m-R wvRЭ0Uzpe(t<*)BҦ)nǏII[[v^+ n!/ai χjfL ׳. rBFnIN).#f!^[uY MÀP䐡jw܆nIy0()$@?hִZݭR5 tHqZ4P@v?7xto$Բ)zHĚɸ*>$l#ɉ) SFwcL~\P9'./%Yy]ܯ''}{KJšW Nէ𗰭NknG:Q 0'jdB$#έ·+R$;Է7n7ևc9Qwҵu{ Ғū{jN}U,_Xuޭom J hD%,*T@)m*P*8器^iYxU1cu򓌍sTL ':y[qdN$fN@? wm%{Bp.l8PA$xm)  qZqիbj-iYZڗgҼ!2x,-. J;Ԩ睸`7[y/nҬ;5φN_Z$*4@洉ub[6lHP%+ǘҌ28}mw=H0wӿs+E dD|y@l R3_5OBt>3Cz>8r$n/Stͮ8_;jQm;֎'?ޟNqκr0( Xdw+m`Ev_p(QUt7g~}SjdJTOSAyr\t?%({_%έHe (*iR;oom5um% *wJQ|7'6KB$:^Sg + vE] sT0ke;=QGXQ#\~cJWyNG1%[R#Z8K`l};U]w(וeїNtۗhP6˳ʎ+-2)89Hz׶ӘQOX> H b|0Mp}ё԰]KNCۯ=TiIN8>ebmΕrIWT⎕̶ݷw-"K>\8/856vV|I©x nj7o0ҼIV=)$Ь$s'jߚu¯\uB $ٷ>*0w)𦮶x,iTF|.>*,5err[gú)-iBu!Gb Ag;wI.qߞ l7K$ovsɨ/- p,ό 4K.,dJH[9K!|I /415Z}}TCWSnL7)N0Ke @Jp f6^"kheaRR;)6I c,9Ĩ^*KrZc% Ц ZVn')+'d+)PW !2FBARвTN09TWk׍n-e#JE*BvZ@ /-ȑ*#b;6 6[QW1:ۅx%!JQ'|,aetk )$:QamCjVm+IqS(9O^BSbz(Z[9Ҳ;{k4޶TFD45 ;=Yb,iÆ\4* qJqdTG$v0.e٩Z }뒡>fܕ!DIyZ{FNNXҨ6F*Z6~5f%%e,ȏ!&"<cPA Y%IPFr9Ɵb˗!ϕJ)VJRIgjMu4Nc`v F4[օ'X)GR ФV`%7Z>SW8^1013IQ9΅iܡJ^xն! J%)4 J@*V΀|]Uu$'`"Iq8bd$KL(JHʎ,CĊqِq+a)$h *)呟5Cֆv(}6 A_P]rqbYu&)Qqso}i|yD%\w VJ#aߊmMײTq^gчWFfuM9g4Rm1a9Mk\ܕ5II*P# Dwנs VyR*I#x5D.. Xz)!@z]H*OV!r"%-(cI0 `N )`I.'lGwqň:U%*7;ڒ0~!S,q4wXJ\u0#'l۵hRV_Jςi $IAON($ CJ#[d-$w:A";H+sHI$ qi2yl!$ɭrs?;g}n%q{ۻBn7*9NnvW„4-)9)XDC#bXp,tjr\[*e5S{R/AB)E $ N" kxBf7&3lGRu$r[ӆKJB.{EtTFqkw!NIApIJbC9qsum9l.qKe (9bck"vx ,KAЍΕ۲>4فjhL^OjE2"W$%Iq|9\P| 줠#yT{A[MG9 }3ciit4AUFcQ/[ZpyGKN9jXSn6f9`y zGfYwhR:N~c7+[wX!2d8 PR hK/82 ,&;1NkIAH5Slfr ''O;c"#8J',%qS%/!;rnkRzGTWޫ"fN* o 9+n\ZD-]f FcQ' &tpvgАAa+Z =F* :v n%Ӡ)n:q[5}pӮ[!i 9Aco=gZf#>UR4(UhZ{ xzDfr'Ą"ZUɢYnO}|qx2e+mC T)L2\u)Ȫ{][ɾײCVs)vPȒQN3i 8ˁQa yp4|Ϟ?¶?8{ݢ,&"qUS1I+ܖTҋf%$Hsks؛opD+k!;r.2L ^0B osUW06 {w pDY.QRpk8^s֓mP*̞.&?pƳ2R SI.D;?WDt*H)U u bmSv^qSblcnWP=|2YPO IRi6_N9kIߙBa49WX Jr_u8Z<KfO.Đӆgү(9 peB}3IޟW؉ Lil*9bRio5j64ަa{l/U+4߿oE}{ܓU][f7 Ę8~ .FSQܕ\ $CHV[Fvg:'*uC)/\S~Ą ZP;tU  29R`ܓ:sZR7&WtWczPs3^ǸD{o3yfA.iמU΀<շ{orW %!{;BVkqUZmw5QSY(BøˉUr˺Xhўj.(gͲ=PU43\)„B-*=+ޞcqs㛼vdș(e¾i nҥmէEc:6KBCEI[8YHci|,=)k"~\HC )gl$G窍I9.5! ?zCkJ6QKi[*L4F{ӣɹ1r5Ub\K4Sm ^Y$$( 9ˬ g#qV k$X2--8܎9W[@״\!*iqn: GaF[%>6$$(YG\=ebqT#"bz J'6-^訌)>2ݥ mR1eQX6MCV5- jN' Yk~esZYJFgˇñ[Z|մmO(3qa1r# 9^~ Vt =LK>>ܙW/\>B i$j:jq"%c8>7*Qٱ[EYK W~[s;.LSix#HI -A"O^K(LlFuB@X5ѽ>˃&^,֩.7-7(Bii=`dI $c:x!gtS>8p12"̄e1ylʔ'8Ӷ2k?ĮfO]"Af5<8#]R +|NV9@orG\Yr0%+WoutI&o֞ٞƂ-ͦ Ju ,6B6mYM!5uz3! SdZVDxu2RBl s>۬~A1\yZu!J;bS?ֽ:d-"Pmn4C-ڎ)vސn'wrB@o: HGX[s`ۑ v72[aĘ=!)K[7Q{uGvklw% . `|l Y;/YVf_PRB(ڳ4##5vq e< 4&(IK9wq.,wz{95-$[Q~7Qmm|^ďT<JiWh8veEmn9﨎#],I\g/j,4IRJetXsSn}nqvBj(BZ $ĜTlslf:JH2nɵ%g}-qqe },a-%An.OX۾j.J3F) 'c N37hSU8;mii`k Bv42>v+c(J@:RB|a2F6ީQ=1.b&wT ʕ'wF0@$-,&􋸎i.4œDŽ@JׁG_w+ϴݵ9і|!6Nqϔ 7"Er D8fl\Mک1nrc2 D5Յdj p=0NM\V$E [RF' @9mV$pOjjJoRgJt{yl)8_hC*JBGVO.묭##㉶~w';&k/T BR H QKLÐA+bcx!GI<{@^=sjAR-1KŭoSd/m*Bt J0FypȰ7rTHo2*A H885l(nqOӅJ3J d9r-6w,i@nqw—$ƅw)t1$ļi>D%"5j*U)]dueH[aIV$:Fݵ"o2YgVu ҅,ηc4ۉbCN7%léq!IVwY:q ׀H$@-㟎\/ ,Ns qZ]qBQ;%WHp@lBV|a3쳖mqPͲ;~7^\ayMY[TҢ $-)#;d;ךLJ$ZE3|}(cd83fMF)ZqOo O/tN]='⛿)M$7gXF %jH (QR[j>/hW0v8bgo3-R-Ҧ6Od%=>)```|_WٻDVǴh'&^ַ;qmqg:C<2DyHv\!̊%GEwP&fS3'0xoFtKP1 qRT؀/E}@! Ig;#9=ݶ*EӕHȌhK,. 6ެoLuۛ&셁8R2T1*duyHRPu!Bߐy[pABU!d'*#tUrSm3S *SkIVr =摞i&6.9xm3;Ր s5 d۴h9꾕%$I=91\7n;d]-^qSA8`ߵ[ t,{ۅsE.F2 S1b H+1A6˗ܹ_*.]j-_r~%)6}ˉ~5 G«[yuvqӷr *aHZR#'q]uOIvֳj6ˮdaXp[.$5- l nryWiseuxYW=%JS+!KH,}*J[]޷i@jZNFTgi_VB{+B0ap7Nн; Kw(Vc>cJZܦ}Bb֠F!4Tj$T~79zyINGyVKCJ<wτCQCAgڿeZ-W-<:6Rթ$gUŊk$Uco\8?x┑9T S%2\BZx()IPF_^.W~}P(T^a)Z5("lk."ڗQ؛^(=dž-- _0soV&Czΰ9B9yr9Ӟ"'. y$RRA)ϊqٓtȖN'9you+k(ҢmCzR9L0j=;lGvd߳{SGW1q"u.vΐ7/Nq==hLxqZm)ܓ$I55r-T=D *uA @평 .B\Mv_]e)ʜRTq5X[k9ó-#%<:e}Ǐ'<_rmb:x sA׍XeXxo1o' zDmo<(585r>vrjJmr3 MšŸRrtTn'cզhMݥ\}!6 iJ$uRWlf6EΗ 6dNtGݰ?K}Um\aaӭ-* A=&.f' L1݁Nu2 Bxr,ťNC2YRQ#%5_sL,)K͕%/RJH>iy+c{"vMTDK[wu8R9'M\\y/ qGYfK(Kir#,!J s;ګ\SmIP-b؆Z)Jq !d d dg\xnf!\gEbS; D[ J\J9?$ol. 7#'[+E 6sIigq5 q-햣Fg$DDTNIRT VyϦö6vi2Di(q.%$ѶOLĶV+- +?A)m7|"z~\[u_ N{kڙ! xJpFu\RS@O*nWmBq+FKVR0'|>*dahlu$xؤ+{ߐ.c,-@L.2qs:53[S^ Hq>zOxa]JTNI{ur5x=fFcCMR (*;a}d]f<2=XUpr^$诇OpSļFDp|7*RN 8$\?qsqWIFxpZXjr%]HYX Nvge}ae #u^}`5?z| p؝:.T+ {SaVKm`n7N6F*?DZ|@iK߽IRNvrzZz>鏢u}!<}H?I\> [n 9\GTtӈVV^ʡfɲ*Z$Y _{^;==Tynp jK)kFQe jȌP`,?4sQS)~Czt82F#Ii qY?#)nm^0YRqE\anA1XNI2u)ױGmG5>pi946ԆB QY^=b-)*CH)cϹ89])r.mvs3W D^#M|2.u> rExO67'g4̔xe$c]zȦ y6Oo1C)KQ$1D婖!6Vr;r7<@wzGJMJe/0?s Tc|;5}(zK nոJBB ڳQl2|,{rw)up {#q%lveCr"#vU:V7Pg;Ym$w=5pёs|4DhՂFu9a<{-]5֮kD`j9PHPG~-4@٬KH_Mq׶OCg8$2@qNP>6m:rpZ[%8Pq%p A&7[ē1| A,Z5-`}].ѤAq]bRe% @!(ƤnImT{>w:& \ps [Y;E**ud'CVYX4I9T*@l7>5>8fuRظ)2ޠ >efqr5)jYRM7-%+XͭxUsH}ҤR0pn de%Ć_ch4g\LXhܕ訵Eܴ'`Q7G?)x:<;Z8פ)aN(4C(gԤ%#mMTZ$cqOxgDoSSiLH`-D(8T,iݤ:nVL:pe_bgmNUp`gXZG'HRG;S^$.{֥Pc'%}ۺ%!+PPHފK|7;ͩi $ 9yWϱ/$-lwQ5PjHYp9/}' öEjHJU&bT2BJ9𧻓~jiW }uON[ln|R)yԉN:4oeX@sLؙ&dwoiS$7v^Ԑ#Qn]%\L0.o es)i^zrH$ v󮐫X,,6|n*IW?1z i[n$rh55Y:R*I-.czog~oW8Y 섀 i0np}YY̭_[u!ZW 2sȷ`lOZmfcaO:ՠdTZqn uR>qQÈLp =U9UkgCec?OB}wp+ 77;JiaʎvY8ܘ7*˒{4m~J\jUd(pN.8uI)B|,4[RAҁՠ^/ClqoP 2|XWRxk5EujqEn)ʱL"FnywHi?nT DןWhCm ӓ桭;?6/I4͖G\c.ϳ%]no!ƐHEN<Z@-\Eݔ6+K5ko{ d`5.KI, 6+=4!j%~=ʿ%xN5G ܄ ,KI.t[soQq=}*XWra\i,\I۵#o8Lc֧5˚z+irh҂u)3R&0sڼKjpAЃ˞qR2ۭ1+Bh>[Z'`T pp6FbKm̔7ÖȊ8SJ{t2?S>zK*VI䰕(EX@p:T#! /'QP'N.D bd$2p'ȯoMVC6G6j> X~x=Fz&LjBipGTRSX9 !J=;snQ:go7suH;TGY!!AI 8U;z*hY+vKNiR8[ZY|V0%)[NvnI>|fךSNJS:Ѕ9)w~CqTVuI\{*|,P1ڶ`gY8 iQ+QJRV q[xqQ[%HK*V (*/wtNOwUt#kzɉqǢOpXfdrKI†0r5#ZE?VFq:-Nj97)#vYe(J{ꔍq豮)iM+:ҡY0hnTFl8;ert|a= NlPy 4@=5vwwˁK%)8m{+-%qm9-ƕE'Oc0EФŎzL)n%yks6L1h*UTJvh{:,4V? C -t' mJ|-K뒔F*iӍ϶.̝m&ދ=Kr.kFlj]n5N\2vkiFVߕtCz,-aM@JJrjD|p)fK[rNO}DΕ+ˡc%D'?!5Nql[L' %ZEQ%+!TA}n>\&W=Wo!mQZHբ_G̎:Vi9JIA Hg5 t ˄#Y˅q:s <=m80 A>dJi< poQ$>2⬾mi%%l`Z֭jlj(@I?G6se\bhIu*2jGomZl攷&SִCZmKQ 珖k!¼G/FW%#ZT '@(w斮hi$ 2]ua,+D7.sb? Mi})-N)'t֋phLHV`FrS[ !%@zI>:iNx4e YO.Qkw.1;.=kaU|2u7 #!;eEg" 'WHQJVkάVCyzO.mvیFz*89|-.JWN4v֩#.-> Kj=[XaRG>W7}f.BS~M Hr3hε5}ڗt)mU-8Vtnm>zPXm(m B1ց K~\?mKS,T)c)*{x"Em堥8T<&=kl"X-aC/EH'Mgcvr8ȗGmٹNҠj&Mļ3aDo.U+u'L_8+YhJЦ{y5-[1یps)XsY!*$` 5(6Fw0zcZFџ~+.cWW[ܤD[Z@ZBT4r@`:K8jk6;=5כ9Xp)D0{VNGq<|Y*mJrZ q|rnB't3q-5ȺO!E!x*Z=jY&hp l2J5syحm5-&:pq=^ jM6)[a&+* ېYoJ 1m6m0My%7m[|-<(8(Jԥ,.œ6 f'=5+Pnxߝ^lMkT_! VUR}5 Iٛh@⏳[\θ'RRmIJzۀzaIe/%hq#PVNv "Zޥ5dduOKyNu,2ZwjQ.6l{|dw-~gS:g@ wq6dqN"Km}i:\u*HSB]_]~5:)s glzc=e k)?RĤu2ZS*I)T )Ǎq֋{.,\^Rq¼iT ]9 T#e&3GPO.RZdFk >dp4lA99jۢm2 =^gLLIS 8 (Pnh ^ uy9W\O? ==E!,Oq'^@|Exi\XP,2 NGu-[5"DŽ\j2+k DWi)[UVKB+mJN>n2񨤂ysO9#T\RBB䓎G?>*8#Q2=7 ؅:rJ&YaƷ1҂̀*ympuߖ ZN& *G utqÑ\_F[gZHRr4J@el k)RFsgQ)n+>aF0Sנ gW6[9_;~ 9K Zn>R#ǎT^~CmQ$vjDouP]baƐtȑ9w 9r'J-B=DEYu }KdK3H:5zwTn`WVҝR9sĥؐ츣pahxwlTTAO7&5}[~9)Ӕce8 Y'3²?ıb4J-O<88.#Xijgǵ &RP8Y <}vm EE\tj[:5+S4+s..;RJzF+J:RHwvp}RoLRm/BNe, *rG`O .>4#6܌⩭Êy3ٴpTR y6dQN sdAM Gl|SH$',{SS.[yH`oV.,2֒VH1#*%P zBt4 Nc㯶[`u fJJ)JЂW ϣ5w2_ZykWv3mpR tdeF7 )e8[7i9-#!Quq8 da&tvB nF^]{jԅcpiQEq*Ṿ_w!)3_N[ D#x63y.Ƶ9򦹯+fRd7+#*mzTQ}6^[Iv"^Dr5^VAI虁F8ޟ[n AmaPK1ʳ}%)3Ԍ!B@ VF-6H};z:I]158^ZmtcE!V-7[ܩjm)K jʔyA=͒ 5ي|֨V*ud<9uo>J#J9=S OG\SrF^E~2 `d_`niZu+FVXmi |5pLL8.\f j&eJNBֵˈ!ŧ<7* n&\Ħ$$ {U\8_>n-q_GZT I>0>ʄBrrOڰZQq 3qӛlR@m.kBHP q}ٓ ɾċۿ,4nr[D-Q`[ +Qlp4:HϠ~:_g.5TGw(B└JbT+[#G(I! 2*ir\!pd0KLv{ٶϖ7nyt53A 4ZM8hpEO:/ qjp?x/!]r^-%!=b9QVr=ڐ&Hi>2Y+!]RJ{HrDZhXZ#_7gkNAM4QUm"Y/8~KZS +RRZ:F@$շDc[uT)Y:cv*vfKw\jc}CMYdR wc _^S%)>ZHA;QR;"ZvS9Bҭ-Ʌ Lq-l Ҷ))NAB2AqPE\Mz[)<ڨxF"ŒsԬ:B~dRFG roӰ0q'<໬mea'Nv*$T`Ķ2O3u<2};ZUe9-'QETTW49W3 'Aw]QJ3z.=iRDcM騢(ewo^ڣs;}<@*PaFrJ$`^]>ECW?ArUq}m| J,R)񔕫|!##"[F-NgGt6ݢٺ;ۣ>=I9 \gq/2D$EEŸc7#H%8*Jޮ6*}̦A(lT%r`VxvI1,v!IϻqJk*R HqvĨ6|C0,|:꼤>p#_e8CKi1^r+`Rۋy^N4RTJINP?5lG[1I$puܚnmBӺ~In xtSCZ@ N `j ^,ciBBv1 V$I$1Q3Ve )`Qnu*dwŽU쭃A$fZNcMrw&۱OK ݲg!q[Sk KhCHPRTVjsgܕ}8aǖR ׮aAFes)!gvґ-E#.׿b*0h%$oϿ<l36cF4`Y844ᾉQSn*1)N%EiH%Gu=´FxFп}Rrz!)!*81#6ܥ-<{^z17 R l7lk٪{Tvv9)[; hZҡaƮSupRuj dpMֿu Ǘ*r$۸')A] EDuݛuڕAS,/(#Z<Á7kҸ,ç/l-:Hy2t?kK8⼞F:k84඼gʤ#~ULymBu)~LtQ7喛h%D +QR C$8P3s*0V ƲH<m=\upXI;|u콐U6F4fds?n&Z~1'8IIAk^89;1]`cdl- #bQEe*kܹ_(˗֢.'QkWܸGsR _%^l DD+%|K [rGG*=2Z6GĊþ>vKŤa#J 9KoKJ`ԵIe$S,-ST]fA[6w@miVsbRV4/G#$jUr o +Bym)cjN K1-+$+:Hd{y4)ٔ5niuՅȞ PKCjy\]~T!(vʜHGF|2JSh U&)$+N Wyqh]q [ l]R⦚}sR\#h }0uy Uq ed@[Uopz("T69mZ0{y;Ա%<ՁҮv9Ayk~jV*g,Y Lf"4 sى K̷6IJ~.ʓH.֙ Rd -'?ߒ_㻧ZIQK`Xe* Mqfm',Ӊ8ElzpَKJqJ9R\I0B”<ꘖ%#K0{sR iog9svҰ 27;9oOdF ,6:ԡލ*5¦!ÀTu6iͲ=LHTsRM@,ۨUֵ۵R3nև}zFF.u]n.!$O2]BJH$F1e| eJpGw*aGeO-P;jֺ+{_I,U߳ҡ\+Ϣ9ΓxD}3E~T)EetQEQ>ʢ}8+U>ȋUOLWפmUTN#; S; ``9۞V;J>.kk(3njk,Wl #zO2*z;vSrk۹!J֯6{mL;$魟(x<0= x3KDM*:PIӞ_h+u+=MsV܌mvڮS.EqFڟ RpBJW¯߿?@W}Z%\h2[ e P>d8gdikA{|u36h,!o `aD~2T`#|,)ۚPTpU7eNJ(6 n7۶>0r .ΰy{ן"SsܱvT? v/l:Pp1NY9ԅ)!%RNNޜAW`Qi,iȩ Sn#*+ns%f\s)@\%$qw4T?%G! ᕺ8Sː&d tXIa6ڲeXݎ5 DBC`BU@=Fc!A99?&䱳Iަ P厺EPt-7+myr+~zp9uC@tA[>*rV8l`3IkHWB˩QAϡ;N*:Jr~!gNc)*S#Y#UNX|@5=k}ki沏0}㧭H !ha H'u(O]u5$$;#e`=`q%.SR 2-;NH˘mK C '|m .53MZ#<Ā~&:R4,9) 99TH7dr "yh!J jhęĆ/BT''Qpl8Kk^:? Q-ēg]7C)>.4y06;2fC YR'|7cQgj!]u Ժ<ʁ'J0TB9d!o,e1K%g_PIdҊtsܮxuL75 m^Zs I|ds6wT+AiGUu@GzYdIq !HF3dYN9!IijA$J2Rw9siY!hg#cg\F1'UX1 :Q!u+rE,ضĸ ">ZRR7Iy>5S.֨ҍҡEj ZioX%%Xcc1h֒]xQQ*I6aC4ja[C#=i緗eh\e^o':͏lÀaT<WY^>wDc{p?N֝YYƝdNN%gXQE^ϵi<_\mzt'i?z`vҲx>O[ssO%iIl(_O?Ssq`K (cvXD$hu-ai>b7_ZQ/J4*AVse"qKSi0ݔݥ(AQ8iJZRZ)8j 4}4*Q8Y4Bأ YO{* }?=7+=Hu(lk%0@é uQp.JKk)qp$%GsK/1h)b[V-!I[u+ׄ'giVx\hAZ ߖRV}٪>[hh\uY(԰ަHI o)EX`"MV'79I@=_PYc !JP^sgrN_lcOV?wTi,ޢC+e`d%C͍R:;pAqe)to%@ݳcU5䭗a!ƕa' 7k{ ni0H5hLQՉŎ~Wf$KX2wP?iLǼ0ƣVLNs+1T]~JTE\įM.q?ZJ?TS\\c&WKl,{?$VsBu;iIZo+;gn.cÉpJXHl2i:Ao*\ӆ.Ӎ_BFy׷խm%)9ebuޞlE6qҒ rH퇈zrXsڣƖAҗH9lNq %كLٜ#~fǻ-(J#T8š|Y97Fb IғD0Sf֗BW%|F]K}D&di82+ ;:5iӔI>HȋFCs[j81xN٤Ce10FYRGV5I z>k/uO!9SU#_RR\ K{cu)eQ;)9YO4^檒CF]j+L4=O1^))ndH'Nyb=I'8Rs׭i^i&ӉQT D)ZBx_s^uC NHE~W?C >|? !qSBE&4QE+i3\{#GL͂+_:g?Ut'}nĎMsS!{8Eᣟ.?瑱!Jq!*'c{3ڪl_5w)K% 9'HmX=[IBUhR2XdO%g$d:ӟvk4#'IAVeWQYڏ>k5R @2+vڊњGe|'jQ'xȯ=Ej|s۫6]48@R<Ԥ ִj~U+N37O_FLJ׭8`S6ؠG gRT۱e-$؜GO\0ΠJQ%?$G}UR .wQRK"( О8;_f=1 dnͱV쏫.+ˁzs/%V~ I:Uit3jƻdy5ۄ-y8I<1IQQJJA=Aϒ]k*i`/`w>wP<cmZ=򮱡S3"ݢ#RpybbV(Ln kPR{yTm:I'[[)YQ#nx=7csFj" ʒH 85gf-l5s'ͦ֗ucn=4Z=sd2d`FSF* I: TU|Ua#4R %G?=H)I$N3dM# ܏N?j ruXb9:k'5**3Lv]%$w+◒O`ښJ{KDeDo½Au$vrKqI%\ )N#rx܆}TGY!ʔώ}K:֖g$Sg.AhNs殐 16ąjC@p/! {ӵX~*{jj$`׫eZ!  %G~_%e\轗' d`!,]3OǮҮ?C}.[KNY N|o7vƻo!X%4EQ\J/4:Dfmb))㴮E!\8n6{IHX^&SNt:СB r]~9o|{*45JN[?5b11cJPt1sa2+RԠ{u<6ERr+,)+O.eDYqNAiFݫ6':arr ^k[ !y&\9PԆ R[uRNH^Cc& 7Y in;x@[z~~l (!!;ca0NCy|xd@{*ih߶>JZ֖NWaHNDn.- m۩pxnuLy)C)j1^p)XqԂE}+tu/qH- J mH7RJKg=FzDe`)%'e qH[8ձI'In꓀cc{.#d}KzZ=h(?p /cjtÍ+QEE 8H/)fГ![X x#G3T?ND}0^VNL)Bv`E:Ki[I;2| `J[,%uy(9Lp_B*m`AӜ`U+vϟ]0i6H2N}:]ˎ -#Zs㨒< J,dCqU3+,N-a?&AV6JFEJ[eeLjZ}cQ%j<ɯlsRo~jgT¤ ysv'5 9%}zCC);QXT2yzs.s3ҡr*/68 8]S<1- ē\qKQH'݊AŕjO c5󯚀 TTgVҢ;vga=+pAHsrN'/^WeI8X+]M Y]|KVLw1|PҮP#X:+009w4|a4> u[d--,CZ̷\@R^u lsv3s_;/G]7?TtܔQE]~JTE\įM.q?ZJ?TS\X_*4qKuii>0sYGO#Z46?Lz|v$M1jڲ8վzW{'͑{'͑ꤳFkWYW{'͑{'͑ꤳFh||<|K4fW{'͑{'͑ꤳFh||<|K5!:~Gi+-p5 *H'`NF O|Q XKA6M<|<|ָ}˓ַGeGrJԄpvH97O0/3s Ԝ UٍT#\ۿE'+/q?%h6G%h6GQĐTwэmdgI#8pi, pQ.iJ/{D=Ty/{D=ThK\RK>lUK>lU%3Fe+QRY4`RK>lUK>lU%3FeZ4˴qԢDccBC:68Րq@88;V'W]U= ]ˡx'B((r2gNl N p\l%h6G%h6G mnd2cq u)DJмdxKםERۊlbC)qDv% ZTc!'-i8Wict{'͑{'͑bgS ܵ`Rr*HǺy2ymE+N$lFA A"i#%QQRY5f||<|K4fW{'͑{'͑ꤳFh||<|K4fW{'͑A bN)8o)mK dDyt0sҝGvڑ5r)ϑª;*+ 舣#B,zwKDie6P4 8$k{'͑1?uLl X}esq'yJ/{D=Ty/{D=Th3*1O#GO#Ifр#J/{D=Ty/{D=Th1O#GO#Ifр#J/{D=Ty/{D=U I&%+#R 8'fN%n\v" o:̺6p]hbqWGXe{]E/{D=Ty/{D=TED5͏n[P8!uZ‘yWnj~lUK>lU%3Fe+QRY4`RK>lUK>lU%3Fe+QRY6 7nn6ĥhNQ+ `3 n'd\f^dz^dzJ5P] Dƒ @:ө+AԭЮiv"xD\n_$%Jy^T*H㇚(ܛ/{D=Ty/{D=Tۛr^ u6V&)$`u di7SJ/{D=Ty/{D=ThOQRK>lUK>lU%3Fe+QRY4`RK>lUK>lU%3Fe-Vq͛k U9O5f/c8q?KՇM;=žjI/mQE|{UW/GI\SR[i$HKe@HUE .!og>&BKV8B5]iV-ƒ((~3^<|K4f#r3+QRY5W{'͑{'͑ꤳFh||<|K4fW{'͑{'͑ꤳFh||<|sz0$@CΨ:d2J#;g .l(Nr{iR ԲNz\vRIO#GO#Ob"Dh괸^H0^#JвC#)*mY$~WI^3 o#}daAq̕%h6G%h6GV2^dz^dz,њ0c)_%h6G%h6GF2^dz^dz,њ0c)_%h6GiĸLm(25LpF3u7DYw:dQʗո‰$$UQz_$HrUZUJ~}(Lz bay,7sO$ ò׽|}L,;W4l8 x]#%||<|K4f0||<|K4fW{'͑{'͑ꤳFh||<|K4fW{'͑{'͑ꤳR _U2$'#=`@^U#V1I| &K>lUK>lUI\,r\a3)A !*#R 2s˝4kFTɷ<Ɇe)D,p*px}Af.ғ!QQ"<_zí):y+bp"\ Q.iJ/{D=Ty/{D=ThK\RK>lUK>lU%3Fe+QRY4`RK>lUK>lU%3FeH/2SQs(Fz9yJq' uR qdkWfo^Ǘ 9 ~W(rɵ\įM]~JTQrQj(QNjy;NIR[=Wͫ].Y`ZfYt>2beQT(Î0%'7'|گzHkh h\=WTu{" UX>8 ~hUWjzJo=R<ƫwUTj'|ڣ pQT]s~acU;*5U pQ_8k*.0G1}U_8kD⯂5Tt\ߘzuN>\\g3ԧ&舆\KZ#F8TIӲpj pSsӦ[Ve9= RM#\gm?.PUFm,qu7K *\ s<(iA]b zA*N†M>:z/Z:;v7֠w}?hUWjC.4Ԗۂ),*FG,wr*Nfkz{Me(M篪\f>"tjzCuޥO4}qW_>8 ~iBa3~a4Ud#VN*+_G'|ڮ\ߘzsGWQhUWjN*+_GIQu9WT#VN*+_G'|ڣƫwUTj'|ڣ pQT]s~acU;&ֱ?"r[nH\Sh*Ǐp:PRd*!}ckڽU⽩i1<;-{?D#Hx~ڽm^>ڽm^ ~Kk/c;Ugm^6U`=)pl)ӝjK(IDHWbxsphu oV&ކIijUX>8 ~hUWjIQu<ƫwUTj'|ڣ pQT]s~acU;*5U pQ_8k*.0G1}U_8kD⯂5Tt\ߘzuN>x9_N8 ~+ x&F}j8RNAV㶡.Т{ DPS1;/Jl\e[ۼwXauM4J * b{\Uqs  AB$(*=][Z򵨩Ghd'|ڤmP.u\Ӏֵl'-=eLK!W8+wZ u?/_ p5o~vHyV Gl pS4T1=囝hϊjz;/OK*5U pQ_8kT1}U_8kD⯂5Tt\ߘzuN>U`D⯂5T}qW_:Jo=QjyE_F}qW_>8 ~%E75]S꫇B=*Xwj? pUYz@].p|u:]sB啤lI@rУu$l$0{STTU-7x}{ڽT}{ڽU줨U`D⯂5T}qW_UjyE_F}qW_>8 ~%E75]SUX>8 ~hUWjTsGWQhUWjN*+_GIQu9WT#莎dt2$JD'|ڧ .4Uqm<:A$'d۳lW܂nܦeb9{=/ުVN*+_G'|ڭT1}U_8kD⯂5Tt\ߘzuN>U`D⯂5T}qW_:Jo=QjyE_F}qW_>8 ~%E75]SUX>8 ~hUWjTsGZ=!;8s^,e@qJd $'䭫_ꯟE4r֗FE`{= {H7:䤨߳}W}WFWv?Ev2jW-5|Vj$گ]TroR+C|IPZVN*+_G'|گ_T]s~a1}U_8kD⯂5Tt\ߘzuN>U`D⯂5T}qW_:Jo=QjyE_F}qW_>8 ~%E75]S6辴BKl(=kxN3hUWjC3nLK.նj+匰Nt18R]-Z͔qI;n }.נ%#$ ̮j&shiC!pT:T%DN4)GqW_>8 ~*z8@s:GI )kO "|&j:ʼ#J:+Lh3RdIQ99? hUWjr̓ ,R$ 5U pQ_8kUG1}U_8kD⯂5Tt\ߘzuN>U`D⯂5T}qW_:Jo=QjyE_F}qW_>8 ~%E75]Sꭗظs/?Y'|ڭ;+t~>%&8g դܓjO>ԲHi& -=IQc3lToWͫGWͫ_9^J=]7V}W}.ԯ-wV O:og6SW4jUX>8 ~hUWjT]s~ajyE_F}qW_>8 ~%E75]SUX>8 ~hUWjTsGWQhUWjN*+_GIQu9WT#VN*+_G'|ڣƫwN"E/Ch&!oV:NOn8BіH(Մ'ؓL񙶦my(dY䑶q7D⯂5U.}Cu6w [@ka: ;~smk{V֕̇t\Ŷm#J4!%J7O!ΓpJl*ncBaa8K]J @Gڜ\G.3ߝ2}en/e9'U`D⯂5T}qW_:Jo=QjyE_F}qW_>8 ~%E75]SUX>8 ~hUWjTsGo]]9WBvc*x5SP9"@{Ө<1D⯂5Um]K$<WV=a#-U_8kD⯂5UT]s~a9WT#VN*+_G'|ڣƫwUTj'|ڣ pQT]s~acU;*5U pQ_8k*.0G1}U^;rTݑeιkTrhuIP8y/'|ڧG步ɷP\0ҵ54S^v}ɘ Drw%`.tZf2efCaW\!zqdS=fl+ŵǖÑmnbHsJR !% {;!8 ~8p[LKpm l+eDX]Ķv ~r\Yp 6iQI9׹/#4VN*+_G'|ڭchhT*5U pQ_8k]%E7<ƫwUTj'|ڣ pQT]s~acU;*5U pQ_8k*.0G1}U_8kD⯂5Tt\ߘzuN>!_!\ZZErjXHWz{UU$bЃÂA,\(/mATvjQvjW^\įM>mv%#B$5)minigalaxy-1.1.0/scripts/000077500000000000000000000000001414231301100153305ustar00rootroot00000000000000minigalaxy-1.1.0/scripts/add-language.sh000077500000000000000000000003521414231301100202000ustar00rootroot00000000000000#!/bin/bash cd "$(dirname "$0")"/../data/po if [ -z "${1}" ]; then echo "Please select a language like: ${0} en_US" fi msginit --locale="${1}" --input=minigalaxy.pot LANGFILE="$(echo ${1}|cut -f1 -d'_').po" xdg-open "${LANGFILE}" minigalaxy-1.1.0/scripts/compile-translations.sh000077500000000000000000000003721414231301100220400ustar00rootroot00000000000000#!/bin/bash cd "$(dirname "$0")"/../data/po OUTPUTFILE="minigalaxy.mo" for langfile in *.po; do OUTPUTDIR="../mo/$(echo ${langfile}|cut -f1 -d '.')/LC_MESSAGES" mkdir -p "${OUTPUTDIR}" msgfmt -o "${OUTPUTDIR}/${OUTPUTFILE}" "${langfile}" done minigalaxy-1.1.0/scripts/missing-translations.sh000077500000000000000000000002541414231301100220600ustar00rootroot00000000000000#!/bin/bash cd "$(dirname "$0")"/.. # Update each po file for langfile in data/po/*.po; do echo "file: ${langfile}" msgattrib --untranslated "${langfile}" echo "" done minigalaxy-1.1.0/scripts/take-screenshot.sh000077500000000000000000000005421414231301100207670ustar00rootroot00000000000000# Variables cd "$(dirname "$0")"/.. IMAGE="screenshot.jpg" # Delete the old screenshot rm -f ${IMAGE} # Start Minigalaxy bin/minigalaxy & # Wait for Minigalaxy sleep 5s # Get the window id WID="$(xwininfo -tree -root|grep Minigalaxy|tail -1|awk '{print $1}')" # Make the screenshot import -window "${WID}" -strip -trim "${PWD}/${IMAGE}" && kill %1 minigalaxy-1.1.0/scripts/update-translation-files.sh000077500000000000000000000007131414231301100226060ustar00rootroot00000000000000#!/bin/bash cd "$(dirname "$0")"/.. POTFILE="data/po/minigalaxy.pot" # Generate the pot file xgettext --from-code=UTF-8 --keyword=_ --sort-output --language=Python minigalaxy/*.py minigalaxy/ui/*.py bin/minigalaxy -o "${POTFILE}" xgettext --join-existing --from-code=UTF-8 --keyword=translatable --sort-output --language=Glade data/ui/*.ui -o "${POTFILE}" # Update each po file for langfile in data/po/*.po; do msgmerge -U "${langfile}" "${POTFILE}" done minigalaxy-1.1.0/setup.py000066400000000000000000000056361414231301100153650ustar00rootroot00000000000000from setuptools import setup, find_packages from glob import glob import subprocess from minigalaxy.version import VERSION # Generate the translations subprocess.run(['bash', 'scripts/compile-translations.sh']) setup( name="minigalaxy", version=VERSION, packages=find_packages(exclude=['tests']), scripts=['bin/minigalaxy'], data_files=[ ('share/applications', ['data/io.github.sharkwouter.Minigalaxy.desktop']), ('share/icons/hicolor/128x128/apps', ['data/icons/128x128/io.github.sharkwouter.Minigalaxy.png']), ('share/icons/hicolor/192x192/apps', ['data/icons/192x192/io.github.sharkwouter.Minigalaxy.png']), ('share/minigalaxy/ui', glob('data/ui/*.ui')), ('share/minigalaxy/images', glob('data/images/*')), ('share/metainfo', ['data/io.github.sharkwouter.Minigalaxy.metainfo.xml']), # Add translations ('share/minigalaxy/translations/de/LC_MESSAGES/', ['data/mo/de/LC_MESSAGES/minigalaxy.mo']), ('share/minigalaxy/translations/es/LC_MESSAGES/', ['data/mo/es/LC_MESSAGES/minigalaxy.mo']), ('share/minigalaxy/translations/fr/LC_MESSAGES/', ['data/mo/fr/LC_MESSAGES/minigalaxy.mo']), ('share/minigalaxy/translations/nb_NO/LC_MESSAGES/', ['data/mo/nb_NO/LC_MESSAGES/minigalaxy.mo']), ('share/minigalaxy/translations/nl/LC_MESSAGES/', ['data/mo/nl/LC_MESSAGES/minigalaxy.mo']), ('share/minigalaxy/translations/nn_NO/LC_MESSAGES/', ['data/mo/nn_NO/LC_MESSAGES/minigalaxy.mo']), ('share/minigalaxy/translations/pl/LC_MESSAGES/', ['data/mo/pl/LC_MESSAGES/minigalaxy.mo']), ('share/minigalaxy/translations/pt_BR/LC_MESSAGES/', ['data/mo/pt_BR/LC_MESSAGES/minigalaxy.mo']), ('share/minigalaxy/translations/ru_RU/LC_MESSAGES/', ['data/mo/ru_RU/LC_MESSAGES/minigalaxy.mo']), ('share/minigalaxy/translations/tr/LC_MESSAGES/', ['data/mo/tr/LC_MESSAGES/minigalaxy.mo']), ('share/minigalaxy/translations/zh_CN/LC_MESSAGES/', ['data/mo/zh_CN/LC_MESSAGES/minigalaxy.mo']), ('share/minigalaxy/translations/zh_TW/LC_MESSAGES/', ['data/mo/zh_TW/LC_MESSAGES/minigalaxy.mo']), ], # Project uses reStructuredText, so ensure that the docutils get # installed or upgraded on the target machine install_requires=[ 'PyGObject>=3.30', 'requests', ], # metadata to display on PyPI author="Wouter Wijsman", author_email="wwijsman@live.nl", description="A simple GOG Linux client", keywords="GOG gog client gaming gtk Gtk", url="https://github.com/sharkwouter/minigalaxy", # project home page, if any project_urls={ "Bug Tracker": "https://github.com/sharkwouter/minigalaxy/issues", "Documentation": "https://github.com/sharkwouter/minigalaxy/blob/master/README.md", "Source Code": "https://github.com/sharkwouter/minigalaxy", }, classifiers=[ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", ] ) minigalaxy-1.1.0/tests/000077500000000000000000000000001414231301100150035ustar00rootroot00000000000000minigalaxy-1.1.0/tests/__init__.py000066400000000000000000000000001414231301100171020ustar00rootroot00000000000000minigalaxy-1.1.0/tests/test_api.py000066400000000000000000000321671414231301100171760ustar00rootroot00000000000000from unittest import TestCase, mock from unittest.mock import MagicMock import sys import requests import time m_constants = MagicMock() m_config = MagicMock() sys.modules['minigalaxy.constants'] = m_constants sys.modules['minigalaxy.config'] = m_config from minigalaxy.api import Api # noqa: E402 from minigalaxy.game import Game # noqa: E402 API_GET_INFO_TOONSTRUCK = {'downloads': {'installers': [ {'id': 'installer_windows_en', 'name': 'Toonstruck', 'os': 'windows', 'language': 'en', 'language_full': 'English', 'version': '1.0', 'total_size': 939524096, 'files': [{'id': 'en1installer0', 'size': 1048576, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/en1installer0'}, {'id': 'en1installer1', 'size': 938475520, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/en1installer1'}]}, {'id': 'installer_mac_en', 'name': 'Toonstruck', 'os': 'mac', 'language': 'en', 'language_full': 'English', 'version': 'gog-3', 'total_size': 975175680, 'files': [{'id': 'en2installer0', 'size': 975175680, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/en2installer0'}]}, {'id': 'installer_linux_en', 'name': 'Toonstruck', 'os': 'linux', 'language': 'en', 'language_full': 'English', 'version': 'gog-2', 'total_size': 963641344, 'files': [{'id': 'en3installer0', 'size': 963641344, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/en3installer0'}]}, {'id': 'installer_windows_fr', 'name': 'Toonstruck', 'os': 'windows', 'language': 'fr', 'language_full': 'français', 'version': '1.0', 'total_size': 985661440, 'files': [{'id': 'fr1installer0', 'size': 1048576, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/fr1installer0'}, {'id': 'fr1installer1', 'size': 984612864, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/fr1installer1'}]}, {'id': 'installer_mac_fr', 'name': 'Toonstruck', 'os': 'mac', 'language': 'fr', 'language_full': 'français', 'version': 'gog-3', 'total_size': 1023410176, 'files': [{'id': 'fr2installer0', 'size': 1023410176, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/fr2installer0'}]}, {'id': 'installer_linux_fr', 'name': 'Toonstruck', 'os': 'linux', 'language': 'fr', 'language_full': 'français', 'version': 'gog-2', 'total_size': 1011875840, 'files': [{'id': 'fr3installer0', 'size': 1011875840, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/fr3installer0'}]} ]}} class TestApi(TestCase): def test_get_login_url(self): api = Api() exp = "https://auth.gog.com/auth?client_id=46899977096215655&redirect_uri=https%3A%2F%2Fembed.gog.com%2Fon_login_success%3Forigin%3Dclient&response_type=code&layout=client2" obs = api.get_login_url() self.assertEqual(exp, obs) def test_get_redirect_url(self): api = Api() exp = "https://embed.gog.com/on_login_success?origin=client" obs = api.get_redirect_url() self.assertEqual(exp, obs) def test1_can_connect(self): api = Api() m_constants.return_value = True exp = True obs = api.can_connect() self.assertEqual(exp, obs) def test2_can_connect(self): api = Api() m_constants.SESSION.get.side_effect = requests.exceptions.ConnectionError(mock.Mock(status="Connection Error")) exp = False obs = api.can_connect() self.assertEqual(exp, obs) def test1_get_download_info(self): api = Api() api.get_info = MagicMock() api.get_info.return_value = API_GET_INFO_TOONSTRUCK m_config.Config.get.return_value = "pl" test_game = Game("Test Game") exp = {'id': 'installer_linux_en', 'name': 'Toonstruck', 'os': 'linux', 'language': 'en', 'language_full': 'English', 'version': 'gog-2', 'total_size': 963641344, 'files': [{'id': 'en3installer0', 'size': 963641344, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/en3installer0'}]} obs = api.get_download_info(test_game) self.assertEqual(exp, obs) def test2_get_download_info(self): api = Api() api.get_info = MagicMock() api.get_info.return_value = API_GET_INFO_TOONSTRUCK m_config.Config.get.return_value = "fr" test_game = Game("Test Game") exp = {'id': 'installer_linux_fr', 'name': 'Toonstruck', 'os': 'linux', 'language': 'fr', 'language_full': 'français', 'version': 'gog-2', 'total_size': 1011875840, 'files': [{'id': 'fr3installer0', 'size': 1011875840, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/fr3installer0'}]} obs = api.get_download_info(test_game) self.assertEqual(exp, obs) def test3_get_download_info(self): api = Api() api.get_info = MagicMock() api.get_info.return_value = {'downloads': {'installers': [ {'id': 'installer_windows_en', 'name': 'Toonstruck', 'os': 'windows', 'language': 'en', 'language_full': 'English', 'version': '1.0', 'total_size': 939524096, 'files': [{'id': 'en1installer0', 'size': 1048576, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/en1installer0'}, {'id': 'en1installer1', 'size': 938475520, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/en1installer1'}]}, {'id': 'installer_mac_en', 'name': 'Toonstruck', 'os': 'mac', 'language': 'en', 'language_full': 'English', 'version': 'gog-3', 'total_size': 975175680, 'files': [{'id': 'en2installer0', 'size': 975175680, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/en2installer0'}]}, {'id': 'installer_windows_fr', 'name': 'Toonstruck', 'os': 'windows', 'language': 'fr', 'language_full': 'français', 'version': '1.0', 'total_size': 985661440, 'files': [{'id': 'fr1installer0', 'size': 1048576, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/fr1installer0'}, {'id': 'fr1installer1', 'size': 984612864, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/fr1installer1'}]}, {'id': 'installer_mac_fr', 'name': 'Toonstruck', 'os': 'mac', 'language': 'fr', 'language_full': 'français', 'version': 'gog-3', 'total_size': 1023410176, 'files': [{'id': 'fr2installer0', 'size': 1023410176, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/fr2installer0'}]} ]}} m_config.Config.get.return_value = "en" test_game = Game("Test Game") exp = {'id': 'installer_windows_en', 'name': 'Toonstruck', 'os': 'windows', 'language': 'en', 'language_full': 'English', 'version': '1.0', 'total_size': 939524096, 'files': [{'id': 'en1installer0', 'size': 1048576, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/en1installer0'}, {'id': 'en1installer1', 'size': 938475520, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/en1installer1'}]} obs = api.get_download_info(test_game) self.assertEqual(exp, obs) def test4_get_download_info(self): api = Api() dlc_test_installer = API_GET_INFO_TOONSTRUCK["downloads"]["installers"] m_config.Config.get.return_value = "en" test_game = Game("Test Game") exp = {'id': 'installer_linux_en', 'name': 'Toonstruck', 'os': 'linux', 'language': 'en', 'language_full': 'English', 'version': 'gog-2', 'total_size': 963641344, 'files': [{'id': 'en3installer0', 'size': 963641344, 'downlink': 'https://api.gog.com/products/1207666633/downlink/installer/en3installer0'}]} obs = api.get_download_info(test_game, dlc_installers=dlc_test_installer) self.assertEqual(exp, obs) def test1_get_library(self): api = Api() api.active_token = True response_dict = {'totalPages': 1, 'products': [{'id': 1097893768, 'title': 'Neverwinter Nights: Enhanced Edition', 'image': '//images-2.gog-statics.com/8706f7fb87a4a41bc34254f3b49f59f96cf13d067b2c8bbfd8d41c327392052a', 'url': '/game/neverwinter_nights_enhanced_edition_pack', 'worksOn': {'Windows': True, 'Mac': True, 'Linux': True}}]} api.active_token_expiration_time = time.time() + 10.0 response_mock = MagicMock() response_mock.json.return_value = response_dict m_constants.SESSION.get.return_value = response_mock exp = "Neverwinter Nights: Enhanced Edition" retrieved_games, err_msg = api.get_library() obs = retrieved_games[0].name self.assertEqual(exp, obs) def test2_get_library(self): api = Api() api.active_token = False api.active_token_expiration_time = time.time() + 10.0 response_mock = MagicMock() response_mock.json.return_value = {} m_constants.SESSION.get.return_value = response_mock exp = "Couldn't connect to GOG servers" retrieved_games, obs = api.get_library() self.assertEqual(exp, obs) def test1_get_version(self): api = Api() test_game = Game("Test Game", platform="linux") exp = "gog-2" obs = api.get_version(test_game, gameinfo=API_GET_INFO_TOONSTRUCK) self.assertEqual(exp, obs) def test2_get_version(self): api = Api() test_game = Game("Test Game", platform="linux") dlc_name = "Test DLC" game_info = API_GET_INFO_TOONSTRUCK game_info["expanded_dlcs"] = [{"title": dlc_name, "downloads": {"installers": [{"os": "linux", "version": "1.2.3.4"}]}}] exp = "1.2.3.4" obs = api.get_version(test_game, gameinfo=API_GET_INFO_TOONSTRUCK, dlc_name=dlc_name) self.assertEqual(exp, obs) def test_get_download_file_md5(self): api = Api() api._Api__request = MagicMock() m_constants.SESSION.get.side_effect = MagicMock() m_constants.SESSION.get().text = ''' 7e62ce101221ccdae2e9bff5c16ed9e0 b80960a2546ce647bffea87f85385535 5464b4499cd4368bb83ea35f895d3560 0261b9225fc10c407df083f6d254c47b ''' exp = "8acedf66c0d2986e7dee9af912b7df4f" obs = api.get_download_file_md5("url") self.assertEqual(exp, obs) def test1_get_gamesdb_info(self): api = Api() api._Api__request_gamesdb = MagicMock() api._Api__request_gamesdb.side_effect = [{}] test_game = Game("Test Game") exp = {"cover": "", "vertical_cover": "", "background": "", "genre": {}, "summary": {}} obs = api.get_gamesdb_info(test_game) self.assertEqual(exp, obs) def test2_get_gamesdb_info(self): api = Api() api._Api__request_gamesdb = MagicMock() api._Api__request_gamesdb.side_effect = [{'id': '51622789000874509', 'game_id': '51154268886064420', 'platform_id': 'gog', 'external_id': '1508702879', 'game': {'genres': [{'id': '51071904337940794', 'name': {'*': 'Strategy', 'en-US': 'Strategy'}, 'slug': 'strategy'}], 'summary': {'*': 'Stellaris description'}, 'visible_in_library': True, 'aggregated_rating': 78.5455, 'game_modes': [{'id': '53051895165351137', 'name': 'Single player', 'slug': 'single-player'}, {'id': '53051908711988230', 'name': 'Multiplayer', 'slug': 'multiplayer'}], 'horizontal_artwork': {'url_format': 'https://images.gog.com/742acfb77ec51ca48c9f96947bf1fc0ad8f0551c9c9f338021e8baa4f08e449f{formatter}.{ext}?namespace=gamesdb'}, 'background': {'url_format': 'https://images.gog.com/742acfb77ec51ca48c9f96947bf1fc0ad8f0551c9c9f338021e8baa4f08e449f{formatter}.{ext}?namespace=gamesdb'}, 'vertical_cover': {'url_format': 'https://images.gog.com/8d822a05746670fb2540e9c136f0efaed6a2d5ab698a9f8bd7f899d21f2022d2{formatter}.{ext}?namespace=gamesdb'}, 'cover': {'url_format': 'https://images.gog.com/8d822a05746670fb2540e9c136f0efaed6a2d5ab698a9f8bd7f899d21f2022d2{formatter}.{ext}?namespace=gamesdb'}, 'logo': {'url_format': 'https://images.gog.com/c50a5d26c42d84b4b884976fb89d10bb3e97ebda0c0450285d92b8c50844d788{formatter}.{ext}?namespace=gamesdb'}, 'icon': {'url_format': 'https://images.gog.com/c85cf82e6019dd52fcdf1c81d17687dd52807835f16aa938abd2a34e5d9b99d0{formatter}.{ext}?namespace=gamesdb'}, 'square_icon': {'url_format': 'https://images.gog.com/c3adc81bf37f1dd89c9da74c13967a08b9fd031af4331750dbc65ab0243493c8{formatter}.{ext}?namespace=gamesdb'}}}] test_game = Game("Stellaris") exp = {'cover': 'https://images.gog.com/8d822a05746670fb2540e9c136f0efaed6a2d5ab698a9f8bd7f899d21f2022d2.png?namespace=gamesdb', 'vertical_cover': 'https://images.gog.com/8d822a05746670fb2540e9c136f0efaed6a2d5ab698a9f8bd7f899d21f2022d2.png?namespace=gamesdb', 'background': 'https://images.gog.com/742acfb77ec51ca48c9f96947bf1fc0ad8f0551c9c9f338021e8baa4f08e449f.png?namespace=gamesdb', 'summary': {'*': 'Stellaris description'}, 'genre': {'*': 'Strategy', 'en-US': 'Strategy'}} obs = api.get_gamesdb_info(test_game) self.assertEqual(exp, obs) del sys.modules['minigalaxy.constants'] del sys.modules['minigalaxy.config'] del sys.modules["minigalaxy.game"] minigalaxy-1.1.0/tests/test_config.py000066400000000000000000000047211414231301100176650ustar00rootroot00000000000000import sys from unittest import TestCase, mock from unittest.mock import MagicMock, patch, mock_open from minigalaxy.config import DEFAULT_CONFIGURATION JSON_DEFAULT_CONFIGURATION = str(DEFAULT_CONFIGURATION).replace("'", "\"").replace("False", "false").replace("True", "true") m_thread = MagicMock() sys.modules['threading'] = m_thread class TestConfig(TestCase): @mock.patch('os.path.exists') def test_get(self, mock_isfile): mock_isfile.return_value = True config = JSON_DEFAULT_CONFIGURATION with patch("builtins.open", mock_open(read_data=config)): from minigalaxy.config import Config Config.first_run = True Config._Config__config = DEFAULT_CONFIGURATION lang = Config.get("lang") exp = "en" obs = lang self.assertEqual(exp, obs) @mock.patch('os.path.isdir') @mock.patch('os.path.exists') def test_create_config(self, mock_exists, mock_isdir): mock_exists.side_effect = [False, True] mock_isdir.return_value = True with patch("builtins.open", mock_open()) as mock_config: from minigalaxy.config import Config Config.first_run = False Config.get("") mock_c = mock_config.mock_calls write_string = "" for kall in mock_c: name, args, kwargs = kall if name == "().write": write_string = "{}{}".format(write_string, args[0]) exp = JSON_DEFAULT_CONFIGURATION obs = write_string self.assertEqual(exp, obs) @mock.patch('os.path.exists') def test_set(self, mock_isfile): mock_isfile.return_value = True config = JSON_DEFAULT_CONFIGURATION with patch("builtins.open", mock_open(read_data=config)): from minigalaxy.config import Config Config.first_run = True Config.set("lang", "pl") lang = Config.get("lang") exp = "pl" obs = lang self.assertEqual(exp, obs) @mock.patch('os.path.exists') def test_unset(self, mock_isfile): mock_isfile.return_value = True config = JSON_DEFAULT_CONFIGURATION with patch("builtins.open", mock_open(read_data=config)): from minigalaxy.config import Config Config.first_run = True Config.unset("lang") lang = Config.get("lang") exp = None obs = lang self.assertEqual(exp, obs) del sys.modules['threading'] minigalaxy-1.1.0/tests/test_download.py000066400000000000000000000037161414231301100202320ustar00rootroot00000000000000from unittest import TestCase from unittest.mock import MagicMock, Mock from minigalaxy.download import Download class TestDownload(TestCase): def test1_set_progress(self): mock_progress_function = MagicMock() download = Download("test_url", "test_save_location", progress_func=mock_progress_function) download.set_progress(50) kall = mock_progress_function.mock_calls[-1] name, args, kwargs = kall exp = 50 obs = args[0] self.assertEqual(exp, obs) def test2_set_progress(self): mock_progress_function = MagicMock() download = Download("test_url", "test_save_location", progress_func=mock_progress_function, out_of_amount=2) download.set_progress(32) kall = mock_progress_function.mock_calls[-1] name, args, kwargs = kall exp = 16 obs = args[0] self.assertEqual(exp, obs) def test1_finish(self): mock_finish_function = MagicMock() download = Download("test_url", "test_save_location", finish_func=mock_finish_function) download.finish() exp = 2 obs = len(mock_finish_function.mock_calls) self.assertEqual(exp, obs) def test2_finish(self): mock_finish_function = MagicMock() mock_finish_function.side_effect = FileNotFoundError(Mock(status="Connection Error")) mock_cancel_function = MagicMock() download = Download("test_url", "test_save_location", finish_func=mock_finish_function, cancel_func=mock_cancel_function) download.finish() exp = 2 obs = len(mock_cancel_function.mock_calls) self.assertEqual(exp, obs) def test_cancel(self): mock_cancel_function = MagicMock() download = Download("test_url", "test_save_location", cancel_func=mock_cancel_function) download.cancel() exp = 2 obs = len(mock_cancel_function.mock_calls) self.assertEqual(exp, obs) minigalaxy-1.1.0/tests/test_game.py000066400000000000000000000405721414231301100173350ustar00rootroot00000000000000import unittest import sys import os from unittest.mock import MagicMock, mock_open, patch m_config = MagicMock() m_paths = MagicMock() sys.modules['minigalaxy.config'] = m_config sys.modules['minigalaxy.paths'] = m_paths m_paths.CONFIG_GAMES_DIR = "/home/user/.config/minigalaxy/games/" from minigalaxy.game import Game # noqa: E402 class TestGame(unittest.TestCase): def test_strip_within_comparison(self): game1 = Game("!@#$%^&*(){}[]\"'_-<>.,;:") game2 = Game("") game3 = Game("hallo") game4 = Game("Hallo") game5 = Game("Hallo!") self.assertEqual(game1, game2) self.assertNotEqual(game2, game3) self.assertEqual(game3, game4) self.assertEqual(game3, game5) def test_local_and_api_comparison(self): larry1_api = Game("Leisure Suit Larry 1 - In the Land of the Lounge Lizards", game_id=1207662033) larry1_local_gog = Game("Leisure Suit Larry", install_dir="/home/user/Games/Leisure Suit Larry", game_id=1207662033) larry1_local_minigalaxy = Game("Leisure Suit Larry", install_dir="/home/wouter/Games/Leisure Suit Larry 1 - In the Land of the Lounge Lizards", game_id=1207662033) self.assertEqual(larry1_local_gog, larry1_local_minigalaxy) self.assertEqual(larry1_local_minigalaxy, larry1_api) self.assertEqual(larry1_local_gog, larry1_api) larry2_api = Game("Leisure Suit Larry 2 - Looking For Love (In Several Wrong Places)", game_id=1207662053) larry2_local_minigalaxy = Game("Leisure Suit Larry 2", install_dir="/home/user/Games/Leisure Suit Larry 2 - Looking For Love (In Several Wrong Places)", game_id=1207662053) larry2_local_gog = Game("Leisure Suit Larry 2", install_dir="/home/user/Games/Leisure Suit Larry 2", game_id=1207662053) self.assertNotEqual(larry1_api, larry2_api) self.assertNotEqual(larry2_local_gog, larry1_api) self.assertNotEqual(larry2_local_gog, larry1_local_gog) self.assertNotEqual(larry2_local_gog, larry1_local_minigalaxy) self.assertNotEqual(larry2_local_minigalaxy, larry1_api) self.assertNotEqual(larry2_local_minigalaxy, larry1_local_minigalaxy) def test_local_comparison(self): larry1_local_gog = Game("Leisure Suit Larry", install_dir="/home/user/Games/Leisure Suit Larry", game_id=1207662033) larry1_vga_local_gog = Game("Leisure Suit Larry VGA", install_dir="/home/user/Games/Leisure Suit Larry VGA", game_id=1207662043) self.assertNotEqual(larry1_local_gog, larry1_vga_local_gog) def test1_is_update_available(self): game = Game("Version Test game") game.load_minigalaxy_info_json = MagicMock() game.load_minigalaxy_info_json.return_value = {'version': 'gog-2'} expected = True observed = game.is_update_available("gog-3") self.assertEqual(expected, observed) def test2_is_update_available(self): game = Game("Version Test game") game.load_minigalaxy_info_json = MagicMock() game.load_minigalaxy_info_json.return_value = {'version': "91.8193.16"} expected = False observed = game.is_update_available("91.8193.16") self.assertEqual(expected, observed) def test3_is_update_available(self): game = Game("Version Test game") game.load_minigalaxy_info_json = MagicMock() game.load_minigalaxy_info_json.return_value = {'version': "91.8193.16", "dlcs": {"Neverwinter Nights: Wyvern Crown of Cormyr": {"version": "82.8193.20.1"}}} expected = True observed = game.is_update_available("91.8193.16", dlc_title="Neverwinter Nights: Wyvern Crown of Cormyr") self.assertEqual(expected, observed) def test4_is_update_available(self): game = Game("Version Test game") game.load_minigalaxy_info_json = MagicMock() game.load_minigalaxy_info_json.return_value = {'version': "91.8193.16", "dlcs": {"Neverwinter Nights: Wyvern Crown of Cormyr": {"version": "82.8193.20.1"}}} expected = False observed = game.is_update_available("82.8193.20.1", dlc_title="Neverwinter Nights: Wyvern Crown of Cormyr") self.assertEqual(expected, observed) def test1_get_install_directory_name(self): game = Game("Get Install Directory Test1") expected = "Get Install Directory Test1" observed = game.get_install_directory_name() self.assertEqual(expected, observed) def test2_get_install_directory_name(self): game = Game("Get\r Install\n Directory Test2!@#$%") expected = "Get Install Directory Test2" observed = game.get_install_directory_name() self.assertEqual(expected, observed) @unittest.mock.patch('os.path.isfile') def test1_fallback_read_installed_version(self, mock_isfile): mock_isfile.return_value = True gameinfo = """Beneath A Steel Sky gog-2 20150 en-US 1207658695 1207658695 664777434""" game = Game("Game Name test1") expected = "gog-2" with patch("builtins.open", mock_open(read_data=gameinfo)): observed = game.fallback_read_installed_version() self.assertEqual(expected, observed) @unittest.mock.patch('os.path.isfile') def test2_fallback_read_installed_version(self, mock_isfile): mock_isfile.return_value = False gameinfo = """Beneath A Steel Sky gog-2 20150 en-US 1207658695 1207658695 664777434""" game = Game("Game Name test2") expected = "0" with patch("builtins.open", mock_open(read_data=gameinfo)): observed = game.fallback_read_installed_version() self.assertEqual(expected, observed) @unittest.mock.patch('os.path.exists') def test1_set_info(self, mock_exists): mock_exists.return_value = True json_content = '{"version": "gog-2"}' with patch("builtins.open", mock_open(read_data=json_content)) as m: game = Game("Game Name test2") game.set_info("version", "gog-3") mock_c = m.mock_calls write_string = "" for kall in mock_c: name, args, kwargs = kall if name == "().write": write_string = "{}{}".format(write_string, args[0]) expected = '{"version": "gog-3"}' observed = write_string self.assertEqual(expected, observed) @unittest.mock.patch('os.path.exists') @unittest.mock.patch('os.makedirs') def test2_set_dlc_info(self, mock_makedirs, mock_exists): mock_exists.return_value = False dlc_name = "Neverwinter Nights: Wyvern Crown of Cormyr" with patch("builtins.open", mock_open()) as m: game = Game("Neverwinter Nights") game.set_dlc_info("version", "82.8193.20.1", dlc_name) mock_c = m.mock_calls write_string = "" for kall in mock_c: name, args, kwargs = kall if name == "().write": write_string = "{}{}".format(write_string, args[0]) expected = '{"dlcs": {"Neverwinter Nights: Wyvern Crown of Cormyr": {"version": "82.8193.20.1"}}}' observed = write_string self.assertEqual(expected, observed) def test_get_stripped_name(self): name_string = "Beneath A Steel Sky" game = Game(name_string) expected = "BeneathASteelSky" observed = game.get_stripped_name() self.assertEqual(expected, observed) @unittest.mock.patch('os.path.isfile') def test1_load_minigalaxy_info_json(self, mock_isfile): mock_isfile.side_effect = [True] json_content = '{"version": "gog-2"}' with patch("builtins.open", mock_open(read_data=json_content)): game = Game("Game Name test2") jscon_dict = game.load_minigalaxy_info_json() expected = {"version": "gog-2"} observed = jscon_dict self.assertEqual(expected, observed) @unittest.mock.patch('os.path.isfile') def test2_load_minigalaxy_info_json(self, mock_isfile): mock_isfile.side_effect = [False] json_content = '{"version": "gog-2"}' with patch("builtins.open", mock_open(read_data=json_content)): game = Game("Game Name test2") jscon_dict = game.load_minigalaxy_info_json() expected = {} observed = jscon_dict self.assertEqual(expected, observed) @unittest.mock.patch("minigalaxy.config.Config") @unittest.mock.patch('os.makedirs') def test_save_minigalaxy_info_json(self, mock_makedirs, mock_config): json_dict = {"version": "gog-2"} with patch("builtins.open", mock_open()) as m: game = Game("Neverwinter Nights") game.save_minigalaxy_info_json(json_dict) mock_c = m.mock_calls write_string = "" for kall in mock_c: name, args, kwargs = kall if name == "().write": write_string = "{}{}".format(write_string, args[0]) expected = '{"version": "gog-2"}' observed = write_string self.assertEqual(expected, observed) @unittest.mock.patch('os.path.exists') def test1_is_installed(self, mock_isfile): mock_isfile.side_effect = [False] game = Game("Game Name Test") game.load_minigalaxy_info_json = MagicMock() exp = False obs = game.is_installed() self.assertEqual(exp, obs) @unittest.mock.patch('os.path.exists') def test2_is_installed(self, mock_isfile): mock_isfile.side_effect = [True] game = Game("Game Name Test", install_dir="Test Install Dir") game.load_minigalaxy_info_json = MagicMock() game.load_minigalaxy_info_json.return_value = {"dlcs": {"Neverwinter Nights: Wyvern Crown of Cormyr": {"version": "82.8193.20.1"}}} exp = True obs = game.is_installed(dlc_title="Neverwinter Nights: Wyvern Crown of Cormyr") self.assertEqual(exp, obs) @unittest.mock.patch('os.path.exists') def test3_is_installed(self, mock_isfile): mock_isfile.side_effect = [True] game = Game("Game Name Test", install_dir="Test Install Dir") game.load_minigalaxy_info_json = MagicMock() game.load_minigalaxy_info_json.return_value = {"dlcs": {"Neverwinter Nights: Wyvern Crown of Cormyr": {"version": "82.8193.20.1"}}} game.legacy_get_dlc_status = MagicMock() game.legacy_get_dlc_status.return_value = "not-installed" exp = False obs = game.is_installed(dlc_title="Not Present DLC") self.assertEqual(exp, obs) @unittest.mock.patch('os.path.isfile') def test_get_info(self, mock_isfile): mock_isfile.side_effect = [True] json_content = '{"example_key": "example_value"}' with patch("builtins.open", mock_open(read_data=json_content)): game = Game("Game Name test") game_get_status = game.get_info("example_key") expected = "example_value" observed = game_get_status self.assertEqual(expected, observed) @unittest.mock.patch('os.path.isfile') def test_get_dlc_info(self, mock_isfile): mock_isfile.side_effect = [True, False] json_content = '{"dlcs": {"example_dlc" : {"example_key": "example_value"}}}' with patch("builtins.open", mock_open(read_data=json_content)): game = Game("Game Name test") game_get_status = game.get_dlc_info("example_key", "example_dlc") expected = "example_value" observed = game_get_status self.assertEqual(expected, observed) def test_set_install_dir(self): install_directory = "/home/user/GOG Games" install_game_name = "Neverwinter Nights" m_config.Config.get.return_value = install_directory game = Game(install_game_name) game.set_install_dir() exp = os.path.join(install_directory, install_game_name) obs = game.install_dir self.assertEqual(exp, obs) @unittest.mock.patch('os.path.isfile') def test1_get_info_legacy(self, mock_isfile): mock_isfile.side_effect = [False, True] json_content = '{"example_key": "example_value"}' with patch("builtins.open", mock_open(read_data=json_content)): game = Game("Game Name test") game.set_info = MagicMock() game_get_status = game.get_info("example_key") expected = "example_value" observed = game_get_status self.assertEqual(expected, observed) @unittest.mock.patch('os.path.isfile') def test2_get_info_legacy(self, mock_isfile): mock_isfile.side_effect = [True, True] json_content = '{"example_key": "example_value"}' with patch("builtins.open", mock_open(read_data=json_content)): game = Game("Game Name test") game.set_info = MagicMock() game.load_minigalaxy_info_json = MagicMock() game.load_minigalaxy_info_json.return_value = {} game_get_status = game.get_info("example_key") expected = "example_value" observed = game_get_status self.assertEqual(expected, observed) @unittest.mock.patch('os.path.isfile') def test3_get_info_legacy(self, mock_isfile): mock_isfile.side_effect = [True, True] json_content = '{"example_key": "example_value_legacy"}' with patch("builtins.open", mock_open(read_data=json_content)): game = Game("Game Name test") game.load_minigalaxy_info_json = MagicMock() game.load_minigalaxy_info_json.return_value = {"example_key": "example_value"} game_get_status = game.get_info("example_key") expected = "example_value" observed = game_get_status self.assertEqual(expected, observed) @unittest.mock.patch('os.path.isfile') def test1_get_dlc_info_legacy(self, mock_isfile): mock_isfile.side_effect = [False, True] json_content = '{"dlcs": {"example_dlc" : {"example_key": "example_value"}}}' with patch("builtins.open", mock_open(read_data=json_content)): game = Game("Game Name test") game.set_dlc_info = MagicMock() game_get_status = game.get_dlc_info("example_key", "example_dlc") expected = "example_value" observed = game_get_status self.assertEqual(expected, observed) @unittest.mock.patch('os.path.isfile') def test2_get_dlc_info_legacy(self, mock_isfile): mock_isfile.side_effect = [True, True] json_content = '{"dlcs": {"example_dlc" : {"example_key": "example_value"}}}' with patch("builtins.open", mock_open(read_data=json_content)): game = Game("Game Name test") game.set_dlc_info = MagicMock() game.load_minigalaxy_info_json = MagicMock() game.load_minigalaxy_info_json.return_value = {} game_get_status = game.get_dlc_info("example_key", "example_dlc") expected = "example_value" observed = game_get_status self.assertEqual(expected, observed) @unittest.mock.patch('os.path.isfile') def test3_get_dlc_info_legacy(self, mock_isfile): mock_isfile.side_effect = [True, True] json_content = '{"dlcs": {"example_dlc" : {"example_key": "example_value_legacy"}}}' with patch("builtins.open", mock_open(read_data=json_content)): game = Game("Game Name test") game.load_minigalaxy_info_json = MagicMock() game.load_minigalaxy_info_json.return_value = {"dlcs": {"example_dlc": {"example_key": "example_value"}}} game_get_status = game.get_dlc_info("example_key", "example_dlc") expected = "example_value" observed = game_get_status self.assertEqual(expected, observed) def test1_get_status_file_path(self): game = Game(name="Europa Universalis 2") expected = "/home/user/.config/minigalaxy/games/Europa Universalis 2.json" observed = game.get_status_file_path() self.assertEqual(expected, observed) def test2_get_status_file_path(self): game = Game(name="Europa Universalis 2", install_dir="/home/user/GoG Games//Europa Universalis II") expected = "/home/user/.config/minigalaxy/games/Europa Universalis II.json" observed = game.get_status_file_path() self.assertEqual(expected, observed) del sys.modules["minigalaxy.config"] del sys.modules["minigalaxy.paths"] minigalaxy-1.1.0/tests/test_installer.py000066400000000000000000000507201414231301100204150ustar00rootroot00000000000000import copy from unittest import TestCase, mock from unittest.mock import patch, mock_open, MagicMock from minigalaxy.game import Game from minigalaxy import installer from minigalaxy.translation import _ class Test(TestCase): @mock.patch('os.path.exists') @mock.patch('hashlib.md5') @mock.patch('os.listdir') def test1_verify_installer_integrity(self, mock_listdir, mock_hash, mock_is_file): md5_sum = "5cc68247b61ba31e37e842fd04409d98" installer_name = "beneath_a_steel_sky_en_gog_2_20150.sh" mock_is_file.return_value = True mock_hash().hexdigest.return_value = md5_sum mock_listdir.return_value = [installer_name] game = Game("Beneath A Steel Sky", install_dir="/home/makson/GOG Games/Beneath a Steel Sky", md5sum={installer_name: md5_sum}) installer_path = "/home/user/.cache/minigalaxy/download/" \ "Beneath a Steel Sky/{}".format(installer_name) exp = "" with patch("builtins.open", mock_open(read_data=b"")): obs = installer.verify_installer_integrity(game, installer_path) self.assertEqual(exp, obs) @mock.patch('os.path.exists') @mock.patch('hashlib.md5') @mock.patch('os.listdir') def test2_verify_installer_integrity(self, mock_listdir, mock_hash, mock_is_file): md5_sum = "5cc68247b61ba31e37e842fd04409d98" installer_name = "beneath_a_steel_sky_en_gog_2_20150.sh" corrupted_md5_sum = "99999947b61ba31e37e842fd04409d98" mock_is_file.return_value = True mock_hash().hexdigest.return_value = corrupted_md5_sum mock_listdir.return_value = [installer_name] game = Game("Beneath A Steel Sky", install_dir="/home/makson/GOG Games/Beneath a Steel Sky", md5sum={installer_name: md5_sum}) installer_path = "/home/user/.cache/minigalaxy/download/" \ "Beneath a Steel Sky/{}".format(installer_name) exp = _("{} was corrupted. Please download it again.").format(installer_name) with patch("builtins.open", mock_open(read_data=b"aaaa")): obs = installer.verify_installer_integrity(game, installer_path) self.assertEqual(exp, obs) @mock.patch('os.path.exists') @mock.patch('os.listdir') @mock.patch('subprocess.Popen') def test1_extract_installer(self, mock_subprocess, mock_listdir, mock_is_file): mock_is_file.return_value = True mock_subprocess().returncode = 0 mock_subprocess().communicate.return_value = [b"stdout", b"stderr"] mock_listdir.return_value = ["object1", "object2"] game = Game("Beneath A Steel Sky", install_dir="/home/makson/GOG Games/Beneath a Steel Sky") installer_path = "/home/makson/.cache/minigalaxy/download/Beneath a Steel Sky/beneath_a_steel_sky_en_gog_2_20150.sh" temp_dir = "/home/makson/.cache/minigalaxy/extract/1207658695" exp = "" obs = installer.extract_installer(game, installer_path, temp_dir) self.assertEqual(exp, obs) @mock.patch('os.path.exists') @mock.patch('os.listdir') @mock.patch('subprocess.Popen') def test2_extract_installer(self, mock_subprocess, mock_listdir, mock_is_file): mock_is_file.return_value = True mock_subprocess().returncode = 2 mock_subprocess().communicate.return_value = [b"stdout", b"stderr"] mock_listdir.return_value = ["object1", "object2"] game = Game("Beneath A Steel Sky", install_dir="/home/makson/GOG Games/Beneath a Steel Sky") installer_path = "/home/makson/.cache/minigalaxy/download/Beneath a Steel Sky/beneath_a_steel_sky_en_gog_2_20150.sh" temp_dir = "/home/makson/.cache/minigalaxy/extract/1207658695" exp = "The installation of /home/makson/.cache/minigalaxy/download/Beneath a Steel Sky/beneath_a_steel_sky_en_gog_2_20150.sh failed. Please try again." obs = installer.extract_installer(game, installer_path, temp_dir) self.assertEqual(exp, obs) @mock.patch('subprocess.Popen') @mock.patch('shutil.which') def test3_extract_installer(self, mock_which, mock_subprocess): mock_which.return_value = True mock_subprocess().returncode = 0 mock_subprocess().communicate.return_value = [b"stdout", b"stderr"] game = Game("Absolute Drift", install_dir="/home/makson/GOG Games/Absolute Drift", platform="windows") installer_path = "/home/makson/.cache/minigalaxy/download/Absolute Drift/setup_absolute_drift_1.0f_(64bit)_(47863).exe" temp_dir = "/home/makson/.cache/minigalaxy/extract/1136126792" exp = "" obs = installer.extract_installer(game, installer_path, temp_dir) self.assertEqual(exp, obs) @mock.patch('os.path.exists') @mock.patch('os.listdir') @mock.patch('subprocess.Popen') def test_extract_linux(self, mock_subprocess, mock_listdir, mock_is_file): mock_is_file.return_value = True mock_subprocess().returncode = 1 mock_subprocess().communicate.return_value = [b"stdout", b"(attempting to process anyway)"] mock_listdir.return_value = ["object1", "object2"] installer_path = "/home/makson/.cache/minigalaxy/download/Beneath a Steel Sky/beneath_a_steel_sky_en_gog_2_20150.sh" temp_dir = "/home/makson/.cache/minigalaxy/extract/1207658695" exp = "" obs = installer.extract_linux(installer_path, temp_dir) self.assertEqual(exp, obs) @mock.patch('subprocess.Popen') @mock.patch('shutil.which') def test_extract_windows(self, mock_which, mock_subprocess): mock_which.return_value = True mock_subprocess().returncode = 0 mock_subprocess().communicate.return_value = [b"stdout", b"stderr"] game = Game("Absolute Drift", install_dir="/home/makson/GOG Games/Absolute Drift", platform="windows") installer_path = "/home/makson/.cache/minigalaxy/download/Absolute Drift/setup_absolute_drift_1.0f_(64bit)_(47863).exe" temp_dir = "/home/makson/.cache/minigalaxy/extract/1136126792" exp = "" obs = installer.extract_windows(game, installer_path, temp_dir) self.assertEqual(exp, obs) @mock.patch('subprocess.Popen') @mock.patch('shutil.which') def test1_extract_by_innoextract(self, mock_which, mock_subprocess): mock_which.return_value = True mock_subprocess().returncode = 0 mock_subprocess().communicate.return_value = [b"stdout", b"stderr"] installer_path = "/home/makson/.cache/minigalaxy/download/Absolute Drift/setup_absolute_drift_1.0f_(64bit)_(47863).exe" temp_dir = "/home/makson/.cache/minigalaxy/extract/1136126792" exp = "" obs = installer.extract_by_innoextract(installer_path, temp_dir) self.assertEqual(exp, obs) @mock.patch('shutil.which') def test2_extract_by_innoextract(self, mock_which): mock_which.return_value = False installer_path = "/home/makson/.cache/minigalaxy/download/Absolute Drift/setup_absolute_drift_1.0f_(64bit)_(47863).exe" temp_dir = "/home/makson/.cache/minigalaxy/extract/1136126792" exp = "Innoextract not installed." obs = installer.extract_by_innoextract(installer_path, temp_dir) self.assertEqual(exp, obs) @mock.patch('subprocess.Popen') @mock.patch('shutil.which') def test3_extract_by_innoextract(self, mock_which, mock_subprocess): mock_which.return_value = True mock_subprocess().returncode = 1 mock_subprocess().communicate.return_value = [b"stdout", b"stderr"] installer_path = "/home/makson/.cache/minigalaxy/download/Absolute Drift/setup_absolute_drift_1.0f_(64bit)_(47863).exe" temp_dir = "/home/makson/.cache/minigalaxy/extract/1136126792" exp = "Innoextract extraction failed." obs = installer.extract_by_innoextract(installer_path, temp_dir) self.assertEqual(exp, obs) @mock.patch('subprocess.Popen') @mock.patch("os.path.exists") def test1_extract_by_wine(self, mock_path_exists, mock_subprocess): mock_path_exists.return_value = True mock_subprocess().returncode = 0 mock_subprocess().communicate.return_value = [b"stdout", b"stderr"] game = Game("Absolute Drift", install_dir="/home/makson/GOG Games/Absolute Drift", platform="windows") installer_path = "/home/makson/.cache/minigalaxy/download/Absolute Drift/setup_absolute_drift_1.0f_(64bit)_(47863).exe" temp_dir = "/home/makson/.cache/minigalaxy/extract/1136126792" exp = "" obs = installer.extract_by_wine(game, installer_path, temp_dir) self.assertEqual(exp, obs) @mock.patch('subprocess.Popen') @mock.patch("os.path.exists") def test2_extract_by_wine(self, mock_path_exists, mock_subprocess): mock_path_exists.return_value = True mock_subprocess().returncode = 1 mock_subprocess().communicate.return_value = [b"stdout", b"stderr"] game = Game("Absolute Drift", install_dir="/home/makson/GOG Games/Absolute Drift", platform="windows") installer_path = "/home/makson/.cache/minigalaxy/download/Absolute Drift/setup_absolute_drift_1.0f_(64bit)_(47863).exe" temp_dir = "/home/makson/.cache/minigalaxy/extract/1136126792" exp = "Wine extraction failed." obs = installer.extract_by_wine(game, installer_path, temp_dir) self.assertEqual(exp, obs) @mock.patch('subprocess.Popen') @mock.patch("os.path.isfile") def test1_postinstaller(self, mock_path_isfile, mock_subprocess): mock_path_isfile.return_value = False mock_subprocess().returncode = 1 mock_subprocess().communicate.return_value = [b"stdout", b"stderr"] game = Game("Absolute Drift", install_dir="/home/makson/GOG Games/Absolute Drift") exp = "" obs = installer.postinstaller(game) self.assertEqual(exp, obs) @mock.patch('subprocess.Popen') @mock.patch("os.path.isfile") @mock.patch("os.chmod") def test2_postinstaller(self, mock_chmod, mock_path_isfile, mock_subprocess): mock_path_isfile.return_value = True mock_subprocess().returncode = 0 mock_subprocess().communicate.return_value = [b"stdout", b"stderr"] game = Game("Absolute Drift", install_dir="/home/makson/GOG Games/Absolute Drift") exp = "" obs = installer.postinstaller(game) self.assertEqual(exp, obs) @mock.patch('subprocess.Popen') @mock.patch("os.path.isfile") @mock.patch("os.chmod") def test3_postinstaller(self, mock_chmod, mock_path_isfile, mock_subprocess): mock_path_isfile.return_value = True mock_subprocess().returncode = 1 mock_subprocess().communicate.return_value = [b"stdout", b"stderr"] game = Game("Absolute Drift", install_dir="/home/makson/GOG Games/Absolute Drift") exp = "Postinstallation script failed: /home/makson/GOG Games/Absolute Drift/support/postinst.sh" obs = installer.postinstaller(game) self.assertEqual(exp, obs) @mock.patch('os.statvfs') def test_get_availablediskspace(self, mock_os_statvfs): frsize = 4096 bavail = 29699296 mock_os_statvfs().f_frsize = frsize mock_os_statvfs().f_bavail = bavail exp = frsize * bavail obs = installer.get_available_disk_space("/") self.assertEqual(exp, obs) @mock.patch('os.statvfs') def test1_check_diskspace(self, mock_os_statvfs): frsize = 4096 bavail = 29699296 mock_os_statvfs().f_frsize = frsize mock_os_statvfs().f_bavail = bavail exp = True obs = installer.check_diskspace(524288000, "/") self.assertEqual(exp, obs) @mock.patch('os.statvfs') def test2_check_diskspace(self, mock_os_statvfs): frsize = 4096 bavail = 29699 mock_os_statvfs().f_frsize = frsize mock_os_statvfs().f_bavail = bavail exp = False obs = installer.check_diskspace(524288000, "/") self.assertEqual(exp, obs) @mock.patch('os.statvfs') def test1_verify_disk_space(self, mock_os_statvfs): frsize = 4096 bavail = 29699 mock_os_statvfs().f_frsize = frsize mock_os_statvfs().f_bavail = bavail backup_installer = copy.deepcopy(installer.get_game_size_from_unzip) installer.get_game_size_from_unzip = MagicMock() installer.get_game_size_from_unzip.return_value = 524288000 game = Game("Beneath A Steel Sky", install_dir="/home/makson/GOG Games/Beneath a Steel Sky", platform="linux") installer_file = "/beneath_a_steel_sky_en_gog_2_20150.sh" exp = "Not enough space to extract game. Required: 524288000 Available: 121647104" obs = installer.verify_disk_space(game, installer_file) installer.get_game_size_from_unzip = backup_installer self.assertEqual(exp, obs) @mock.patch('subprocess.Popen') def test_get_game_size_from_unzip(self, mock_subprocess): stdout = b""" 550557 Defl:N 492111 11% 2018-04-19 15:01 48d4ab3f meta/gtk-2.0/pixmaps/background.png 0 Stored 0 0% 2018-04-19 15:01 00000000 scripts/ 212070 Defl:N 63210 70% 2017-10-25 11:07 a05c1728 scripts/localization.lua 21572 Defl:N 5592 74% 2017-06-27 13:02 e47c0968 scripts/mojosetup_init.lua 9171 Defl:N 3374 63% 2017-10-25 11:07 14ac8da7 scripts/app_localization.lua 4411 Defl:N 1247 72% 2018-04-19 15:01 2405a519 scripts/config.lua 76365 Defl:N 17317 77% 2017-10-25 11:07 27d8bdb2 scripts/mojosetup_mainline.lua -------- ------- --- ------- 159236636 104883200 34% 189 files """ mock_subprocess().communicate.return_value = [stdout, b"stderr"] installer_path = "/home/i/.cache/minigalaxy/download/Beneath a Steel Sky/beneath_a_steel_sky_en_gog_2_20150.sh" exp = 159236636 obs = installer.get_game_size_from_unzip(installer_path) self.assertEqual(exp, obs) @mock.patch('shutil.which') @mock.patch('os.listdir') def test_get_exec_line(self, mock_list_dir, mock_which): mock_which.return_value = True game1 = Game("Beneath A Steel Sky", install_dir="/home/test/GOG Games/Beneath a Steel Sky", platform="linux") mock_list_dir.return_value = ["data", "docs", "scummvm", "support", "beneath.ini", "gameinfo", "start.sh"] result1 = installer.get_exec_line(game1) self.assertEqual(result1, "scummvm -c beneath.ini") game2 = Game("Blocks That Matter", install_dir="/home/test/GOG Games/Blocks That Matter", platform="linux") mock_list_dir.return_value = ["data", "docs", "support", "gameinfo", "start.sh"] result2 = installer.get_exec_line(game2) self.assertEqual(result2, "./start.sh") @mock.patch('os.path.getsize') @mock.patch('os.listdir') @mock.patch('os.path.isdir') def test_compare_directory_true(self, mock_path_isdir, mock_list_dir, mock_os_path_getsize): mock_path_isdir.return_value = True mock_list_dir.return_value = ["beneath_a_steel_sky_en_gog_2_20150.sh", "beneath_a_steel_sky_en_gog_2_20150.part1"] mock_os_path_getsize.return_value = 100 obs = installer.compare_directories("/home/test/.cache/minigalaxy/installer/test", "/home/test/GOG Games/installer/test") self.assertEqual(obs, True) @mock.patch('os.path.getsize') @mock.patch('os.listdir') @mock.patch('os.path.isdir') def test_compare_directory_false(self, mock_path_isdir, mock_list_dir, mock_os_path_getsize): mock_path_isdir.return_value = True mock_list_dir.side_effect = [ ["beneath_a_steel_sky_en_gog_2_20150.sh", "beneath_a_steel_sky_en_gog_2_20150.part1"], ["beneath_a_steel_sky_en_gog_2_20150.sh"], ] obs = installer.compare_directories("/home/test/.cache/minigalaxy/installer/test", "/home/test/GOG Games/installer/test") self.assertEqual(obs, False) mock_list_dir.side_effect = [ ["beneath_a_steel_sky_en_gog_2_20150.sh", "beneath_a_steel_sky_en_gog_2_20150.part1"], ["beneath_a_steel_sky_en_gog_2_20150.sh", "beneath_a_steel_sky_en_gog_2_20150.part1"], ] mock_os_path_getsize.side_effect = [100, 200, 300, 400] obs = installer.compare_directories("/home/test/.cache/minigalaxy/installer/test", "/home/test/GOG Games/installer/test") self.assertEqual(obs, False) def test_remove_installer_no_installer(self): """ No installer present """ game1 = Game("Beneath A Steel Sky", install_dir="/home/test/GOG Games/Beneath a Steel Sky", platform="linux") installer_path = "/home/i/.cache/minigalaxy/download/Beneath a Steel Sky/beneath_a_steel_sky_en_gog_2_20150.sh" obs = installer.remove_installer(game1, installer_path) exp = "No installer directory is present: /home/i/.cache/minigalaxy/download/Beneath a Steel Sky" self.assertEqual(obs, exp) @mock.patch('shutil.rmtree') @mock.patch('minigalaxy.config.Config.get') @mock.patch('minigalaxy.installer.compare_directories') @mock.patch('os.path.isdir') def test_remove_installer_no_keep(self, mock_os_path_isdir, mock_compare_directories, mock_config, mock_shutil_rmtree): """ Disabled keep_installer """ mock_os_path_isdir.return_value = True mock_compare_directories.return_value = False mock_config.return_value = False game1 = Game("Beneath A Steel Sky", install_dir="/home/test/GOG Games/Beneath a Steel Sky", platform="linux") installer_path = "/home/i/.cache/minigalaxy/download/Beneath a Steel Sky/beneath_a_steel_sky_en_gog_2_20150.sh" obs = installer.remove_installer(game1, installer_path) assert mock_shutil_rmtree.called self.assertEqual(obs, "") @mock.patch('shutil.rmtree') @mock.patch('minigalaxy.config.Config.get') @mock.patch('minigalaxy.installer.compare_directories') @mock.patch('os.path.isdir') def test_remove_installer_same_content(self, mock_os_path_isdir, mock_compare_directories, mock_config, mock_shutil_rmtree): """ Same content of installer and keep dir """ mock_os_path_isdir.return_value = True mock_compare_directories.return_value = True mock_config.side_effect = [True, "/home/i/GOG Games/installer"] game1 = Game("Beneath A Steel Sky", install_dir="/home/test/GOG Games/Beneath a Steel Sky", platform="linux") installer_path = "/home/i/.cache/minigalaxy/download/Beneath a Steel Sky/beneath_a_steel_sky_en_gog_2_20150.sh" obs = installer.remove_installer(game1, installer_path) assert not mock_shutil_rmtree.called self.assertEqual(obs, "") @mock.patch('shutil.move') @mock.patch('shutil.rmtree') @mock.patch('minigalaxy.config.Config.get') @mock.patch('minigalaxy.installer.compare_directories') @mock.patch('os.path.isdir') def test_remove_installer_keep(self, mock_os_path_isdir, mock_compare_directories, mock_config, mock_shutil_rmtree, mock_shutil_move): """ Keep installer dir """ mock_os_path_isdir.return_value = True mock_compare_directories.return_value = False mock_config.side_effect = [True, "/home/i/GOG Games/installer"] game1 = Game("Beneath A Steel Sky", install_dir="/home/test/GOG Games/Beneath a Steel Sky", platform="linux") installer_path = "/home/i/.cache/minigalaxy/download/Beneath a Steel Sky/beneath_a_steel_sky_en_gog_2_20150.sh" obs = installer.remove_installer(game1, installer_path) assert mock_shutil_rmtree.called assert mock_shutil_move.called self.assertEqual(obs, "") @mock.patch('shutil.move') @mock.patch('shutil.rmtree') @mock.patch('minigalaxy.config.Config.get') @mock.patch('minigalaxy.installer.compare_directories') @mock.patch('os.path.isdir') def test_remove_installer_from_keep(self, mock_os_path_isdir, mock_compare_directories, mock_config, mock_shutil_rmtree, mock_shutil_move): """ Called from keep dir """ mock_os_path_isdir.return_value = True mock_compare_directories.return_value = False mock_config.side_effect = [True, "/home/i/GOG Games"] game1 = Game("Beneath A Steel Sky", install_dir="/home/test/GOG Games/Beneath A Steel Sky", platform="linux") installer_path = "/home/i/GOG Games/installer/Beneath A Steel Sky/beneath_a_steel_sky_en_gog_2_20150.sh" obs = installer.remove_installer(game1, installer_path) assert not mock_shutil_rmtree.called assert not mock_shutil_move.called self.assertEqual(obs, "") minigalaxy-1.1.0/tests/test_launcher.py000066400000000000000000000240641414231301100202230ustar00rootroot00000000000000import subprocess from unittest import TestCase, mock from unittest.mock import MagicMock, mock_open from minigalaxy import launcher from minigalaxy.game import Game class Test(TestCase): def test1_determine_launcher_type(self): files = ['thumbnail.jpg', 'docs', 'support', 'game', 'start.sh', 'minigalaxy-dlc.json', 'gameinfo'] exp = "start_script" obs = launcher.determine_launcher_type(files) self.assertEqual(exp, obs) @mock.patch('shutil.which') def test2_determine_launcher_type(self, mock_shutil_which): mock_shutil_which.return_value = True files = ['thumbnail.jpg', 'data', 'docs', 'support', 'beneath.ini', 'scummvm', 'start.sh', 'gameinfo'] exp = "scummvm" obs = launcher.determine_launcher_type(files) self.assertEqual(exp, obs) def test3_determine_launcher_type(self): files = ['thumbnail.jpg', 'docs', 'support', 'unins000.exe', 'minigalaxy-dlc.json', 'gameinfo'] exp = "windows" obs = launcher.determine_launcher_type(files) self.assertEqual(exp, obs) @mock.patch('shutil.which') def test4_determine_launcher_type(self, mock_shutil_which): mock_shutil_which.return_value = True files = ['thumbnail.jpg', 'docs', 'support', 'dosbox', 'minigalaxy-dlc.json', 'gameinfo'] exp = "dosbox" obs = launcher.determine_launcher_type(files) self.assertEqual(exp, obs) def test5_determine_launcher_type(self): files = ['thumbnail.jpg', 'docs', 'support', 'game', 'minigalaxy-dlc.json', 'gameinfo'] exp = "final_resort" obs = launcher.determine_launcher_type(files) self.assertEqual(exp, obs) @mock.patch('glob.glob') def test1_get_windows_exe_cmd(self, mock_glob): mock_glob.return_value = ["/test/install/dir/start.exe", "/test/install/dir/unins000.exe"] files = ['thumbnail.jpg', 'docs', 'support', 'game', 'minigalaxy-dlc.json', 'start.exe', 'unins000.exe'] game = Game("Test Game", install_dir="/test/install/dir") exp = ["wine", "start.exe"] obs = launcher.get_windows_exe_cmd(game, files) self.assertEqual(exp, obs) @mock.patch('builtins.open', new_callable=mock_open, read_data="") @mock.patch('os.chdir') def test2_get_windows_exe_cmd(self, mock_os_chdir, mo): goggame_1414471894_info_content = """{ "buildId": "53350324452482937", "clientId": "53185732904249211", "gameId": "1414471894", "language": "Russian", "languages": [ "ru-RU" ], "name": "Metro Exodus - Sam's Story", "osBitness": [ "64" ], "playTasks": [], "rootGameId": "1407287452", "version": 1 }""" goggame_1407287452_info_content = """{ "buildId": "53350324452482937", "clientId": "53185732904249211", "gameId": "1407287452", "language": "Russian", "languages": [ "ru-RU" ], "name": "Metro Exodus", "osBitness": [ "64" ], "playTasks": [ { "category": "game", "isPrimary": true, "languages": [ "ru-RU" ], "name": "Metro Exodus", "osBitness": [ "64" ], "path": "MetroExodus.exe", "type": "FileTask" } ], "rootGameId": "1407287452", "version": 1 }""" handlers = (mock_open(read_data=goggame_1414471894_info_content).return_value, mock_open(read_data=goggame_1407287452_info_content).return_value) mo.side_effect = handlers files = ['thumbnail.jpg', 'docs', 'support', 'game', 'minigalaxy-dlc.json', 'MetroExodus.exe', 'unins000.exe', 'goggame-1407287452.info', 'goggame-1414471894.info'] game = Game("Test Game", install_dir="/test/install/dir") exp = ["wine", "MetroExodus.exe"] obs = launcher.get_windows_exe_cmd(game, files) self.assertEqual(exp, obs) def test_get_dosbox_exe_cmd(self): files = ['thumbnail.jpg', 'docs', 'support', 'dosbox_bbb_single.conf', 'dosbox_aaa.conf', 'dosbox'] game = Game("Test Game", install_dir="/test/install/dir") exp = ["dosbox", "-conf", "dosbox_aaa.conf", "-conf", "dosbox_bbb_single.conf", "-no-console", "-c", "exit"] obs = launcher.get_dosbox_exe_cmd(game, files) self.assertEqual(exp, obs) def test_get_scummvm_exe_cmd(self): files = ['thumbnail.jpg', 'data', 'docs', 'support', 'beneath.ini', 'scummvm', 'start.sh', 'gameinfo'] game = Game("Test Game", install_dir="/test/install/dir") exp = ["scummvm", "-c", "beneath.ini"] obs = launcher.get_scummvm_exe_cmd(game, files) self.assertEqual(exp, obs) def test_get_start_script_exe_cmd(self): exp = ["./start.sh"] obs = launcher.get_start_script_exe_cmd() self.assertEqual(exp, obs) @mock.patch('os.getcwd') @mock.patch('os.chdir') @mock.patch('subprocess.Popen') @mock.patch('minigalaxy.launcher.get_execute_command') def test1_run_game_subprocess(self, launcher_mock, mock_popen, mock_os_chdir, mock_os_getcwd): mock_process = "Mock Process" mock_popen.return_value = mock_process game = Game("Test Game", install_dir="/test/install/dir") exp = ("", mock_process) obs = launcher.run_game_subprocess(game) self.assertEqual(exp, obs) @mock.patch('os.getcwd') @mock.patch('os.chdir') @mock.patch('subprocess.Popen') @mock.patch('minigalaxy.launcher.get_execute_command') def test2_run_game_subprocess(self, launcher_mock, mock_popen, mock_os_chdir, mock_os_getcwd): mock_popen.side_effect = FileNotFoundError() game = Game("Test Game", install_dir="/test/install/dir") exp = ('No executable was found in /test/install/dir', None) obs = launcher.run_game_subprocess(game) self.assertEqual(exp, obs) @mock.patch('minigalaxy.launcher.check_if_game_start_process_spawned_final_process') def test1_check_if_game_started_correctly(self, mock_check_game): mock_process = MagicMock() mock_process.wait.side_effect = subprocess.TimeoutExpired("cmd", 1) game = Game("Test Game", install_dir="/test/install/dir") exp = "" obs = launcher.check_if_game_started_correctly(mock_process, game) self.assertEqual(exp, obs) @mock.patch('minigalaxy.launcher.check_if_game_start_process_spawned_final_process') def test2_check_if_game_started_correctly(self, mock_check_game): mock_process = MagicMock() mock_process.communicate.return_value = (b"Output message", b"Error message") game = Game("Test Game", install_dir="/test/install/dir") exp = "Error message" obs = launcher.check_if_game_started_correctly(mock_process, game) self.assertEqual(exp, obs) @mock.patch('os.getpid') @mock.patch('subprocess.check_output') def test1_check_if_game_start_process_spawned_final_process(self, mock_check_output, mock_getpid): mock_check_output.return_value = b"""UID PID PPID C STIME TTY TIME CMD root 1 0 0 lis24 ? 00:00:02 /sbin/init splash root 2 0 0 lis24 ? 00:00:00 [kthreadd] root 3 2 0 lis24 ? 00:00:00 [rcu_gp] root 4 2 0 lis24 ? 00:00:00 [rcu_par_gp] root 6 2 0 lis24 ? 00:00:00 [kworker/0:0H-kblockd] """ mock_getpid.return_value = 1000 err_msg = "Error Message" game = Game("Test Game", install_dir="/test/install/dir") exp = err_msg obs = launcher.check_if_game_start_process_spawned_final_process(err_msg, game) self.assertEqual(exp, obs) @mock.patch('os.getpid') @mock.patch('subprocess.check_output') def test2_check_if_game_start_process_spawned_final_process(self, mock_check_output, mock_getpid): mock_check_output.return_value = b"""UID PID PPID C STIME TTY TIME CMD root 1 0 0 lis24 ? 00:00:02 /sbin/init splash root 2 0 0 lis24 ? 00:00:00 [kthreadd] root 3 2 0 lis24 ? 00:00:00 [rcu_gp] root 4 2 0 lis24 ? 00:00:00 [rcu_par_gp] root 6 2 0 lis24 ? 00:00:00 [kworker/0:0H-kblockd] makson 1006 2 0 lis24 ? 00:00:00 /bin/sh /home/makson/.paradoxlauncher/launcher-v2.2020.15/Paradox Launcher --pdxlGameDir /home/makson/GOG Games/Stellaris/game --gameDir /home/makson/GOG Games/Stellaris/game """ mock_getpid.return_value = 1000 err_msg = "Error Message" game = Game("Stellaris", install_dir="/home/makson/GOG Games") exp = "" obs = launcher.check_if_game_start_process_spawned_final_process(err_msg, game) self.assertEqual(exp, obs) @mock.patch('os.getpid') @mock.patch('subprocess.check_output') def test3_check_if_game_start_process_spawned_final_process(self, mock_check_output, mock_getpid): mock_check_output.return_value = b"""UID PID PPID C STIME TTY TIME CMD root 12486 2 0 17:47 ? 00:00:00 [kworker/u17:3-kcryptd] root 12543 2 0 17:53 ? 00:00:00 [kworker/u17:1-kcryptd] root 12617 2 0 18:02 ? 00:00:00 [kworker/5:1-ata_sff] root 12652 2 0 18:07 ? 00:00:00 [kworker/0:0-events] root 12682 2 0 18:08 ? 00:00:00 [kworker/5:2-ata_sff] root 12699 2 0 18:08 ? 00:00:00 [kworker/u17:0-kcryptd] makson 12783 6690 1 18:09 pts/4 00:00:01 /usr/bin/python3 build/scripts-3.7/minigalaxy makson 12866 1378 0 18:09 pts/4 00:00:00 /bin/sh /home/makson/.paradoxlauncher/launcher-v2.2021.1/Paradox Launcher --pdxlGameDir /home/makson/GOG Games/Imperator Rome/game/launcher --gameDir /home/makson/GOG Games/Imperator Rome/game/launcher """ mock_getpid.return_value = 1000 err_msg = "Error Message" game = Game("Imperator: Rome", install_dir="/home/makson/GOG Games") exp = "" obs = launcher.check_if_game_start_process_spawned_final_process(err_msg, game) self.assertEqual(exp, obs) minigalaxy-1.1.0/tests/test_ui_library.py000066400000000000000000000151221414231301100205560ustar00rootroot00000000000000import sys from unittest import TestCase from unittest.mock import MagicMock m_gtk = MagicMock() m_gi = MagicMock() m_window = MagicMock() m_preferences = MagicMock() m_gametile = MagicMock() class UnitTestGtkTemplate: def __init__(self): self.Child = m_gtk def from_file(self, lib_file): def passthrough(func): def passthrough2(parent, api): return func(parent, api) return passthrough2 return passthrough class UnitTestGiRepository: class Gtk: Template = UnitTestGtkTemplate() Widget = m_gtk class Viewport: pass class Gdk: pass class GdkPixbuf: pass class Gio: pass class GLib: pass u_gi_repository = UnitTestGiRepository() sys.modules['gi.repository'] = u_gi_repository sys.modules['gi'] = m_gi sys.modules['minigalaxy.ui.window'] = m_window sys.modules['minigalaxy.ui.preferences'] = m_preferences sys.modules['minigalaxy.ui.gametile'] = m_gametile from minigalaxy.game import Game # noqa: E402 from minigalaxy.ui.library import Library # noqa: E402 SELF_GAMES = {"Neverwinter Nights: Enhanced Edition": "1097893768", "Beneath A Steel Sky": "1207658695", "Stellaris (English)": "1508702879"} API_GAMES = {"Neverwinter Nights: Enhanced Edition": "1097893768", "Beneath a Steel Sky": "1207658695", "Dragonsphere": "1207658927", "Warsow": "1207659121", "Outlast": "1207660064", "Xenonauts": "1207664803", "Wasteland 2": "1207665783", "Baldur's Gate: Enhanced Edition": "1207666353", "Baldur's Gate II: Enhanced Edition": "1207666373", "Toonstruck": "1207666633", "Icewind Dale: Enhanced Edition": "1207666683", "Pillars of Eternity": "1207666813", "Grim Fandango Remastered": "1207667183", "Knights of Pen and Paper +1 Edition": "1320675280", "Sunless Sea": "1421064427", "Dungeons 2": "1436885138", "Wasteland 2 Director's Cut": "1444386007", "Stellaris": "1508702879", "Butcher": "1689871374", "Reigns: Game of Thrones": "2060365190"} class TestLibrary(TestCase): def test1_add_games_from_api(self): self_games = [] for game in SELF_GAMES: self_games.append(Game(name=game, game_id=int(SELF_GAMES[game]),)) api_games = [] for game in API_GAMES: api_games.append(Game(name=game, game_id=int(API_GAMES[game]),)) err_msg = "" api_mock = MagicMock() api_mock.get_library.return_value = api_games, err_msg test_library = Library(MagicMock(), api_mock) test_library.games = self_games test_library._Library__add_games_from_api() exp = len(API_GAMES) obs = len(test_library.games) self.assertEqual(exp, obs) def test2_add_games_from_api(self): self_games = [] for game in SELF_GAMES: self_games.append(Game(name=game, game_id=int(SELF_GAMES[game]),)) api_games = [] for game in API_GAMES: api_games.append(Game(name=game, game_id=int(API_GAMES[game]),)) err_msg = "" api_mock = MagicMock() api_mock.get_library.return_value = api_games, err_msg test_library = Library(MagicMock(), api_mock) test_library.games = self_games test_library._Library__add_games_from_api() exp = True obs = Game(name="Stellaris (English)", game_id=1508702879,) in test_library.games self.assertEqual(exp, obs) def test3_add_games_from_api(self): self_games = [] for game in SELF_GAMES: self_games.append(Game(name=game, game_id=int(SELF_GAMES[game]),)) self_games.append(Game(name="Game without ID", game_id=0)) api_games = [] for game in API_GAMES: api_games.append(Game(name=game, game_id=int(API_GAMES[game]),)) api_gmae_with_id = Game(name="Game without ID", game_id=1234567890) api_games.append(api_gmae_with_id) err_msg = "" api_mock = MagicMock() api_mock.get_library.return_value = api_games, err_msg test_library = Library(MagicMock(), api_mock) test_library.games = self_games test_library._Library__add_games_from_api() exp = True obs = api_gmae_with_id in test_library.games self.assertEqual(exp, obs) exp = len(api_games) obs = len(test_library.games) self.assertEqual(exp, obs) def test4_add_games_from_api(self): self_games = [] for game in SELF_GAMES: self_games.append(Game(name=game, game_id=int(SELF_GAMES[game]),)) api_games = [] url_nr = 1 for game in API_GAMES: api_games.append(Game(name=game, game_id=int(API_GAMES[game]), url="http://test_url{}".format(str(url_nr)))) url_nr += 1 err_msg = "" api_mock = MagicMock() api_mock.get_library.return_value = api_games, err_msg test_library = Library(MagicMock(), api_mock) test_library.games = self_games test_library._Library__add_games_from_api() exp = "http://test_url1" obs = test_library.games[0].url self.assertEqual(exp, obs) def test5_add_games_from_api(self): self_games = [] for game in SELF_GAMES: self_games.append(Game(name="{}_diff".format(game), game_id=int(SELF_GAMES[game]),)) api_games = [] for game in API_GAMES: api_games.append(Game(name=game, game_id=int(API_GAMES[game]))) err_msg = "" api_mock = MagicMock() api_mock.get_library.return_value = api_games, err_msg test_library = Library(MagicMock(), api_mock) test_library.games = self_games test_library._Library__add_games_from_api() exp = "Neverwinter Nights: Enhanced Edition" obs = test_library.games[0].name self.assertEqual(exp, obs) def test6_add_games_from_api(self): self_games = [Game(name="Torchlight 2", game_id=0, install_dir="/home/user/GoG Games/Torchlight II")] api_games = [Game(name="Torchlight II", game_id=1958228073)] err_msg = "" api_mock = MagicMock() api_mock.get_library.return_value = api_games, err_msg test_library = Library(MagicMock(), api_mock) test_library.games = self_games test_library._Library__add_games_from_api() exp = 1 obs = len(test_library.games) self.assertEqual(exp, obs) del sys.modules['gi'] del sys.modules['gi.repository'] del sys.modules['minigalaxy.ui.window'] del sys.modules['minigalaxy.ui.preferences'] del sys.modules['minigalaxy.ui.gametile'] minigalaxy-1.1.0/tests/test_ui_window.py000066400000000000000000000051471414231301100204270ustar00rootroot00000000000000import sys from unittest import TestCase from unittest.mock import MagicMock, patch from simplejson.errors import JSONDecodeError m_gtk = MagicMock() m_gi = MagicMock() m_library = MagicMock() m_preferences = MagicMock() m_login = MagicMock() m_about = MagicMock() class UnitTestGtkTemplate: def __init__(self): self.Child = m_gtk def from_file(self, lib_file): def passthrough(func): def passthrough2(): return func() return passthrough2 return passthrough Callback = MagicMock() class UnitTestGiRepository: class Gtk: Template = UnitTestGtkTemplate() Widget = MagicMock() Settings = MagicMock() ResponseType = MagicMock() class ApplicationWindow: def __init__(self, title): pass set_default_icon_list = MagicMock() show_all = MagicMock() Gdk = MagicMock() GdkPixbuf = MagicMock() Gio = MagicMock() GLib = MagicMock u_gi_repository = UnitTestGiRepository() sys.modules['gi.repository'] = u_gi_repository sys.modules['gi'] = m_gi sys.modules['minigalaxy.ui.library'] = m_library sys.modules['minigalaxy.ui.preferences'] = m_preferences sys.modules['minigalaxy.ui.login'] = m_login sys.modules['minigalaxy.ui.about'] = m_about sys.modules['minigalaxy.ui.gtk'] = u_gi_repository from minigalaxy.ui.window import Window # noqa: E402 class TestWindow(TestCase): def test1_init(self): with patch('minigalaxy.ui.window.Api.can_connect', return_value=False): test_window = Window() exp = True obs = test_window.offline self.assertEqual(exp, obs) def test2_init(self): with patch('minigalaxy.ui.window.Api.can_connect', return_value=True): with patch('minigalaxy.ui.window.Api.authenticate', return_value=True): test_window = Window() exp = False obs = test_window.offline self.assertEqual(exp, obs) self.assertEqual(test_window.api.authenticate.called, True) def test3_init(self): with patch('minigalaxy.ui.window.Api.authenticate', side_effect=JSONDecodeError(msg='mock', doc='mock', pos=0)): test_window = Window() exp = True obs = test_window.offline self.assertEqual(exp, obs) del sys.modules['gi'] del sys.modules['gi.repository'] del sys.modules['minigalaxy.ui.library'] del sys.modules['minigalaxy.ui.preferences'] del sys.modules['minigalaxy.ui.login'] del sys.modules['minigalaxy.ui.about'] del sys.modules['minigalaxy.ui.gtk']