pax_global_header00006660000000000000000000000064151426355410014520gustar00rootroot0000000000000052 comment=f7bd48ed2db5bbe3530deccf4c2e34f3b0f60c45 gottcode-kapow-350ecea/000077500000000000000000000000001514263554100151365ustar00rootroot00000000000000gottcode-kapow-350ecea/.gitignore000066400000000000000000000000351514263554100171240ustar00rootroot00000000000000Makefile build kapow *.qm *~ gottcode-kapow-350ecea/CMakeLists.txt000066400000000000000000000110631514263554100176770ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2021 Graeme Gott # # SPDX-License-Identifier: GPL-3.0-or-later cmake_minimum_required(VERSION 3.16) # Configure project project(kapow VERSION 1.7.0 LANGUAGES CXX) set(project_copyright "2008-2026 Graeme Gott") set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) find_package(Qt6 REQUIRED COMPONENTS Core Gui LinguistTools Network PrintSupport Widgets) include(GNUInstallDirs) add_compile_definitions( QT_NO_KEYWORDS $<$:QT_STRICT_ITERATORS> $<$:QT_NO_NARROWING_CONVERSIONS_IN_CONNECT> $<$:QT_DISABLE_DEPRECATED_BEFORE=0x061000> ) add_compile_options( $<$:-Wshadow> ) # Version number include(cmake/AddVersionCompileDefinition.cmake) add_version_compile_definition(src/main.cpp VERSIONSTR) # Create tests option(ENABLE_TESTS "Enable unit tests" OFF) if (ENABLE_TESTS) find_package(Qt6 REQUIRED COMPONENTS Test) enable_testing() add_subdirectory(tests) endif() # Create program qt_add_executable(kapow # Headers src/contact.h src/date_editor.h src/filter_model.h src/locale_dialog.h src/paths.h src/project.h src/project_delegate.h src/rates.h src/report.h src/session.h src/session_delegate.h src/session_dialog.h src/session_model.h src/settings.h src/time_editor.h src/window.h # Sources src/contact.cpp src/date_editor.cpp src/filter_model.cpp src/locale_dialog.cpp src/main.cpp src/paths.cpp src/project.cpp src/project_delegate.cpp src/rates.cpp src/report.cpp src/session.cpp src/session_delegate.cpp src/session_dialog.cpp src/session_model.cpp src/settings.cpp src/time_editor.cpp src/window.cpp # Resources ${translations_QM} ) target_link_libraries(kapow PRIVATE Qt6::Core Qt6::Gui Qt6::Network Qt6::PrintSupport Qt6::Widgets ) # Make single instance find_package(KDSingleApplication-qt6) if(TARGET KDAB::kdsingleapplication) target_link_libraries(kapow PRIVATE KDAB::kdsingleapplication) else() message(STATUS "Using 3rdparty KDSingleApplication") target_compile_definitions(kapow PRIVATE KDSINGLEAPPLICATION_STATIC_BUILD) target_include_directories(kapow PRIVATE src/3rdparty/kdsingleapplication) target_sources(kapow PRIVATE src/3rdparty/kdsingleapplication/kdsingleapplication.cpp src/3rdparty/kdsingleapplication/kdsingleapplication_localsocket.cpp ) endif() # Create translations file(GLOB translations_SRCS translations/*.ts) qt_add_translations(kapow TS_FILES ${translations_SRCS} QM_FILES_OUTPUT_VARIABLE translations_QM LUPDATE_OPTIONS -no-obsolete -locations none ) # Optimize build option(ENABLE_LINK_TIME_OPTIMIZATION "Enable link time optimization" OFF) if(ENABLE_LINK_TIME_OPTIMIZATION) include(CheckIPOSupported) check_ipo_supported(RESULT result) if(result) set_target_properties(kapow PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) endif() endif() option(ENABLE_STRIP "Enable automatic stripping of builds" OFF) if(ENABLE_STRIP) add_custom_command(TARGET kapow POST_BUILD COMMAND ${CMAKE_STRIP} $ ) endif() # Install target_sources(kapow PRIVATE icons/icons.qrc) if(APPLE) set(datadir "../Resources") set_target_properties(kapow PROPERTIES OUTPUT_NAME Kapow MACOSX_BUNDLE TRUE MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/mac/Info.plist.in ) include(cmake/BundleResources.cmake) bundle_data(kapow ${CMAKE_SOURCE_DIR}/icons/kapow.icns Resources) bundle_translations(kapow "${translations_QM}") elseif(WIN32) set(datadir ".") # Use Qt6 macro until CMake provides something # https://bugreports.qt.io/browse/QTBUG-87618 set_target_properties(kapow PROPERTIES OUTPUT_NAME Kapow WIN32_EXECUTABLE TRUE QT_TARGET_VERSION "${PROJECT_VERSION}" QT_TARGET_COMPANY_NAME "Graeme Gott" QT_TARGET_DESCRIPTION "Punch clock" QT_TARGET_COPYRIGHT "\\xA9 ${project_copyright}" QT_TARGET_PRODUCT_NAME "Kapow" QT_TARGET_RC_ICONS ${CMAKE_SOURCE_DIR}/icons/kapow.ico ) _qt_internal_generate_win32_rc_file(kapow) else() file(RELATIVE_PATH datadir ${CMAKE_INSTALL_FULL_BINDIR} ${CMAKE_INSTALL_FULL_DATADIR}/kapow) install(TARGETS kapow RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${translations_QM} DESTINATION ${CMAKE_INSTALL_DATADIR}/kapow/translations) install(FILES doc/kapow.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT doc) install(DIRECTORY icons/hicolor DESTINATION ${CMAKE_INSTALL_DATADIR}/icons) include(cmake/TranslateMetainfo.cmake) process_and_install_metainfo(PO_DIR ${CMAKE_SOURCE_DIR}/icons/po) endif() set_property(SOURCE src/main.cpp APPEND PROPERTY COMPILE_DEFINITIONS KAPOW_DATADIR="${datadir}") gottcode-kapow-350ecea/COPYING000066400000000000000000001045131514263554100161750ustar00rootroot00000000000000 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 . gottcode-kapow-350ecea/CREDITS000066400000000000000000000011371514263554100161600ustar00rootroot00000000000000Developers ---------- * Graeme Gott Translations ------------ Bulgarian: * Krasimir S. Stefanov Czech: * Pavel Fric Danish: * Rasmus Blomqvist Dutch: * Elbert Pol German: * Swen-Peter Scheel Greek: * geogeo.gr French: * Guillaume Gay * Stéphane Aulery Italian: * Alberto Negri Lithuanian: * Moo Norwegian: * Lasse Berge Polish: * Michał Trzebiatowski Portuguese (Brazil): * Rafael Ferreira Romanian: * Jaff (Oprea Nicolae) Russian: * Ilya Rogov Spanish: * Ricardo A. Hermosilla Carrillo Turkish: * Cüneyt Oktay Ukrainian: * Sergiy Gavrylov Libraries --------- * Qt, http://www.qt.io/ gottcode-kapow-350ecea/ChangeLog000066400000000000000000000135521514263554100167160ustar00rootroot00000000000000NEWS 1.7.0 ---------- * FIXED: Did not save time data immediately when adding session. * Added option and command-line flag to start minimized. * Added starting and stopping sessions from system tray. * Added moving sessions between projects. * Added removing multiple sessions at once. * Show total as hours in report. * Show decimal totals as two digits. * Replaced shadowed variable names. * Switched to KDSingleApplication. * Updated link to translations. * Translation updates: Dutch, Estonian, French, Lithuanian. 1.6.4 ----- * Improved code for building translations. 1.6.3 ----- * Improved deployment. * Translation updates: Estonian, Romanian. 1.6.2 ----- * FIXED: Did not quit when close-to-tray was enabled. * FIXED: System tray icon did not work in Windows. * Only allow a single instance to run. * Replaced deprecated code. * Translation updates: Spanish, Turkish. 1.6.1 ----- * Allow higher hourly rate. * Improved Linux deployment. * Replaced deprecated code. * Translation updates: Italian, Portuguese. 1.6.0 ----- * Added optional closing to tray. * Added removing last report. * Always allow creating report if there are unbilled sessions. * Always use exact value for totals in reports. * Only save when timers are active. * Prevent adding or editing session after start of running timer. * Prevent starting or ending timer inside of existing session. * Refactored code. * Switched to Qt 6. * Translation updates: Czech, Dutch, French, Lithuanian, Romanian, Ukrainian. 1.5.10 ------ * FIXED: Did not load locales with underscores. * Improved Windows deployment. * Translation updates: Italian. 1.5.9 ----- * FIXED: Window icon didn't work in Wayland. * Improved loading locales. * Improved Windows deployment. * Replaced deprecated code. * Translation updates: Czech, French. 1.5.8 ----- * FIXED: Automatic high DPI support. 1.5.7 ----- * FIXED: Crash when adding projects. * FIXED: Crash when removing projects with multiple subprojects. 1.5.6 ----- * Extra warnings only shown in debug build. * Improved Linux deployment. * Improved macOS deployment. * Improved Windows deployment. * Translation updates: Danish, Portuguese. 1.5.5 ----- * FIXED: Could not compile with Qt 5.10. * Translation updates: Spanish, Swedish. 1.5.4 ----- * FIXED: Last column in totals row was truncated. * Translation updates: Swedish. 1.5.3 ----- * FIXED: Did not always install translations in Linux. * Translation updates: Dutch, Italian, Russian. 1.5.2 ----- * FIXED: Broken report totals with commas. 1.5.1 ----- * Generate binary translations at build time. * FIXED: Was not properly loading Qt translations. * Translation updates: Romanian. 1.5.0 ----- * Disabled removing projects with running timers in subprojects. * Properly stop all timers when program exits. * Added starting, stopping, or canceling sessions from sidebar. * Added support for high DPI displays. * Added AppData file. * Added manpage. * Added unit tests. * Refactored code. * Simplified build system. * Switched to Qt 5. * Switched to C++11. * FIXED: Could not add session longer than one day. * FIXED: Broken system tray icon support in Windows. * FIXED: Setting locale did not change layout direction. * FIXED: SessionModel ids were treated as signed ints. * Translation updates: Arabic, Bulgarian, Czech, Danish, Dutch, French, German, Greek, Lithuanian, Norwegian, Polish, Portuguese (Brazil), Romanian, Russian, Spanish, Turkish, Ukrainian. 1.4.4.2 ------- * FIXED: Compiler warnings. * FIXED: Did not migrate data from previous versions. 1.4.4.1 ------- * FIXED: Timer did not work with Qt 5. 1.4.4 ----- * Added automatic backups of time data * Added support for Qt 5 * FIXED: Settings command-line parameter created a folder. 1.4.3 ----- * FIXED: Could not save to WebDAV. * FIXED: Restarted timer if enter was pressed in task. * FIXED: Did not use new file when unable to remove old file. * Translation updates: Greek. 1.4.2 ----- * FIXED: Was not migrating data. * Translation updates: Dutch. 1.4.1 ----- * FIXED: Some projects had no totals rows. 1.4.0 ----- * Added entering task before starting session. * Added totals row for each billed session. * Added exporting reports as HTML / iCalendar / CSV. * Added setting the data location. * Improved loading time data. * Translation updates: Czech, Danish, French. 1.3.5 ----- * FIXED: Did not warn user when unable to save. * FIXED: Could overwrite unreadable data file. * Translation updates: Danish, French. 1.3.4 ----- * Replaced icon. * Added portable mode. * FIXED: Qt translations were not copied in Windows. * FIXED: Languahe was not stored with portable settings. * FIXED: Sessions tracked milliseconds. * FIXED: Could not type in timer time edit. * FIXED: Could sometimes edit sessions that were billed. * FIXED: Totals did not reflect billed status. * FIXED: Quit was not causing a close event. * Translation updates: Bulgarian, Czech, French, Spanish, Ukrainian. 1.3.3 ----- * Minor interface improvements. * FIXED: Report currencies were not translated. * FIXED: Decimal totals were no longer translated. * FIXED: Decimal totals didn't add up. * FIXED: Projects appearance did not match sessions. * Translation updates: Italian. 1.3.2 ----- * Added filtering sessions. * Small interface improvements. * FIXED: Totals line didn't update when last session was billed. * FIXED: Always showed decimal totals when launched. 1.3.1 ----- * FIXED: User was not informed of all session conflicts. * FIXED: Window was not raised in Windows. * FIXED: Totals row was not always shown. * FIXED: Timer column was not always wide enough. * Translation updates: German. 1.3.0 ----- * Added printable reports. * Added totals column and row. * Added column hiding. 1.2.0 ----- * Added subprojects. * Added multiple timers. * Added renaming and removing projects. * Added system tray icon. * FIXED: Added sessions had incorrect totals. 1.1.1 ----- * FIXED: Missing columns. 1.1.0 ----- * Added inline editing. * Added note column. gottcode-kapow-350ecea/INSTALL000066400000000000000000000057171514263554100162010ustar00rootroot00000000000000Installation ============ Open a terminal and browse into the extracted folder. Linux: 1. `cmake -B build -S . -DCMAKE_INSTALL_PREFIX=/usr' to create a location for the build and then configure the program. There are more options you can pass to CMake, see below for details. 2. `cmake --build build' to compile the program. 3. `cmake --install build' to install the program. This has to be done with root privileges if installing to system directories, but the rest of the build should be done with regular user privileges. For packaging you can optionally install the program into a temporary directory by setting the DESTDIR environment variable. For example, `DESTDIR="alternate/directory" cmake --install build' will prepend 'alternate/directory' before all installation names. macOS: 1. `cmake -B build -S .' to create a location for the build and then configure the program. There are more options you can pass to CMake, see below for details. 2. `cmake --build build' to compile the program. 3. Run `mac_deploy.sh' from inside the build directory to create a disk image of the program. Windows: 1. `cmake -B ..\build -S .' to create a location for the build and then configure the program. There are more options you can pass to CMake, see below for details. 2. `cmake --build ..\build' to compile the program. 3. Run `windows_deploy.bat' from inside the build directory to create an installer of the program. Note that you must have the NSIS executable from nsis.sourceforge.io and the 7z executable from 7-zip.org in your %PATH% for this to work. Release Builds ============== CMake does not specify any compiler optimizations by default; this is useful if you want to inherit CFLAGS and CXXFLAGS from the environment. You may want to add "-DCMAKE_BUILD_TYPE=Release" during configuration to get an optimized build. Debug Builds ============ You should create different directories for each type of build: 1. `cmake -B debug -S . -DCMAKE_BUILD_TYPE=Debug' to configure the sources. 2. `cmake --build debug' to compile the program. More CMake Options ================== -DCMAKE_BUILD_TYPE= Choose the type of build. Possible values are: 'None' 'Debug' 'Release' 'RelWithDebInfo' 'MinSizeRel' -DENABLE_LINK_TIME_OPTIMIZATION=[OFF] Reduce size by optimizing entire program at link time. -DENABLE_STRIP=[OFF] Reduce size by removing symbols. Linux CMake Options =================== -DCMAKE_INSTALL_PREFIX= Choose the base location where the program is installed (defaults to /usr/local). -DCMAKE_INSTALL_BINDIR= Choose where binaries are installed (defaults to $CMAKE_INSTALL_PREFIX/bin). -DCMAKE_INSTALL_DATADIR= Choose where the data files are installed (defaults to $CMAKE_INSTALL_PREFIX/share). -DCMAKE_INSTALL_MANDIR= Choose where manual pages are installed (defaults to $CMAKE_INSTALL_DATADIR/man). gottcode-kapow-350ecea/README000066400000000000000000000023031514263554100160140ustar00rootroot00000000000000About ===== Kapow is a punch clock program designed to easily keep track of your hours, whether you're working on one project or many. Simply clock in and out with the Start/Stop button. If you make a mistake in your hours, you can go back and edit any of the entries by double-clicking on the session in question. Kapow also allows you to easily keep track of the hours since you last billed a client, by providing a helpful "Billed" checkbox--the totals will reflect your work after the last billed session. Portable Mode ============= Create a folder named "Data" in the same folder as the executable (the application bundle if using Mac OS X) to run this program from a USB drive. Simply rename or delete the "Data" folder if you later decide you want it to start storing its settings and related files on the host computer. Command-Line Help ================= Usage: Kapow [OPTION] [FILE] If you pass a FILE as the last argument, Kapow will use it instead of the default file. The FILE must end with ".xml". Arguments: --ini=FILE store settings as INI format in specified FILE --no-backups do not create automatic backups of time data Exit status: 0 if OK, 1 if unable to work with time data gottcode-kapow-350ecea/cmake/000077500000000000000000000000001514263554100162165ustar00rootroot00000000000000gottcode-kapow-350ecea/cmake/AddVersionCompileDefinition.cmake000066400000000000000000000024671514263554100246110ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2022 Graeme Gott # # SPDX-License-Identifier: GPL-3.0-or-later function(add_version_compile_definition versionstr_file versionstr_def) find_package(Git QUIET) if(Git_FOUND) # Find git repository execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --absolute-git-dir WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} RESULT_VARIABLE git_dir_result OUTPUT_VARIABLE git_dir ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) if (git_dir_result EQUAL 0) # Find version number from git execute_process( COMMAND ${GIT_EXECUTABLE} describe --tags --match "v*" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE versionstr ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) string(REGEX REPLACE "^v" "" versionstr "${versionstr}") # Rerun CMake when git repository changes if (EXISTS ${git_dir}/logs/HEAD) set_property( DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${git_dir}/logs/HEAD ) endif() endif() endif() # Fall back to project's VERSION if ("${versionstr}" STREQUAL "") set(versionstr ${PROJECT_VERSION}) endif() # Pass version as compile definition to file set_property( SOURCE ${versionstr_file} APPEND PROPERTY COMPILE_DEFINITIONS ${versionstr_def}="${versionstr}" ) endfunction() gottcode-kapow-350ecea/cmake/BundleResources.cmake000066400000000000000000000027731514263554100223350ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2022 Graeme Gott # # SPDX-License-Identifier: GPL-3.0-or-later # Add files to a macOS bundle. function(bundle_data target source destination) if(IS_DIRECTORY ${source}) # Recursively find files under source file(GLOB_RECURSE files RELATIVE ${source} ${source}/*) set(parent ${source}) else() # Handle single file get_filename_component(files ${source} NAME) get_filename_component(parent ${source} DIRECTORY) endif() # Set each file to be located under destination foreach(resource ${files}) get_filename_component(path ${resource} DIRECTORY) set_property( SOURCE ${parent}/${resource} PROPERTY MACOSX_PACKAGE_LOCATION ${destination}/${path} ) endforeach() # Make target depend on resources list(TRANSFORM files PREPEND "${parent}/") target_sources(${target} PRIVATE ${files}) endfunction() # Add translations to a macOS bundle. function(bundle_translations target translations) foreach(file ${translations}) # Set each translation to be located under Resources set_property( SOURCE ${file} PROPERTY MACOSX_PACKAGE_LOCATION Resources/translations ) # Inform macOS about translation for native dialogs get_filename_component(resource ${file} NAME) string(REGEX REPLACE "[^_]*_([^\\.]*)\\..*" "\\1.lproj" lang ${resource}) add_custom_command( TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E make_directory $/Resources/${lang} ) endforeach() endfunction() gottcode-kapow-350ecea/cmake/TranslateMetainfo.cmake000066400000000000000000000051731514263554100226460ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Graeme Gott # # SPDX-License-Identifier: GPL-3.0-or-later function(process_and_install_metainfo) cmake_parse_arguments(PARSE_ARGV 0 arg "" "PO_DIR" "MIMETYPES") find_package(Gettext 0.19.8 REQUIRED) # Generate LINGUAS file file(GLOB po_files ${arg_PO_DIR}/*.po) foreach(po_file ${po_files}) get_filename_component(lang ${po_file} NAME_WE) list(APPEND linguas ${lang}) endforeach() add_custom_command( OUTPUT ${arg_PO_DIR}/LINGUAS COMMAND ${CMAKE_COMMAND} -E echo "${linguas}" > ${arg_PO_DIR}/LINGUAS COMMAND_EXPAND_LISTS COMMENT "Generating LINGUAS" ) # Generate desktop file set(desktop_file "${PROJECT_NAME}.desktop") add_custom_command( OUTPUT ${desktop_file} COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} --desktop --template=${arg_PO_DIR}/../${desktop_file}.in -d ${arg_PO_DIR} -o ${desktop_file} DEPENDS ${arg_PO_DIR}/../${desktop_file}.in ${po_files} ${arg_PO_DIR}/LINGUAS ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${desktop_file} DESTINATION ${CMAKE_INSTALL_DATADIR}/applications ) list(APPEND metainfo_files ${desktop_file}) # Generate AppData file set(appdata_file "${PROJECT_NAME}.appdata.xml") add_custom_command( OUTPUT ${appdata_file} COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} --xml --template=${arg_PO_DIR}/../${appdata_file}.in -d ${arg_PO_DIR} -o ${appdata_file} DEPENDS ${arg_PO_DIR}/../${appdata_file}.in ${po_files} ${arg_PO_DIR}/LINGUAS ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${appdata_file} DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo ) list(APPEND metainfo_files ${appdata_file}) # Generate mimetype files foreach(mimetype_file ${arg_MIMETYPES}) add_custom_command( OUTPUT ${mimetype_file} COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} --xml --template=${arg_PO_DIR}/../${mimetype_file}.in -d ${arg_PO_DIR} -o ${mimetype_file} DEPENDS ${arg_PO_DIR}/../${mimetype_file}.in ${po_files} ${arg_PO_DIR}/LINGUAS ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${mimetype_file} DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages ) list(APPEND metainfo_files ${mimetype_file}) endforeach() # Generate description template find_program(XGETTEXT_EXECUTABLE xgettext) if(XGETTEXT_EXECUTABLE) add_custom_target(update_description_template COMMAND ${XGETTEXT_EXECUTABLE} --output=description.pot --from-code=UTF-8 --package-name='${PROJECT_NAME}' --copyright-holder='Graeme Gott' ../*.in WORKING_DIRECTORY ${arg_PO_DIR} COMMENT "Generating description.pot" ) endif() # Translate metainfo files add_custom_target(metainfo ALL DEPENDS ${metainfo_files}) endfunction() gottcode-kapow-350ecea/doc/000077500000000000000000000000001514263554100157035ustar00rootroot00000000000000gottcode-kapow-350ecea/doc/kapow.1000066400000000000000000000027021514263554100171070ustar00rootroot00000000000000.TH KAPOW 1 "February 2026" "Kapow 1.7.0" "General Commands Manual" .SH "NAME" kapow \- punch clock program .SH "SYNOPSIS" .B kapow [options] .RI [ filename ] .SH "DESCRIPTION" Kapow is a punch clock program designed to easily keep track of your hours, whether you're working on one project or many. Simply clock in and out with the Start/Stop button. If you make a mistake in your hours, you can go back and edit any of the entries by double-clicking on the session in question. Kapow also allows you to easily keep track of the hours since you last billed a client, by providing a helpful "Billed" checkbox\-\-the totals will reflect your work after the last billed session. .SH "OPTIONS" .TP .BR \-h ", " \-\-help Displays help on commandline options. .TP .B \-\-help-all Displays help including Qt specific options. .TP .BR \-v ", " \-\-version Displays version information. .TP .B \-\-ini\=FILE Store settings as INI format in specified file. .TP .B \-\-no\-backups Do not create automatic backups of time data. .TP .B \-\-tray Start minimized to system tray. .TP .I filename Time data file to use. .SH "SEE ALSO" .BR qt6options (7) .SH "REPORTING BUGS" Report bugs to . .SH "COPYRIGHT" Copyright \(co 2008-2025 Graeme Gott .PP Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). There is NO WARRANTY, to the extent permitted by law. .SH "AUTHOR" Graeme Gott . gottcode-kapow-350ecea/icons/000077500000000000000000000000001514263554100162515ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/000077500000000000000000000000001514263554100177105ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/1024x1024/000077500000000000000000000000001514263554100207755ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/1024x1024/apps/000077500000000000000000000000001514263554100217405ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/1024x1024/apps/kapow.png000066400000000000000000006376361514263554100236140ustar00rootroot00000000000000PNG  IHDR+sBIT|d pHYs'G'G>tEXtSoftwarewww.inkscape.org<tEXtTitleKapow icon>tEXtAuthorGraeme GotttEXtCreation Time2011-10-17B>IDATx읋$Wuof==ݚ a $A$X?]džm6b7~b aY^c#&BX %#H !ͳU{onԩ{3gzf~ʪ;97)MSӡSpH,[X\y1JGq``O}CR{! $|޽޻1=`vvv KKKC< Q?0*ɴoG{{{c}O^P f9ևLiǯ0 IE~PD}L̗ *^Gy~YZ483b3 "ɂs0Oq[L}H؇{Lć{e[_]]MUľ}}FQ5B_{X,>h1?q)IW|-𵸯#bĮ۷u]/jH\qt@*/7=ܹs^$X8зKc@u H`c0 뮻j|-ĽSoIL*&=G :!e&86Ɂ2_WW |/cޟ''/_\\ }-Cf@]_i ~}}ss3x3 &11`MV`5'G[?Я/!ŵj1/wX`JEU 2m1c8O( q́c`RSC0b_V*CU jq}~* &-L*8g5 : ijsL+NOR߯P%?$C}~~>cVxg[ H`vufm%1 b? }\^d[AЭz7))! X_}-_XXHtUЗ" q8NtE~T-VTmi@j9vy^|7bh3y.߶w$NmݤkL7MvM63ab]Mw܃_8j(yz+Nh>92|bN+/5Lq hGH}]QXRD|Ou%ߋ~)j?iHDz<'V7:,uo+Nz˽[9{͗9KVZK.u`~bZ\_I]ydǦ 6l`3ٳ۽˖l6HϤ뭗Z/B#&ALq[ny$ ow]%1Moș,&1*0*KM"Ce'Օ}-OmBUE?U>~POKekۻݺwz'l!;Q_P̦ .$-8Xk<}JMSzSrvO~V_׏ǶX[pƦ:qqbAE{N&E !Meƀ?~kn򺦀3dZ 4`060IB`tf\F_Z;L׍;/ _Oy)eD?B?$%[f޾wsUO٘lL;>2?fxLSԴ&G+7^pζ 8||Go\hzQoO؏/L!SH:%6p c ``e~_NCb=NWeU꾎72QU}-m\νv߲k;7Nnql%"Eyu:eeEU}]!=*9R>oM?m?~ܷ^m>5<\%rJ˴@(0*iȔNHS f ^K-/^jP选[00xEWWWSe */Ž:o>y9?C_C{{}f+Onl7Wc"L&aT"p_-1~RC'f*TI:EYR46?g1`|sG3ά S(}@_xW!̀*/V,Go+8~/eL}'~^uן}{?wl cMv.B:-1{L $PDD}Q22ʌII͘iw5Bpo>g 0rm R_y@  =X4XY@,pV D?ퟤ_B~h`C_,7d~/{){see7[J|?1e!q,:q014xU&1'dou+~Ř_4 /Yy;|O?}l{yL]P@fHצtfQe~9_Nw_W]LŽcg_g}[޾f;}bX9T__&C%%̇X"L imETI^"CgϻAp@\hk>z[³nu~ b)*`0\p-tOt@h D!~9/$R]S*>_%q &nk(Ca-ܻsFOwo螶[֯_&13 $ 䧝x$T eC[U=֫3"v[Q"-F@1P1ă 5imxjsO١QioLme gȴ_rP0. ʋ$0pUK&}E_m/{וOCV͠o_ӝ:{'{oh+;e?y W֓ uRaS7ړ X]!fc , Q61$oS3ھP5h:e%|2Ggg%|T@ (1r/|:m!pf +Z X_ ~_嗃7|0Hx6l{oq7A}oCLz"l˷Qr'LiЗwpVfnmmù K."#B}tzԩ!L~~=o l6ko}h붝}m|)ib2y c*̀45&^Y#}l<&눺qކ#3ab¯Jn} ѯS y dҍO[}w[xDNH@&@VfeiL<8#`_K/0?MC_ M_`} ;wd'љCey@7Թi Q< B&7 Q꼉ucW"0xnF+$YcVmM!%`^lڏ/~m}QJ dbVP6o00JWE#Ѕe_u_Nͥ~'e?"2Eo7y[w߼{G ~L~=MM8Z^/?d?|uM:L.AP󌭆P6Lj: $p Il,aM ~oŇۼ9lmCmn߾demr5"d%"LNԮ~˩焿^>2*оʿ}޹ݷV{2?4l=-3ָ]$"Lk c%yq}<`?d LoyTwe_J %12$R2%P"0*/ZE>~ E} J@7JߴU7mݽuOuݻOX(Ϯo#`"2!A:CbB T@!ZhkW׎I/roe]VlELr`!CNH 5)iMKfBApd z6 a s^r Ӛ-0z4 Ȅ1048o* $C=ɿE(_5~ MqwnӯT%Ci4 KJMJD}_l>(;"40ЋВM '5\2_l$.d*@-TX7W `{/crocAѯ~{ݸ}.;N/H>ė}=/o9y?5bvVBTȕ e1p X lp wW kkka`ub/Er:?"mɋ:Sz&pLWe?,U? ca_زƄW8g?humq𷯁ȼ!3tLnp`٬gT  +Swe1_Ho4> w=f?~Ν;N~auE6L|z6R,"3B`iV/=P44u/ܱG;]p@I@S.Mm3j>p #,K ??P?=_ j@E}ogظ/bq_V쥐l>@L . `J^FP:5pf@M6?jm᥇:c P@N*~9Ao8?XNphh`=9p Ʀ˘~/$jJ@7 qwo߽7[n=Ї WSuLK, _ p ̀3O~8֦֙3@ovT\A=@`[9p`X;oS_=$6nۺgkh#K./ o W'eq@PLS;8 /=  TXN0@ e]7"s0R e??fhn{{o>Py_GMOJL"b#MHƪE 3G8$N6,~+ZgRnKe  CA`2~z{/ ڟ@\kN_e:ޓ>.~!1_W}؋2IklՀ\G:Uyߚұ9hSЬid*grN8F*ba ׿:4  C~U~;޹iWyO. [-Ӏ 9#LWp5t dI1[N~ϋG6AK@/̀T0@~P?P}ſ5'޽_V7Cw}/5pHf? '3BuqwHiG4@  s\ te12 ڿ/u_Vw }?{Mt?wޯ?\3o"B^/ї0-3 &icf? YH%إT}D?\ f@Yk8-%dlvhC3ߞy1 Wp@lN@l`\9#0.wO~)~?߯*6߲yw5/[?5d_'pL~5RvaL;4֣_Z|h;wu"@?#blJF@U0t?r~uސK9}j6I~=;ڹ?;:c9Я0)LsQDWu_ ~,́RXk<3͹jnN3D*`NX9` >S^LH+^*16;v㶿~jT^ $pܘb¿fo,%ekyZ:P4&<00d0|Lws3O|asvNO: =0з D8X>p"#&EM+U˄ ߏˈ`}klF1[6Õ})@ P V~x#fP_B"?r)<"x@%nN?4 rKI评H_o|x{7?Խ֯*!QޯuAg-_0ܖ۵(>Eַ҃KO ՃKN`P `'c?wuuǿL˥"@̚umߵ}v,GD3~l ?-uj5beShŀ@}Ir;'o?t/F[D"`5c[UO |wzYԿL/R1w;v>\J0)FqK1\+fv)sS>/ f/m79?Wt[F0#p_$F&`CS>=E4_?f~ ;w>bPh/|`h1lp= K.=>?Ybs- 4r~N7[BpF@lm\0n_Wwbߋr~L^}~#gj?@9U^=@RO0'o<66OƎ}@7 L`>XAo}*BF@dP F`n{ o? {9 [Z¿N,⯍#Y`:FlТ>33re&00>/N|Ѭ WЫ45Dz F3psU'NfMPE/ڊ@mNdT_OR) fԌ2 /24'`d6̮0apilI?{__P !M@>P'mG0ɌO%@&)̓F3@.d~.}/ҁz+s%u']>bI}oi_o ?[1տJǖ Up4 R pi+t" ujs[ȌD8 ྎ@0`bN]/go~'dۺN+* ; S!/o̫iV9 S4$k C`B# JbҁN?l> | 3Fh_7B~DT?:_kNĞ^: P B?3-!ap~&Ci/zP4``d^N?~??=ߕ}`d7bЄKҏ2mH)S 1VlNsg7{_p\:1 <ſwuu5&s?w3kf|̯ޱ|6_k~iȕ3K$gc ~cnznٿ]lt> " 0;`ܶL ~wqc_ ~_(?0qOݽ? Oh =2Pel/.~u}'L5 deh =/]u_OV]_oZ[۽zM$e~1qzBc:%`f46\~`/Áh pBV oc0$0!?wIdo^ws7;뼷R~ ocDk [oտi?>jP`p{kO|O-#2o /dbX8ٽ}E[3ZG?nJLx&P%v%{O>xO|>l4\1@&bm~>}\6 lY?_}~"F>g߳}퀿h ?y185z#:!0`V|SvĊD@$rm x'WM?$MW}_7o[w-?i(~c XkIakg=t3LmG0H-Fm0  +DŽ7`?/݀;wo 쾦o(~("@5Z/>6}O #@Z-m0  Ww7urY?{[W}7ͱa“aF1tF4B %t# 7gpNƋ|A+W F@l4Y-.ĿW6 ?aL̜_yobØt_DpBr\kL^6(l}klϯ z3 m~P3`'!?Wt 0|+?T}=aFuPF1KߐMidJ6%ҭŇyz'zoIWPKzT`nFB śg]ʟTO|KOȭ^-m||ܶf`Q?Nտlȟ Y0gv~acVj z!#<(r̀|0tuv  Ll`%I`s"K>|1m&/Ioh?pԌWEp_)hL4@xlj O $ NGݥ}*_ K O~}R\V47ʾgyb> m7h?ʉ?y6߳E88Z Ea\FLx>)$k˟Yo(L%  8/??_5֝/΅콭=4̯0l!j ߛӛgYݹ{wO &&U}j~5sgm?ZޮCO f#uT(aZFVd39O=X~8h}KkvA[@4\z_ZwW.1CDտ/ vl)7a \͆r``Рps8'̀}# d i 8|Ѫn_لYWNTv-{{u] cxIMCI Z@a>?<׍20lg8  _{y?ܟ?N_Mo~?sloSL@1fƺ5 3qՐWb_<П 3BiRz>^9`ſ^ORDZ[?߽o@}}i$WyZ:Z ڐAR#$3|Fb`ٌ"a1?̀FbE`UU?S/]WflӊC.*|j@=J ޿wVdl@`{b@jmA 4 "@oXOhߐ~JEC =U_Y:5%󂈿kK- @)vHHB/ZN6`"-dKDێY?;O_Ts!5+%TɷLsJZ$VUgɿR=bdl]" Ԛ!Uw'.K2 n`#Ԉ#n?oHݻAǮǪ^gN̼iXCJ!L L=yH 4) n_$'X;۱~mowg^_U//,>,!~Z` * @ ЊI aL@`{B@6CM@#nMӵL `+B[ ۪?ğ3dJٶDkxmӯox3NyGJƊL*(%8_na @[̴vFXrJZk̾ןk- V+̿d /]6Hx?O)Q#H|Ā+쮯ׇ~ؠ"H6@5.d@ Zly/j_ZZ?kA'տ?ۙէ1_ZyH3ۯ+?ZBdE L S):-Q7̄+ DK@ӉJA cVN,^0깷;ӳ~ ;֏~ %'OUo/$0-ֽĿw|wωپR7uhX%`Kgʿ!Ckf[@WП7֩+ *."ǷĿzGIGNDM 1 eAR_:53.=%7`@`[ ۪?f[>>򵑻l;i hHSD~Z7rl6/S˿!&O_bo?WhϿW'_R_WD@Nㅍ&rpͷG&&K륤0"^;% "@ !]UsǐRoHݻRs˿N~K.ߕ%c- -6:20"BAT,TeYaJ@5. `& hT r__"}} Ϙ @:ZHcuU]ؾB|L o( J<3:% \+KE.  07UHU<6ls?  3yG^ {˫? PQ aB BT5w~o_~v@&,hFnd.Dߟ~Z0ϐ}oCi}&8|/wYiU-_ ? +@):^hK >*\">& ꪫ3O醙۠?Juѐg/5};i=߈s˿GpR:.l[Be|x'4XN`@s "4쯨ߟ!3w ޒU/L.~/sH45.^XeEo _?\en&p ewqR߆˿&ʿ6&_ro)W>bSJ9XTw՟R!@ؽ:ovp h\mo̥ԺĀ^l6?!Ǧ:hU #JƋ6:Vr3>>ڣp5$$4g׮_w%3?) EKN i$Zv#;aTm.^_5i8 k|Ŀ4/ 3ߐSx%KW,Fb«ToE9~Š)y12!֎{? @ZM `'!_3韇 m 쯏glǡ]8!("@@{R\o 'So~]HK=F>Ji4-pR.)Oofp `DB0Ii؟!߯;.[:gf0ݑ^T)WUjT`|4 =^W]#qvB ,„l _?663 J7"s/>eu'AJ;@<N<[ âfe[C?jVChBvw@1__<1)'=!!3!Lz&4i&u1pzDIm^KGϝf#韧+%Wcƈ?8yֈ-Zcaqʫ=>eKr9[\D]H8ŌK€!烃w>jT;Nh;ZtB[mlYH^p 3k)p>lj~&gK\ \t_)y~OW~He=PD#BYQ3J {J-ĝw3vZJw߲;maZ @̂ijSR[TE?`_qP:Vϓzgҿ" az+[|qq Na{|yV|sRcx5=짂]_9㿑R}>@f"Q"=OVb`s D`+ |\`1U&ŀf{R@O0cm. _ZZ26ȐE]IoW SI//jU}QUWSF9oq҂@GW;8y-{.&1'ܞ篐׸Z**We@!pQ@)+%'@z*l-'|m{Vi6s\")Dlao>C+V 7_WMwyV3QrEG[qK[gpR+[J]ۤ^"E3|YR@$B@$jV![z_r ; s2%;*M>D{Vi8 (M0"^"Rs  o듽8٘?Sϓ߱Ф P, }qSR_\R $%ܧezS& XG@"R_! #Uc&rA V8r_A'|؄p $ vL D&ߐ#>?FJwa{wPC5h~A5v;fhG?ߧ5C},Sjע5{?ٲ:=͎l}u17DPowҊ='=*T(% CA *'@"2Ƚ+oU|CQ]vŻr67$ߒ"zuQX3#@. B㷥l)?vMJIHsǖ"PSǝTW` `;Jx[o lƮ}]V\"l6^'@lQB@ ƐG<ߒ[71s{o,\?]l$%?9`~ȣJIR~8|(vw[ Cyt5_z _V=.t-r?>wT.Q:Vù(`V X0 S eP1j1@E(@lkF]#UCZ2'Vmk8 ׍ @-@r[J۶1]٫_FisAEgNlWү(O+S/f+-*GM~,oќo~RO k#}{_c`D#~k}[~iA- `&Qt~ n39|L 8@I{j!RvPᖏ_Vό~qfJo@-@N;aq}ן̼aEKW.gZ$ڊ4.x+U~OIj?OOAn[ o{=joWc[2]ໞ#T pg߆/3ZOU ϸi5N7s6]k$R'p!1!@*Z `\O"v p߳CձQJ"uXy0 DB{cMࣲ_^vG/?zɿ4OtH'H?H# >~IoyU?x$DG ȿ c=9Ps}g.M{ @<^QfA; @#lcWc BwpW>1vj`G1eE68B $}맮^d RfU>+ =H?7 H4OJ$?#>C+97I."x轊āIЯ5' ̻>'nN~* wLjCIT_ =쀪uA^B#l So 3~m-{[l>u4h0``hh(; TFD߳_էfiO+5R(ت_HUJOG<Wgg*g[/U]H!->Kz6C~Z9\Q7t''rA&Io!oQ;Чi."z}`SvMiE"@ sOJݟ^glzsƯ9vBӛ9!8^R~BH$~^}C !gDg#3DAGދyWFRAHOO3oGѼoȾ G~予\>4섀`#~!A/zt:x Փɓn%09N1@ t <$.1@ANk&f* P{v5jDKFp?_lv3͉^)ZCy1[yA1"N+ ##H].u^|:rzZi_$EdWHY-H n{m5?4K=Q 1!{luj?N[#ђ: *F0B;῏t8ݭ^Sˊ7DĒtjӷX[.:0T ;r~~˓=G}}Ā2NN"@eI E}Ed=|OMgù Dsh.g$(@>&Ƶ ծL@:S}@vd EB k!R'?8d8yO:L@ 'oK㷏(T̮}MD{ ]9[բZT2Nׄ"U15p>cCE̚/:lV9?Qjd\mt-TL_<_T+?TU7J^f)"ͧ5QIs//X0[GB**!fB>sN|1үo"Ev~/">wO("E@iұe'y)# D>~_@AV]I]= 1X1T +@l&J,",V#_{6ǖ.? "/ W]u77oLLmi==%UwujU?,@@?jĿH*oI T5%IX4.\~W*U+ku9y_3#M(XF^c^$hNVĀ`* T ຾:l%@QA I : X"qOUKVk뛹g+g일a ?ER[o?`:B-"~+oH3*PϬ>SD#.oYCϗ}2Ea|x.Bkh@ K  ,!_okbyl>'mbv< 9 6R#`?N)ix;K뮻@@`c_ZZ)7[W*!f[3"!o6Fx菂m1Y$(T>ZO{[.H]dsqKA  i._D]Ǘ}}>%%f@@_5DD"7P 9mMbb׭Xu{i Q|:@]RU0qğV&+seE]2t="p:|kA,Psp?z|i_^k$lF͟q}՟V[lTPhoNQ}FȽϟB@{U]=$52Pzk+l?W-3 |B\=!S| !{q?'>7?Ω'?V?M~)? RJvXQ%Tpl$MD r!@G[Vh D_@M߿D> 'OA5yo[ niG+6Џ)o*p^S@%k!ETH&bo_7A(C*z;Z\"mZ|buZǯoRNsD(/޷h):EעM*h4 T?zMkDN9"ض_s?_$d&lN4/+Ez&-rſE&y mP Ϭ<3'!X!(韻( R_Q}%!e7Bp}K(("0K]D]DQK%Yg`[\ߍ tĀT|-MȾ|-9\8"@&{Dڡ=ZmUhm!#'@DGFF%4τőM٪Y$Q2mokռ{qd11N5 >j?%W@\TH]Z4$[/^#rMJ]DEE* IAQ4E+Hs}JԽɽAg)vK oV "uD5fnHP[2B@ڝciV"XP@pڐβ lȿ~ܩm߮WI&+Op|sƯy`,,~N53`lʇ}DX4uvEʳԅ U5xKE% Br|@@8pK> XD!p$({`#!%tOD Ho υߋ;g'!uo^x+2 @ ZA &qS%;#=})+0`Mv<z ͔T_?2t%|!c߽{wNM_+ժDd/I5O_}!f! Yp]aߺlC#a1 }N9Bʽ/E]D'HWM[8'9^""!jw Eؾ9iχ 邺/OHlQ2+F5ю`}\#7_Nd_K%!P7\oO|h `K`"D̓p}S`}"ʿ,'"o|+/+R?O8S)Jl%$O./Is{\s2P B|;|//?It(HOzr 1 ./ >1Z\ x(}(w \#HH*y=Du`3.tGǿNsN.lL>|8"^mDpsۿ'AO{]W$Ϧb'|JoݯKSٴ,P,ɧ!48f$ ȯ<oc1v;hK Px@pZlɿʿ!qokW;ˍߛyҿZz#T-H< 5?j_oͤ}#HJC+O{W0 }>r#!-rL?W[Z~=}j}/= :I8p+8TZt Jމ{ `4E[߯as߲We 4 `z=ey})6wB\uߩ7̽f,Q<-*F`3,Bhǟjl=D#9՜B:\hb@Y1kC+eB볥}.+H}}.ԇJEqQ"۔|s-s_>j.s *!D(058_*P=eS7 gF8rG*JE4ϧXfDpڐ:G}K0s OW?< Fo, *W]iоNU-Ytt|^o{}!{HuhVW@u1"A tJ]RO_g/}iY>A5~K,$?w[|'?Ww'wDzºYROG[?`^2~G=߻n?P@u `R.@&G@lM߿>U +C% S*"߀|jYD?p*|"v`?ϲ+>٧Vq>?}2J41H}2ϐ5%eZKB'|gT)Yw~Rz}#y@+ަiuWrz0};4%l BD))V>}7RL+7@fRV!\!y蟩j'俯_gϿb]Y9ɿRU(~p ?,H~oejGC${.~sU}XKB{H?#|YzBp.Oĺ t:K,V}?)81E}I8?nP2-&?T$GSݶڭUxpNy)S4UG>bP@s3N J#6_"6:_o v0pW\4{{J6$amQpH?'-"V7*4jTuy{+[wycN~Z,?}EEdI@IDVO?} qٖ)\EIHDTݥU'289\h=N 4#tTtTov J 5+T"q@G0[}} ,85}+F_g=oꚩ?j OÉhX?p'\ΩdR-s]Ah_ѱqe>]"_PTO*ɗ}k; _8IZwsv䀢ti:$HA8>XXp VQݭp'dA+i:TЌ6' >VV-Ugؖ0@C1lYo+'ߟSm_W_t0[x"^DzC%8?bYRo}m߿?ޟW{T}JXDCGmuQ~.J$i Q>A@r(K?5RGm|_s_G0恁9!Bm$ik E[pE@'8w;xjCdm@`\mAeV0:"ج_)Ǹ!CPV%TH؟ Χ&Ʌ'pjiFKpXU[JKKs+U}V~>OrF*KD] f/k)'#(!DezHB}.a "|, \~43RRoqRk#ugr7/X޺@֧zG*u|r`#E>"YKV+g/Z@r'.%`ӒS_ZZ-L8߆Y_O7l^=aGW{ܟN@I{zN} P_YRv޳Ŀω|QH!U~9N__DA H_,8ׇR6('|y^(wRqu='~rB@j7GANT IQ;NPvN3`< rKjo˵ɷN^r˼'ÐzE?_~Uu YP˸@0I*YkM Ӷ؍(ʾ4` *4(΃'~|{.=3~oEEfUft}̈wOt'ϽYuo|y˒?L-o)jgk߇5PEزy/[YS}<+m@=oS ]m&!4o 6oS| x8<=Y\È~h@P ]5quQF/z_%=0_3 3L/eH`ݿ?9]π?-߸}Ş\oc%d?ڽߏN\8 c~֟DmE>'K7Ϗʓw[ߕݷe:( 󮳚a<NxX!K aȣ(JJl$A=@+@J] 6 >qI^~n?hgD?7A4?: 2 o"PK{O1@R.3UӬO%Oq?1PqRDT\;{G'c)OdA;3ӃNy$\ ަ$x z/ [Yki` .a>/ȗuY]Ϻ@!ڎH \s~ 5 Oypy v%D,PUQ 7u"4>>6}Ha=D0?g{yEk׮O ?&S??w2֭q 9}G ٟҏ<@ 1{V9M|Yޕ??eYɟ<Elmfc.A^b #o޹Ӭ+>[{@"|g?<DŽ:v(Km-o|ht͙*4:%~_:@cƟH^'(ٰ$\;/d{$w ( -;o޽lص6voJ_0},XK/O(y@Y}2:F0!sݟ&E<\l]D33pai6ky M}Ye@S8F/y (#m 80tB2^:;xS@?<Ǹrw/7lkկ/~s 0GXYn{vjx*2ն,qqw~[]??E[ytɾoٳp? #\i^#_RXu*wȼ?c ߘUM Mo,_ 뵸?$NXVK< Ϯ\Ï1' g{C9 y4P uLWlHo 'h'[l n& 93O?lwYF? 6{Y.>42uhv?6qXd ܻ2Ozee'w N9׭_aJdil\8}!|/Öwį A`+j#livJDnpR|\__GDGU2 .M%ʁ,@ViqNEaT2I WHoE(A;"c*<p <οk}VI%@fgo 'uGf?4:O;'VOxy?-Yvt [-,Kjmr^ok~6b u&. ob;߂v3 }Q  }.~mv vZ ϷJ__c/xeB,ײE\lź:x,zLj" ,E{HXg) ?J9M'dލ>|T+-U@v~@4:\1kON*AwНY綋$hk~m geYY<,sl~d'$ܹN,{Q[缻TPIb 헏f/-k/'a+d@VkA 5 uue\pbcZY% }G8#13c*~ O zi7^ 4d*ށ'<&LDP34Q?Oܷ]mޓ^2 `ydw_+daf{UU07k'Ў&4RЗqpKmU_4nVyf*b;p%N{[Gj}n:V wf+2 TlJn2wplF<,"Kuz&pl߃fSN7E&$e'o9<pڏӜ/͹LIS@IxS@?<G+i韹B?aLHշ='l[UNp zGŘBLYAi6>uhǶ~ggK+/m2{/:H<26Bv\AA,Y+"m:2[˵p헯z\o&yY애_V;Ehw{l++ښfDpztIFw[IW7 &fXqO5&lmy@N?+_}G\i@) ))0G鿹 $ '?KP/F?o{6D3UσT߷,x)30a$XU΃CC K A@|8$BQ z?O7<~YǕ!f3p^v7ʖ<+! Y=w K/)[Bmc]@9>}]] WWщ A#\<#"\]\d4/,/ͦ~CS7ӽ^ G1o/R lII,?O  ^_/ͮ-m Y__GE/ļSZ} t]^DžY]g۞F_lVןY~o-_:?UY6k$Ny4_!rp\&/!k:.ÕѕpY|̊gYI^D`+$yPФ1z/(Pί_l*  %PzثP'}C/3IbO*\l2) z `׮]XPhv< ?`7fjaƺߴEV56VXp;_W?\;LШeʙM&5`_{uMJmufe2IpO87vI?/#g<""7M(Yq& ϸoƧf~k0LKFXrmO&?sk\,Iwirߋ;n6d,_ՏD9/QWggE`z8='N>?&%\^_ce]?=&;R<𐄀u1~-pZ7>{<Sց [dUL ~8S's)YKI {Gxx=D% ߷F~]6mJ'p?/'"Aļ;Dhȿ|]+Dʹ?CSEL9G/Ϟ'u5{#х>%bca. & 4.:(ذah, 6Dϔ#u sfnMuGXlÍd@뿞~h;gGK)?lÌ`-Zxk~~ $8y]?+Om\fb PkKEv釶d7 cV/v~p>(| s0OYf_Y~6ύl4ZaV kO…PH>(?waa&n(ϴBl7)çpx \]ǗáV Zf& f8uļq0Y$@v0@@u ~]x?/$et >oa `'H IaUL9?z?ff@%/2t7MFs<.dؽ/h` <+bAr֠O9 %|ǘ"Lf \~b@ShYz1rKOee';H7>%%/o< gg# 9G`V%p9fGޏ;|pM (NJ%82z4H߉5ڒm[zROI;y9qw,>r?;E4!H2Onc)a)@$&db,0|Cx zj?71d&ShۛO ;^/IĐSEY䟎)uII@JxVѿLlYN?/ c.oyAu̍77:|4se@sjjZ LJ55@ۻO~$LU*IO19CnF3ZOKG975H[߲+f^QS_Ʋ(?jw0~lfkHŀ_σb ~ w:_B'Ҁ=5ˌfuɁX?Ikamu-,%_ a&$hn%6,@Sp?7R w[lE"/~m&̺XÞ*S0`Wd^Tq` ¿Y`DOxFA5dAIjgULrTꟴ3% pM麡SW?O+ZbAV RvN OfعHfgwIy]vv"e"`L?JlP[뿼-5S.hw;tMܴRbL}Fj %3x9V+6]]8 Y2,mywZu:*?4H8)NR$؟g;~$JHCcǴ5 >41P"0i hn'M?b]7[J"s+>Nt!N___B?dY]z+W>(>_f_1k$$weYrK~ 5~Z}Y~ozn|شgS6&s66Uf45%@A5G| |ol~~Au U+xO=<^o33JdF in:|d-$*_ 1yCBF fXlrRГU%D " q ;t:OXP)Ll0 `C"Rc#8LL!G;/6ugE*l&T~L=/?eo-;]^s9|v.XW*Oƥ|.D(h+55^9V麜˵<ߦcpmYN֚~ֱtõkw1_Ǣ|Ěy".f3ܶ06n!F{6he5` ;b@j| ?pNqt-{`$?xj4IФ'5[{WY.j;[x L#Ȕ߻0a. /)`d|| mHPF0H x5u ( 1ZeN̝/ #h%,DDϱh"?."B›o›u.y>cMYT6K9Gs`5wkϱ9c'\kp :F',el~LjqO1vJ}WB/fN Ț8?J`29Y{ZaLd@eώ8kdM w2&o2 5sϒ@i.5%6uJ\ku !%Hiد+~v^qXf΀]CIm4mAU7|^5pMms-/.qk56\ DwM5djD^2@qNRz~.s)?5\vl?aA1^D.tNI__#rn =,_ⅳf}m+a@h 8j [)i HR0`88:[\ `TYBukHuC-sVR%WS~,`=55pDxSehTdIKe@9&'!e*5cAWƟZ_@RьleNKnOV x]R)(;H|oϪnym2*iF z N3U>h>)Zɀ,@_}9ks:?ў+j\{6E Kh% ͏CsЕ|d"CBX>-HT @忕$`Ce1r9(?IO뿹a&}fזX'-`s!1 dMrz#nPڪ9M(tG8vαM: oaopkDoYMnZ,u кuZhx7s:ֺACCzDF୛EWK4kjr B.MUWYEw+OHgt61k&apaWs=6mZv5]& S?Jc^O˺Wo6ˀVäOMEl4QFDfwl1۹IVU/f_VyeN?H^v%([}NVw gm>y؎UߩϪwR/"_9c&h3߅+V§O}@F֪.E4RFߥ|Mizmti|iF5Dxs*yf_?V2Wvʘ1fvͶU3O&?T . Sp g+tX74زeK`)J쿩K]̿yjSS?^6x7NVJĄ[! hP?l*F[钓KՁVSlOkGkY3G,s:k y ܡgm;@>d(7 q8b:h|Ηh P2NLp8>l7oL8Pm !y̿5̾K_;.;pْVbI^MHF DP!%D +vڅ :1 ^0~}mdٻY@oT;.q c)O]G`LOnޟ8,[$_q~Z=/5ίh"|bLt@&"1&|Q>] Zk+#몯 :P6b7J´N.6Ti~/6QVհL!|dQKcic,c{ F@4 mi UOn?pUlj˿k\Y?~r$bC)5?{a vL+pqx1tJ%}m}Zk?j'_/v@DYg7yw1🳞 K+d ֖IN<< V[[a\,>hj,s\JsG? \p5mz[OLm@&B5u` W:Z&$)8&a5/8xo89Fpܹs#GW ǒ?4!M]-wF"Ljn6y7&6`g@/;O./S[ ]޳_&P&IIO#%0_R~Ee 0z?[~ wu8ZE/(yee+Ik׸ײ2[:& VǫTHKz>mT}ަKx? v ߷VтoL=#r\5|&8S`!40.ؽbf<8րRǶ5`bg~'b%4IYLJc7cJ_1) ?h%̝WCП'fqKWS񖍷E,n̿t$jME )$TT2`U܌gm]dfq 5='$g d:f'p範G-S"is8/=m|+yAXc 9%SֹGƋ_NOjZ~_ǽu^/K.@ ̶#S/~/$QSo- ;}bч۪)*+^GsaamX>}WoAG?:xGX߃J !_j+3Hjޟ$T?cFTlYzt{#>ܪXNMלܿSR"~!?н&B_oW+~Xvn|-|ܵ=:( GÝ'pE z|Aa6z+og9/ku.u=F[7p-[m6\ۚ@/%uȑjȇS+gW+@ͭ#j1O* 8@)})'8 Ik{Rÿ@ HHqaïGD$' {ɏs/k25c?!> 4^1٦OkvK@ >Z@P) \x:' :'ʽ>wH7I<7Dw`΁V;3]]k|%JrFzʹF."nZxI\]km5DN&pjX2ZF;sS]tc 0& SC` b $ -)Lzawް''mPo3hoqr5H$ޣԏ0N \4,pZxZ>+~l2UV/K 4c{"@*h+ L`x<) 8\`iۙd␢q_g14DPCɒ[Yl ZZY*@Ax,|sw Kw t_?FE2/12 1xP nm=`֠$-JK5 ,X 9ףOQD??ƽj~U$Pѓ(N^3=/u܅jY45H s?^_oEE4XO~ݬ)=qmB$ LQ3Hx޼yڵk$ FN &(O{-\+{?-P2ONǍt<}[uzǖ,ZyeF}aY,Rۉ86|$18,8P#p D؀$Rl'˹ F)C9Ù鮺gk7wTU׻Fggkޯ..<{o68`eed9@_m+w~B;#?|D}o1(@욷_۸~c -[㍹guϳo+-g*tz[%Tz:#hǮM`W J\v7o@F4ѥ@O1x5G@Zuv䀥bÿ~xm\i84@>t~!B)5{Xh xILGT殮_L?d;Ho'f3J/\|dH9(#nY[P c??<I?єeH%5 L/=<VϽz3훶6nW;T{wUt/\4[ߧ]~4_IK/Km5@.t*7Sٿ7),*Q/C3Z3J,X s-bI#TH8۶6DpQ&"`Ru RGQWbk&p{ oP{Y >}[73yHΒb+sR_s=^7M?Ā`x]/_w^!ZuYia?b/$ZVN~o{^^7H d- !`@:^2&'猱[}2 6n8.-^y ` <+R R-,ck ؽJ:kZu0Kg\@+#=m*hַ?:T_~Y]ox  ?Z@YN2z}9I1-cQ?cX6@$t>]Xz>O /mc1ӉB(❸;o؀{ܣKE"*K9*1B1|(s ĮIIRG-XI#0Ǯ#GO*j/},795-$7#jUw.oos7%Ҁ1IV%] *?*ka%P/%w'^xF}lT?CYB])~Ug5X1bw=6_z>~09P<6'?@gC] 3љ[СGQK>|x$bԧ6 -ˉzxЏ8z{u Uv㱫W/X).2{*01[ bO?:H/099@S>ѧ)O7I%2@s~\[5>& #L/˱7/5eV:Fՠ[R[xׇ/:i'iOϧ=7U0٧Ʈt-WQWZ;YtRE2#Ktʹs JX3}Zorlםeqc ?&j7RXǯp QcŠ&X#u!cFkpF)>&G-x> (6} \ԋ P k/)p x:Q++RM)N)1!gM% T0v&O?/Ъ U֮Ȃ+mIȀ6۽VHg&s^Mk67tMاd5}LX;{O" $ww$ti\˻v]%0un6`q=",ȀM( GŒ%& fi?L<ڍD4NX0%8Ƒ;ùpr`loEemZO43j5/.) "eMx0`% H%pO9R?F Ҁu _/ n4X Ȼ_}n@E7=6I 5쌯1iMky[p[&.6/"xV .$^e QHhlpa0(?b+c=T @,**q)hKTp#' dc-r?s?7̳ k-_kt@>qR%ŜܥުoR-?֛2%7qmpO;FWaذI }W_՟T]]5R]q5 =w5dӖZJ׽fK#Gjcp0Ud6kjV轨߫3L k?&K]iLfM듩 i_TÚc8q^V=*1`:d>޼SXF3Q9@02,%n_?d?z?ċ.^[ Gþ2Ec?mR?([~i|iTZy)6If2@#k/hD_)jMd=͙5?q'%jC}o={˙J(, H$4WhM~&"\j_׃Jv:`MtT/u[/_~`1+Q";C@G300a`ж/l=jf7Y#ݠTR g i% KEܣ6I&@nj3Rݤ8Sσ@)fWe?K[.@.п8Q?ZQ>`^~m& jVའߩ2jz SIJޭƴIc`1ZkaM=hٞXCN3}5eV8v#lXUh1}X%nQ FMx(jO(?9_<9/562(ri=@f1xqAxAold2.ȶ̿fkM,FW/MCۀ]MIښߋ_NՃ~UD@Yh_}+HAtM\X{EIZ-Q Bm]Go>+sP7z_5I ˦nKk}oCsX8zwcD(=v2O^sFF9 @\(@l#pG9 ؑb˿@hwgt $P0 ;wTϥp~%` $ %`l[ֿI_o_uZ g=6'N?gݷ:M+_ B-FmRNpEVZKu޺h x쳤`1^\;o } x<Az! ޣ @(pn&Ndwro]Ŗ^ j71[yN geSg-ϵX xc|lJ4QTϥ6c\i}fh-59.5{3Q3 -0|!N|;Iqۨ0 5^:#Jc[Ɔ D'\;vL'l>HP9nO- _p;;ߖ"if3&g˿QۀJ4 0k3ns}1Of_,K+q :#\ mSWN Zh#n> RO"0pdT}^{e LXcC7嬆n8`rtha4 ō'`ۿhb9EEV2(%[~4 XfA*1w 6ϟZ"q$ӿ?-3:ZOeI%_.^M.6e߁Kj$=^H jU8M5&@2 o1`+y;@(KJ*m|#9XBc[t&3QQ2m Tn4۰aO?3-:}qVE'ԱBFr@a7_Dt+$e[&%缒,Fi$Hn_vO,_~}5f|}W9ywaz쳥F|ݧ@94~4闒ט;N_f|qP%  {qM77Mo,NpO3#ƹṑ0oWK.y36o<$6^ֿhֿ J^\6A_ a ::b=pi฾VQy \i]5FZ kglJJPߍom"d?v{_ ~c#7k5$f3#&"Hs`;~[W&Q3.i*I!ŃIהSOf2M`kYkJ9YH`5{}>I ?GL/ `cm΅.\Z8$"bur/  0 X GL OS?4?k~5'2wr,C5.[}mR0&mLK9 cޟz$Y u%(h/P6羊^Q^T3I_A}Yx߉J^^d}h8I.i3%f @ǻVБiO -A(HҶVN5?L|%&76Ǯfo.tZ퀰2$(70лP5lG352i*75K@Q&?) 68?^zeϺ_WV4\JdP(c"%}YI@z pX-:-A5Ąw3RF%0`5D/2$@KXHD>#f&x3+W;S{2ύSx@ DGOW)0e$$oJ&O29'TN^ 0^7O 6ᵱ$F,*Ȁ.u5;Q_&=TMրi-t%vϑJ褵pX{@K%«`4!H%C ϧ ȣ ˠ!`n8`꧟f|챉oL􎣷jsF=M~4,?m nܪުo&@n9jf4/KuR[&|+J)o3Րe#o3PA=5 C+WۅMfMm9-&umBZw7ZG# $m |Z/0]qO54 bl m c[@qGPiclwDۿL840Fl&f߱|KO_gxͿw鹸S2YYv_Xunܤ.7Ir(Y$q*)I07em`5OIAy&eSE^SuUOO[te \mO^IϥMطߪOfٱC܄a?O;oam1Aۜ˂ˢoGdHލ/D.N""3~߀9/]|jO׿ >\4%@oh?b@ CQnݺ;jNtm3b?Oxg6=f/H~WW MY?ψ,?O{ . |l+jݧ--PݷmOflǸ#J k;ύvxP r"E|Kt;'$}T& 9&h>p@7%-0Zdm$5'XpcfmSɤ|܇Yr2v v&M[?~nfAR70y[Av-z?g9S? 0j"Tx K~ 2|{MK$Ԓ6/ :?XaOĈ4u 2MKG=:q ?%HgԶqS3FӍf_p*K?tM0=wps w16c?JK߲fM&F4;glO K i_7诺hsWY S6&yYI^bgjnZk~ E 5 v$t qZȉ=ӽ&UdIJذ%`Dx7p@ׂOH1MDR\n9kx&77tޛCl냋7jLqIp:$_^ de%P/J0U)n#]d4xId'2e4*M}D@ 1 `*?AhLWH%}Jh,rfր3" *]ƶhJlmp@gfу 9SS=x x$>pp7ܧz^RhK$@Vu8,<@Y^Uʷ mB{5U83ϨGGJQܦty`"bo7~ |QE8$$p'䈐,n`~#l0P/>P2t*Gtg W~320T@{`ubSVODžlS2o}^>]'x 7?Ĭ=o I>-pj`Rp4f/u)#)<0W~U@]D@EMmsŚ<$@1)$^ab $>S)\q^` `X0 m QT '?S40\j<?j&d3[xyK7XU.S1j_6<<c$0#2T*o-F[E*&0NwCR}^CK(EyZB p~~gKXBr5NPn@#e=.7152f ?H!;m%\9ύ]S?Jc"`EY==b}39 x)I)`rw?{y#^VI@֔M`Au;X3uY:W | YݓhA0pWro wI&D8&VD5 XTa/pBcOO:O4胹_^FJɎџBݽHy:L/T;bMF(ق<8O&I˒gKe*voo{ٟ'7 6WA$NV}\$mK#ʽR'C 6) ,DGLra c9o#ѻ L -R@*Rh缱dS_CMGi"RB7=zж U :#ʡfgd:1@ GwepEbrI/lt_7u}VIucvݢ .H $l9H O9h,36Ѭ:AU v ?ێ K-I3E~j*K ~\=@J\lDI3)u]" F1*hW\~I7@5Fy-c<ӧq[F$ƍ}ЩЕ&5۶m/kݡD$M];w~}NXc]sB-Ф}"^^TSCLBdBmou_=HXVɲCgvID^ A5'Pjx̠zp@\=ڜ ]6m[}9G ^jw63`VoWuo @´LR$fˤϗgeήKO:yɀ6Th{ֿ  %%@Fhpa]yW@1C= 7C'1 -w:>(0 D@[*P{In"Yf;!P;F9"$y']FkZ?w?HdIIeC(MP Sibvpz_>k!&i[?|+'uZw ςjA~ ߄\ ~++'kk1,o&[{@|o! 0X@@ -F%[SaeUO@p pS8h`N^`x_*XS;H77Jt4bko3rAMR?/ eqMI{Y> j mm'c iwY*-. x{Mߧ^_M}&>&ZZ 3''LO,xCj hi %0q7Hn'i ;#K0z(=V'u ݽ;XλގlT7$ iY{)hA罋4 'c mW$;? Y< ~E (e8vӤQglTY{I(eD?pNf/|y =1c 'LDu"&+>Q/@q0 Hy#S8`ZhÉOTg| ^Bݞb}NQ%8AO 'UlQ`}'ٿYPqwfAz܃'KeOBMT]LHk+&_f}"DQj [In6Qd^hjN N:#:T?i*хx?߿~uypFfd VB&dY *^[y4 l| Lz|?m%|MǫJ&W//I%J}<.b ~`w$ 9xt NTp`$p@ [4 dgDMG> as2`Ou(G`U%L.^ M¦ L$R2Y@VߵҀi' N(7۟7aN2UICޡ3$@/? ) {%Po[%S@1 Wi>*aG$?:S@dKW.NrԚ;r:n{tT:W 99jp$ NA )h y?\z]U./mYtٟsKϩC&Uwl(o;wzʖw& 3I-Q1ٲUybGt7Fb:*uq74к5U@8#ʇF? 6Gn/pt2+jeN/j^uIni{p)<( MNI"@Y2YA\ EAiA25G Keyȁ"N) pX>B륉\}8 ; ր!Te5*I:r2$ * '?R*Nv q{_ZO 3[&?pD\]Vm'LuXEY@ yMՀ-x4iWP1Rt)O{oATI JWS83RVWW}[4Oeڠ^ ߊy gԭ+YoV\M@?)@GMAKR'V de:t]}m5^45LߦMlh1 p?=$fi;؈})`ZC $ψFW Эx  jpETh+65n  Ӎn\HCPRL9JëV[T%/evP9` ࿉RUex Y k?LmT&2IM<@HAe/wNyK0LL~R;`E &\1*PR.6΄ `#(b5ThC@cE;D?.9/U;lO97IM\)q_hKfX7Ik(5Y o Gze)) % &$9FZ@ݺroG,3Y:&M ῢJ xKeEw }sWI!ܠvv[u_$_eVn_@n:}x~ߦZkKՓ'5iļf )B@a(F9xT=!LdIS~JS0(#(tq˖-c_1d4|1pr=Jl,,ЃgMl? LRm?Xhߥ*YLp^G /Z߶Z2>G/mfE$@Šuo]$wfi+J*[@\XDd0 oRd*+zT,6bw*GT4C6 $* |dXۋ+3d=%lbݘ1]T.?{{nuYpYKuR{S`3eLxK-ω.|R0qeݵݵ/ygd`^fƿ 0_wYΒ,f IS4?1 @2N NA!Zq?JcT:DiQ 8S8's?>)#?)OG `Vy?w;Q`XelR|$Kߴ".쾔eHk(I0MR^1Puֿi? xl ӿG~̃ xm7kKI`Au?BKqJRAU f{h):pU%n{P/9JC̅pq4Jv"^X#B58I#ʄo \'?$`݋[U٥+n0Jl,M7JXRۀ,|R˿puʍQ,Yzb/I;kݿi?I.E{UA?+(,o ;?>Yiٿo"_ <6$7{k{@7DH%&E!=%}bcW$hû#~T$Re%㜥Kթ9L?*$WcB5 *\_"1? 0^ǯ?~dh?ceYe?h^z8XosOZK!Sf!^ysUVm"X@LP$b " xd2 <`=le?~>iLlāM`"!fe3ր[ͫ,V t'~u=ްdB@K A(ÉFqK ?fz&vRϜzש_3N*Z;cZM %=Ci%Aхj`JlԶGlgul~ p_Vֿ ^o 羍|uMYS?RVl״ȁj} gggUx`ڗ'@ 3$Y!DEGJ $iT\ apd# cxpӦMщHZT?|uBIS )uo~W7-ߤz^R3V~y>y (/*  ei7g6;rR(R"u]+$JRAXD X& T RnŸ&@O%w XHc+ &Lt?zěl 79HXX`tҲ?p}eW>jԸ߯qq #~Y-Tڕk} 2/ @fm7|<#VT=*jF P4_ 0)PZyP;ԷzP!$'Һ Ipsˌ}xP\)@G/jӶmۢ*{D2`巬^TF Jp}H'uH\h:}UUV^ #+KY>4,'6MM1V?zz$UEy&<x#ՏJ[/ߤ81e IXӎH*@7S? `0ۗ.!^b*H2#28韣RI2/>'%?u}k$u>d`󂙁lEq#GEtn"*Y{cG$&(N'\_8~+e&{`yݧoZ=V]U:*9>N}[ߚSG#_U>蘮W?3)d'J}Y=i8s8_%o'S 20{}d0o<䷥? h=oY`c%s:Μړ+ ;x.9 6\N~4GruwjX OwPMV1@TuF(}J}%hT#@J 'Jd]6MĂiސ.8s_R/.s0`ReUm22y4m1}A~Yo쫂ܯ$|ޏ⦀D"y;awrS06 J.7&BUJ%_ۿmy }yzH:8IT YIa?:/S%T8t⮉?Y+Jg&:Uq!jG{yp jxvVg_?}R_/v7 gMx ϳ3Sv.d,7syGӂ;k#@OIh 8$n.;(7s ; XN =J;U:HFO)G@U+{,c pyso]ǶiI93KaeәU_T 87Et#gDt2mo{&<͏  Kym%rȁ7͉iE''khCNQS8e떯 TcsmH#$J?4Dh_8ݧ{T-Zk6PyUp-Y"nӘ~LK@߁1A&Vp L40}&Yg_8Wy$@ w߯^_OK@^KH] }|4 P:uy1̡D˽#6p\$?4KuytQm >{H %1: 1 2JuR~O|SQӿ2|ߡ,x+I o ^o< Vס mjU- p&SOdIuZB·6ȁ oQ.㢙ܘBnܜ9  /3@RMUfn$#VXb7U@ '+i1*1Ў3fDP%{&cvVgV*@Z9I -t4x+H}4oЛ M T`KGfUf%gY[3Y70.7Ѝj(} ANˏ1oJIvJ%=t*7 {OMIuvjn$#RDGL>/P7]~="+6g.r A{t=kty]EĈsV]b%?+Ǒ<]J*LLW^c$ _U_?)P/Co4X$<X=},h@1~܂z/LԈ ANm\0RN6<:@s0Ի!`H`b3t@a*pBF V?`NeZk1Jj?}}ӿ"KW]_7O789EhUc6ezm/\=>ty% l4\Uϩр ?^UAn?a$P j\DWmN[40XiuP `64D3@hhl @n|DSsϽ;_d/ Q'9jqskiܩ7%?:B'Pr..:A󤼈po^ཪSomz#WtIoJ P9&&M-3_` 8[%FF MJOrD5RIu%.mƽ3-`)0T&P[Ҫ#jǍ"?WoH|ƄI5" ӫ艎e%KiKR=.:miꀼlyky9Xg] I#  I<}C\Zy @Hfܐ.t An96*}{JxlcTGn$ dF~#yJ1۸qch.b:1ed*KyT[Gɳ1]}(u&Tnub?qW3wd@Ӓ4*$Myh4m~e/%Uⅻ `_ 0]$@S1 d7 r|?/?#A͵P@!`;rf =|Sd#;8A)mB: ?L ZWkԚ5[tO0. ޖ1&utp "ӮC:fIQ! ϩw>/V &X7Hg<LH2]-n,T^)#[Q5I#0tS,4?7#zuiW/n*ĀqLCyHW'׫2#@G$ȢӤTEd|Y+Y} $ a0@jbTr&ȝ$5.9 -~ `+Xr- 0Ӊh3tb ?xR ENq3M'γViń={RAn.ۃ*>g᫐W?O@Q`cS* _ מT(?x Iŏ)em%L|Eƥƒ4-@s37|W]a%ixKR ?v+2X0͗$3Elp-2c-S9 +ׯܖpO`GyAQ/+i|t?7@7}JYYY7po zMYp_\D,f_ӛgNs" N0_'}xZ=}Ly@N.H*vpP &.>F w2@scqPOT~40fΙ.8 )T;N_eh??yR6{6 i):k'kAqJ}\e@u?mU9UKo[}U$x/L?+YP䐌 i_ϩOxϜ1~;~]N# / ANUеX.\{ ME-t$``93E!$?*QLQt;m .HѦѵdca$.Pd nv w-UJQ~K+ 蚪uF6xu2oVo_ipH&E$O-},G"kVԙ}Anjt*TnTR lZ޵GO"5oA'9`qN;Q Q46*S'h\;Կ Qa'ዹc)ì7sS]=Z[]_:EE@8+"MӦYWXҠ*r:W%o+෍h0>:9*Vu#yn[$O#]' +M 5.n*S6Cމm h@A+7Ni,r¶Pe!fI¹DepE#u7ߑzaϟƃس!kL%yM<8gbCIĘ-\B'.E]9xϒU7\﯃H M9bG8=mt79vo; `ԿF> 3 1ď1=դ/ 9E_I?? $猀ylhzlpHPYU;n)EU*C\4M(2Pʙtk!JUa3-8"|J%O܎swP3@,vbܼysp?ΩEhXHu?0HDJ2ˇwhiKE х꿐8Q]<8J_i[E6/"߿.x<I&F@Io) >QуyM {kA%@ʨf\ ssv^cp` zb-b7F"#ǹO #:(-xd}-s?&ŽrTaF/Uu,n_0,q_N ng6T_̀_?b?sߖ624X;>?Z|Gp/=O rTpD;{o?} 8 UQwZ~/)pP3 c'|o].>c[Z[xY0ћƛRT ':A iA}u6Y>K>U<'_JBT9&#*[ljXVw? Kf:c#ρ+TzB@?ޘ0 a5;X 80U &*oPD4Q@`*?# #RJpRzx2-.#UPmpW?o_[?Bn6o?./$ 7 X8b*U6릈jx{Y=p ׈}5@{9'RtطS@ 3@ߣF0 =#T]˷h />?$ MRy|#gDn>E;_~yY*y UiNzI$)@c>A)\`ρ{БzO⦀s08?-P  `QSHAP&$Ճ}Ecl}|ۚ얛ToܚOR\i\Gr/"G@[uK&Q7PO@Y /9bq"1//xy&*~ISm}ׇ>o䙀$ҢF>kB ` s#!fngCGq4K`fPB,L (GC" ]#2Jp2̶ tn ]4F2W/8tQB5+t`,jZ@o46д*E*(XUeHY@OO##ϑԞ(U옿V*HŔLZڅHu [(}0Yoo`5Bܑ M[#.=Wc%_nG"}~I'HMd[D|ј4Kf}w\=`!`CJx-bnI:6g2Z2R H X%~n1#@o0m QN#'![?D} '϶p* $7A@#gU"%Sɛn_Z㿢VY=7y]^{Z@ք"cTp;Jwh5$m@q۔lǧ,zyPNHҡ>ONsnX΍"ZLi?k=_Œ舀4OLl .:/C 8"OJ4P PmP)Fׇ>4EiJE4F  A 0 6 `mX^6yWh\1C"Y%BJ(GX{\.v&%e5"'oߧly,ۺu P/3v`߫Gf~P_HIS9WjYYg|B"C?^NRi+y'ۇh? O0Zۦіhpm PP?u'0^SQI2x]dnܨ67fVR M-TM2Ж?")a߬dǫ$ʐM:7I8yC݇ԊT<אHU +khC%'t*ω"J%m0ڙa@No#m>mrm+`V?D?t tm۪+ihnS&1yR SpYEsg?V#'OD~Y&Yu~F U}{C=X"*~+*@SSgZ~nc1VVs~ӉNO[q"̳`;`(_ J/.Je+><.GV:EW/:8Y}?sΪPf,I]?/ ˀY_kɪ~zkmRUԩΩDsjQЙ#K9~0W}:>\/ah >@1O(߬=I쨤\OZtQt?Z7<˴ 8Ks0#@,W3'9ﳑh$Pa|96'MI]1$M@"r6@r;{̎]2mq9gMPssAӓ!8 ۍ7$u뼨O!cQ$/ͨtaE  L"ߧ^WPQHG@Scu L*l@2R!p5Eȁ* Ā1~8ZS/}\,fHE^׍35O_>*G ~~.4~6h['X m@"̣`Z{G'G"XfN%ZfJrEg=fvDCNtu"p,/=$Phv߅ı'_klk 0*H@qaF/g;rW_R2&Y3}AJz?.U6T͍ FUaD vfKܶ QOnD0g~&+"%$,G.6ng3E6MN~>OWrm9m>6M4!mi?:J"l ط n yҟV% p lfrnkp X+`8R_8M7\i( ,PN^/M&\ *R?F^s@kG#jTelF H?k&eMKP] S{@~^0_ϯ`~;O ]>12T~É4+XvSLG Q 8b@oZO?rx#vEωN)dD6]1rgSN ƒtyb 6xtGjp R?|.&v $/M= tR:&J/cdysJH-5'/ܦ#y{.U~ͩxݕ۬}h.roAO7ifP> #P+a;R:%EiH1륣K qp]uzn1Ō>Sv@,`w\{ >aPf2@UUY?O$)CEٗxpAdމ|G*螣kU r9AZ 9[#tך8nEh@XX`i;j@:6c @A'E7wjb'#݅Ú/|_/Vx_X1t``?F[CH.o:|5=fyY`R>$@ Qw ދ5,7WEL\ r;Qqd) $guʽӍFmV͛7#=EACx`:`u}ud QJ ]g_e~vLN֪7b%1ԺM}I(wasL,+/1UFy۬ (C>?x %i$)k9v @B,'t99kM3`:b@pE): @h޶ `Z@-[L?:|ۻ#d⅓mv#c)LTJ^J7 ixlЯ `?o.ڛ^^U^D"M8>>F<~L|$ t;vPa_{Mj}gwGc?€qsGE :5bܮ_ާ:RwV]ٕn>rg{B"V|tn[ljC;/nMW˺LTM9b c_2J?+5 f}>{X^$DR~D/im(ǟo$/T@4)H@qS@r)o,SLEb 5~a`\l-p`~~p`G /NaDžz2p/-[գ4"[Σc?л-nM*)فwVPAR?.Fu\""(ːF'tLTYMuMwOL@1.\B; M+eժ*I: J*{,<>[F dlk{ K䎒Yk3ϗ O6vgن5_qs[gGo]ޕz{B/n^gsB'XNnߤ+ HdP3OPSkB/%խ~gف.H^z=eSD&@UW]EMW;_UwEE딚R&|憘7ml܏ML3q>󄋍D?[Gy6' ̼;vT}f&EdʹF2,/@b1y W^t߅ z%7ů٦}f}mUI6NPߔ`lf]hjD7PD=Od~ ҉N` Tr{8ܸq'qh2Й+?ؠdj6$}IjŸ b1vx4E(kcmfZow1ʌ}oۧv\C=W=ډE߁m<5uSloXRM?LKvQ_"r?Q2>fn m.&머X)n U>3>'P+TVi @ޮT`6\$7Wsv\/Ϛ?+9He?N {_5qPP?P:%u;`Ec=wh:#8g?Olp/K2ٿ_w(ק|:?y>|Bdmr)y4& q`B8@6΋^eCH1p%`Kd_`@O>қh]99ź:mM\4fJ,n?bpy3 | (ǎSNR'OTK/-IcmLas.~#{*hC|D0oX~_%௒0OZIB*0‰[z#$㯁rߌrH`O]gwC΃."1?l_~B *I,iPЈA@?޸;|vL>1O%]]4]BN zunaJ3uy@UMسYKˍ)XYLA?# -wQs?UdCQ4hn`&O}`>n `A4r@?l@:N6h&/rWU ۳'J}iicʚ-np^_ ksMя~A3>;:{=_=x߃_}#IWwO|Uz]XIpkz?oUUsM4 0ET4;^ =e&CEIMy 1==ɜ8J= ~6DhvJ^owﭑ>8L3g:VW*Q oݺu@۰μEC~;W^][i@'HOqugӀ e6#uV}Oˡwݐ zXu;~`Zo<_K}mR,Z$eh_T c1u{$r$/ki$%3-KUEF 3byh\ ;1xEoG@3?qp ! "T^B&Emmc4qI1pߑ[D8In2=}Eح{Xk.ugu o|Cik=~E=E//|[ޫ~C^z#\E@R)e̿Jj_7h7MPE6\KzyH@Lc005<䂉k!{ܻM!d UÝ`:D@5@V?-H?diu5"0!'D:Kh0 X>؞Xx"˜6_+9a >Y@΄Mຉf9V;vP i %qTWڷ%K.[-Emyp&9$C?$&$C$ 9I d#dB&b!U2ލ-/-^WKUiuUuuIU{w++i?j0},@͛7êy;c-ٿ؈&m~<t}=r]$WAvUT|yH;;ffkQ_@P]'Z7 5X;@F2`t __WW.Ëf:w ï;z$o7e^&`w2G?>̘1#3f͚E;lڴjdmc< |$yHmw/WO' P2W锟Mv2NO|[ />aOħԦAj֮% D.0<Ӆà1D|$ɷ{`%Ou+?ccsmSL⒛@`-ci$>nZ/[5,Lu`ى͝;̙CC^-A/8_zG6p-y9Wmn|&  )wdKB@Aϡ?cOc5eZL?%{)NZVN*jmpSx@&257tǧۂɸak: H 4`K&818 t`_v,'Ж+W {>xj9B=Yt+(!Ύ {7V~b%|p)k+(sLK s $ @}&?TP`H#LNIa>aJUCXصͦU;b??`q Y )cxz)H-$ 2? IqRe 'Ћ&ī"$/`繐$  zhĤ$@OOmH24zխ k{\lG {#aiˈ~DgMR>~[ۤTR)"!`e @eжj{/6%Vl X:[AX Hi#")dKH&Hʵ<Z3|qݷ%&o7Ɉ̴X.?[`П|v @e˖=z^|E6A{`%k Oӌ?n )m_3n~8~~8W4N3E8Ntvʴo2.22 T[4` ? s_VR>t ȵ=j[ueH%_/x}vvuhtn/@&A*dŋ˗( w^JzЦP-ˤd]SC<8|}wR_ 5+~VOsۜJF"#{zOBPJ& 1kL{|@pהb@#f, :r S 3 ]Ƨ\z 65&Xxqܻ%-_ϊ\?߮'l~jAq-Z돺6pzt'MӚ\}޾[ }2ؾ/jNnG3n|.`O| ISM0nS-z!H#~_sʠ}7$! Oz 4W5CNU5 C 1KMLS]5%̀+6eV)!%`6z"ł#XGG#LZk?)c7ṶFb FC. ?>oY.bx2xN[p}';q([c@l lܹ.$p|q#w‚MO3 ㆶ@lá ~>Id U" ܁@^,}>x-eW/Fr1?|o«_ ]5k:)}D2A&mP<57:@!xcHt A1Ղ,5CPdipt6~x:dd#p. ۥ;Ez~&@X .S l촽6p}}V[Fஇm}D@m2Z/Ы\I|NU8nw Z+_:2>/{ //+g[.޷}ZۚtqMu5⠃*`YK@So6F`;I.tӧ'0(@Q; a^rra1|/p6,e7~7AY\//N${76,{ fmxi :g~z"p׮]3L4m6 2pbJg\;?{{p? w]mۉ‰쁈b[A[sq2׵鎟XqwHE/%GRf#i&xe+.Jp7T5_+XݾK:=WSşRJMC6A`7`c. @?r/drԩf86dDZu(M)?h0`<_ UDˢ 4'ښ#:Y{?'+}20%om;6g](i L4 'p =/oħS;/Ú/0;Y%<w:qAKO6D@6ْ쓏>$H>9- ۰1 O=WƮL>ο ^W CcCtηR1qx;UAQ 3amF{bQE<%UE Z2?XҤ<.|d@Q!]_L8~0 3ei, q v >d-.F viM_N E(p[?.'@W 5۰=ŋ:"b ؼy3= D%@yy4Iɍ=~_+|JK-F3}7D@>^7 ]o,??G2wy]/S!n0`%piץzj(2_סWz!d2!ˠWW;Ö[ &2fc;%B}E='Cٳg)gav/V| ֎SB:tA&Lu^@~Z4f+:m4p%K4H84 J;Oo|ww,:0E)ܔ4 8{m__ k9@B6pnعs' He`ǎ?$:3,~fbg/ LJ3=}{_}7]7-zіa?jGg @[r@EɚD"Y)M_Vxg;ayr gw"<yE3 ױt;O 8il._ >bB -  =c:qFM۱ jL1U)2@g ٷeBFH y&NM-vw Z`ٳK믿N,3djiO^I@V'^z] 7^u#|گAuysemw@"PA U W&Á.k[Ww\:ej"UW1Y\~²:\p=mǓ e%en]SwI@ u'~}gPYyݯO}6'6%V?ۈ6%X|JZOU1@~s2%˅w+=|ق Ӊ(?+`Yl?#"JT|e NZy$ S/ f`?EoO .^k]a`u3$aNA@y2`J,@IlB0@Ehn= +1  ԋvb:,/p+ OlA{eȄ|㵴Pgd߾}qimm~4|-5J}|?>;s<6p n&t7\B=ismGG¦lu-WLeKrjP=_ 9 4,؝vĹ=y*17z8=Lk}1@Ҷi]$`y:|(Fm`4%BnaH&0js&J  `'H:zL [!FR׌ND[0q96-2 U`En׊93ĴtD [%@WYOR#sC,@߾};u|:C>"w,\jxxﵜz_ojCF=iKkz|bLR?mAiV+~?(W6,@4kȲ,eɛ1C4h3ϥ,q;vijj$:+`BXFwp.}+@}ȓE'V@Hce!8Z]`"BL3H&I B,*Kx-ghbyCkC. \w mz|Ͼlkslǧ>&. tEEMl]&`Q YeMpB!ӧi@u8Jxar|n-Mc6[nA~:w s^~| ^*d_.߇v,-nTM&a1e n8=%,༈0L#,;}>,S3R} O5Nd) fOd@BA4^pʕƦM (@: Gmri`lu`Zm5{K:;LHI:`0b===&I6H$!ϥs.m8䚉vv,|_^'m)GO"2%T?S0RVWC}OD:?K?wa|Ӏ$΄L=\4x\0~Z)Ju쌃q;DZѺ~9 "Ǻ^E }ȗSŀT\O5^1׋TO$KJG [ۀ3!@r i K3ÛR$F$-xӈ%Y@@Y @vcAYrɺȲث]Sg f*42;Љ$@WX[l鏌LRx"H.ۯ-\~_7tc=y8>nLB0?$נ]ճ V턉(?. f[5Y*&6s[gL F/ ‚I!#k-E}* 1ϗ6$p~m$v|3CRqx#rZP˹I Xج%}M`5 F@6i ScIlgIG'.b e+f(&?vxt);@\ MU2T&ҝ/F8-ZD1m'ON+L0-_ a42}_6Sp5BeY7g X^lI/ K,Ce `)Fo3l?.6/x)3K~~nDP%qՉ}[;?g|&@/t @-YKwrf~1&N0\&[E PU &z iBj<S>Ӂph_d^%[;ztE ؾOq|ߎ0p 2 9o w~~ɒ%T#ȑ# 9@j} _'} }ǵm2y6`?g PAO",|* ^ gcFuYy;b~s Ű\Jc%L1&c":}* xJgKg~$$_E?D?~! }IJeZڂ q{ RiDOÑ\G!@2Ģ$ `Bd.K(gbzP%R!nph@Zx/xۭf2Q>x>ZY;?@.AA&d1o<?|0}:HOD,M O47 7Pб/<~|7߅{nVuכWOIK?_k { m;34~C\ k5x/S,kDz6~Q=u,ܸp_Vϋ1 >,/αKn$?)v' 4!z;ɂ`%ň%('4 &M- X` &()4[AHh[s2o&٩g ]&SBCEEkii$}&ȯvJ`@tj`j̪Jh&/j 3כh_eL7A.@6ӏT|^E(~f}!]Z?oXVM%$_CgcU.0м:u 8FRZL3 _1|Qπ9#1SqAa?VϢ/%|?_϶DG_}`1 :Q6^KĈђXhD(x!@t-g)c"nJ`@W`m͕`_6Ɍ~MRFׄFP̙3) k.`c|}Dm$uG~ n;->?OgP\TDz7gKx UZ**gB6xyѹ@~0c>o& =#ZVXS(?5p CFi̇b@# fb{gɺ>#@7r]D"H6sm쬍 t6{4KmQy Qկ^nJ;x =% x-ܖ4'.CK /_oy擨(?oXpB8 v@%"xߢAJ9>_kkqxS@ g 3g 5_,1 &"?aL'B_f})f3i0mx aϙ=Ii.F1?qH?n,D[X,Xvvv`n)7WlN磊e!=d& N-<`s6J *O]0k@'_]{c|zM+?7d@>mt}l3 "_̈D}}=8ϱH>~}#1u_$wSJ}JC<51Dc`ya\;@leV?F\ 2=:$m :h@dl Ǿ蟉{]VG#;?WÉBjdb>>J%@_i=1o[ D.#kP2& 3tpBšnJ# g_ USGHcۨ'/>}gᖏS+7,)//5$ 1Ut>!Ŷa (@_NJ Varyf&8 #0 `?Rױ~ ċ~|,͢S9'tJb%Է/O7x}*|j fgrXL:1B@{ foܸQN.K ')̔~EN\,&m?" &葮vڳIC6Iؕ@M n*'WA[@!A/ 1`֭T탙d(RKy8#aϞˮm' pp}z, URWA [5~U?J(whc&NtuÒ%| Q_HHڹ,C@=?>XJp.be~>̷k:Q@ 戾e`J,[UDg%HXްd,je+M)E tuB Ѻhe8^H3 o K.2 d&sc&7 ~+B(( x ~ҥ43ѣttD`NnupLgw5G wt7<=8{fKuـO?2rL ~ 㲋,c}1ʏ~i"ChZ]C]4,Uto,_DCR?c~|@mv>p*ϢoI{@ԨX\͘/G8>md hrZsI P^%|QupDsed :d%eMMC&g=>$r)?|+ zACM 6!uLE H BN|Q @IoQǺ~G4a9IJɏ̘] #KG~?+FDP=Q_lV}K(-&3TXϐcp[D`e3@Ns&pkbZ 2,0n 5V7(GX!|bdb;,Z50Br>~In9 ?Y`_mMSk+%Oϙ3)hf55vZx`pAowr?Z#~ _kpU7궁f)!TQ/@_=ddArsi^ :19φX`.5 V{ڙ/Ãq^Sb)؝>+t_T)Ȣ2?-cS6>F1cY#|S!@2NPNJ|&,pAZ `/`zHc@lJ.K9&zpcF~69c>##Hĸ`iA!') @ss3}A' KM- ,x~N9c?n ~XOӑ! U?s?~ٛm~81Gzw¢Pc$~1ڏ$ұ *ˀH_iɩ@98e{n9д npuuB̈˭Nbi ւ7)_:0Y h@4bDLA\d4*>־͎}2./N$vjҵMt=oc2d%Nb9$lB 1]ff1|pa/r=z_|\yѕu0qg<CCP=-3J!! =?sh6F ݓDZ,>i_‚!5_qz^4~&7Ɵ/'_-O>ݩ?! \N,EA$mV\ilڴIY:HKE6U Eˣ3R6j<dILh\}?~vlg(l"؟L+H28b 8C v6 Dw.*>۹>G/>W QAKQg @eڭ(V<7ӾA v7,miIsTCoQ+$_ʛhzg~,.Hե39f>vd:N|=\0 x%v"8svgf<7"H JL&:aКT֔!41@L` kӐi#RiG=(&yhCp!1>#q]vv_6ȋb'6'BA\0EɸJ0wwwSҿe[Z%h厍m?OOzTG?;#zJ=<}Ì8uא&%X KBkQ+4?z84|]?oR1_c. ܻ!NǷL1#Dx$0&b*`N0||@8>{~)Öau08 E hR8 ?>4d;)6NQ`8# zC̆id鷫wvB4ـ/cU&0ʏXuka&֭[a``'#Fg.)?Ѱo{|<zTA>, P.^+|0Y3 1ڏQy`Q"S4]'#є(?wxBA=~aEFL㗭+eN<D"  Q_O~HR>mpvgh#!Z83I 3͓tV9LY ժAdf蘭]/Hi˧Rq.7_N-l@d4ZOuC'0ɓ'Kcǎ}X&PΛ6>cl?־k-|s7^چ2逾"$@@Z}+}<;l~\0?+TDl-O#}jڋ)_<EǤs}J 1şl|* 3܀l;헍X)02=e: Ґ7Y{;,Dsb'BP)Nt`B'B -N|@eNMᦌe)`v8ϥ_}dG-ZD3< P$) G o}pb䄯>v/j}>OCQoFL׫FT3AcZp~Yi. ,(%?8ltBЏ Feu鯩)|NMG훋O"lUmY=* ;RLiN`ƍ)1]kH/s"23"m2vµk7Nz{6e4}eH.-L)68p;w.%0;N$;&$Nki&o~g{n?}6ҕ1G . J+먾Y"&">y2J K),rC#1r㶠~Y#8#2.z~qj`+Y?/T\yLM I%SLJHyNfԮVerr%@|j$V-MT iTCY 5`v۝4dir :rL:wY{, @g L6eepkW;O 伷}2-W8!$n>@vDs!rᅒb(1)CD@"'#1j&"qr)]g̘A XZ뗏yݮs)fuNvF.F2mEŦƦGK%yNVfW)RR% XpLGp!rg$몬Ʊƌ&tlSM!Oh/dEL߹s'M5Ũ(t.P1|C得;0l2=zhIn|.`ɡWۯ\z@v&v[ː:^Y1Ѻ#S:)7멏1? jcepe\t2keDtL"x*~Q5erg6 Zeʜ/  dw#NpґPq>v! ~*AF裓M s&!b=o W.J`㾍hxoL ;C!=zdO -؇[~բ~){/n@S̵)1(/-N sS?z5].;ϥ;ɔ6K^珇>gOyϹ{|T;ǧK,RL:(BI :{dӤj\5s|+@CipnX K1K7A.0REIMj;pok{%?{%WUg;CIH:iF(?(22 "` ꈎ# 3?0k^Q"N(΃tBy#t:IwW=S9ꪺUVݪsoj,;>Oc=dYf:%%T YEgY1Yh ?F'NԞ߃-ca?7$C}d)UUId4:I>O+% L'#, i3l @mr+@LK}"i@\l$A 3lKر0E%p#M0E!@_"#G-۷LQ ǎ`)mPY\IFF} oznn[.eſ@}u_`B:"^O=l)?emЏA=@E5aS7,φp S?AHk>~Hd&YH!eIUl@(j(#)vR6i>c7aaz %`Z[`hhHVv;Ѓl> A'ZS.0PQ+;.NtX"j(;@^ u$Ot$t1,pBرc햖ضm[\El&R; Pao.&|㟇P0dqk:l>mϕ!&}qJ^}@ T`鰤j ,(YŁbk*O=ߞIۏ$m&7Q~v|KeO.UvnEvIHXԇnL$BlOI$9KJŭh̉"d 9%ۓB'K?9 vz1ɍ36/07E ,E@U,Mm] =~*jjjN%X#[8p b@,Hmzt&pզU7;w |x͜;ev*/]E3 өC z 1ҏQ/"&LuKaaB(+>ʈ?ίZ=gFsZwwe|~ _5BT)R} &RF9O0' T^k'fCl @ 2-OoC,-J \OۚD$Pj)  @s!j={6qDO͛G"Nv:X|jeb :ޥoi#pՇYf`8 89Ȼ@d32E0Ȼ6ا9pY h Pq }<9Vü|o{:"Ão KPU*P oG'®]g#@/\CV[Iz=DI9Qnbg:hgaǍz`i @) tTEI TÂ̠ҋ3<4&N\E̮ŧ^NH3k6}8d̙d6fm 7s[Gwj[^ ꛯ—2çJu{׹s]?TwP~c.)œC[u4\^h?VG/c>ʳ{82M'T 7^hJmӉߢuF 96q*|09AH(((~&ә,$OLS k<+sҺA?r<aF Xָ ϵ~{?۞cn?K>#+(Rk|;t t_="DTʤ+T%c2:a2T qc" [sa\ 5ƪl=TEFȢ&K5}: t\$ r5 YlKE mph@$XgCuI5ݱVShKo^ ^q+|oB]USVvLtL n =[ pnZj9AOWGA?{ ټxC >$d$ȟ{ {'ŧЗ=T|H YaC@ӎ%faI :r]VvDblf2$/m HE.igb,{$h8* # J0*tEl 2" JAJv`׻s UUa4WH4xuo1mm[g" 3I"d[o}c#![I K| dϣ'xٿ,DacI׭+** k:RJ``klc)-q&WcQzQ{U@B@?+ jw @3Ɇ5vkk+lݺ>LJA[аk k  Εp z7p݂}y 3%/0b=X%%4 >t#ňK2"_ddMW6;E.~ num7^G' n2`ǎ' E  6fij*?ٯo{}Cw;ޭ߃f?5r6%Ix11 m(p aV֟2?nA?>,Pe%V0qxaIvZP俹}ZQ2_tdLe+jGˢu t{[ݮxx?>v.ic Dk4a0cD`D@Z.om+MOC`o'kCiqiA=kY?).AZܟ༩AKCK[c A?|l u<~g7Q~^KسudnUhKb[wA?|% X\$@Ng? bݚ ӂ>12iJtM^&ʕR: BE¢feĂl-Vn 8MkAcIf"$ mZ%zjշK6tjï?Q0J9;Of@T(?gqVUBKc ?|(+*;s(\D@|{>*#o8Idy\U7ByA=<|EA`l= MI!@qCWd|EAEr?!GꔇXIZ@G+ߩp#ZH\$ A`ed{˖-$:רV.O7^2k:{:opqxn: 8 ̧Jdu(ϣ {@Y;, i@cE$061@F6b>?S+/t csq %K3UakJh*;J8񢄂ް:MGkGȠbd2G~Nyes+E(044D٨no΍V]%1n&Vng] X}'$ ~@<}XS3V#U<(r T) `A." J'NVXmmm8 Jv=%R䯉|C4&υ 3֐姃ʴ x@i@?|EJ22V E2 `D'](j"5<|ig_O7  λ5oc:@GG;vlc:֭[ȑ#d`EAeQ%xXnh6|µ_ z?Lkca9F°snC 3Y??ή >"!/D%|{>4VϷLd pqz:~# +X|1GAan v EmQDeVP68 7nhp$eQXv^/R0ZsdE@^lQHHƯ*R|*lSt+B2t,Xv"^pH twwǝrͪ7.VmZrbJ+~3w_}7丹xRt!z6= ?sń /i\%`xE_[#&!Fixowc < s8C-L97H$,W*wmF_@ $]0Ej!fقk.NJ$p.J8f:GEީH B퇻sEϟO{90O/M, 0bv!83p^} ƒ|<|ly` 5vy*g8T ͓uJ+̨4/cc>V񯩩qM6b?T> /;wD>U蓞HkEMߢЊ`6 2 `Q-BQE %-A'b UֳA%Ȕu08 yΪǪ!R, ;ԍ0$A̙3#IgϞMo6.$ ~[@T؏3 [[@MCgS6&G$W$-H J  s@$Rsc>-*xs-(sXԭ0w…}vGo%p| sooƶ0*wߩ>WC`Ҍu쟏K%mcQH0E_ cX-:+tIHU{z/k;|T~BQ }$R |HxZhI7[cؒ >3jj)Im*׹%6GqV`;,@@HIM7髱ęVQdxt/|&z4$Av ̈́"6B I;,gUU!*i#|}O{߻;ςtONG)?RsMi 6Z-PWVyΥ~Q|#"pq u#$UV~nZHK%Xi/`ן k,RJeC')8Y Ma{ w+1& DITY獟Sj5c5[8)t[$?! c輣G%͛C`6 zj85v*';:62{஫p)AJk@I z";f'\V?,ٵ=ϋ2?GuBIT$}t').Z@毹--z6Rغ:a3"Q\::۟˙ `Gi`9cWu D;&`{;G8L3]u&ow3X 9rl/Y}]< ė.7= G|᩵OC_xz_=0~z|JuT}_,g [!_^݉l6 ㉈?'L7蓢o*LC؃ d@r%9@q&1HM p0u܏ToܸQàS i:ѳ| _J.Nfk;r/.oϘV[phP)vx;j*RCyS$ P?@>|\/E(]%h@@}RMÃ/,bq?ɘĊc,֤$0,%`+O< si( w$7W!q@w\+w#ߒ='e 6$ܳYf`Ϟ=d{Μ9@u.p؊+Ǜ {c ol;?q'|CuyuVk:׉(HG8V}czCV;a*iii\϶suMM /d9UL9u|No@Ⱥ[[CllP8}̧jw-]0Vϓ$(VI NsqG[u8Ɋcvrw岜2}^])SiӦm,)4)ʊຖŭ/¶r=@j| ސs3 wC`&X:OkԪ$ҏ6ePVϟHxc%nS !R E~(*DoE&wIq XزbO*G9 l OPc[baM_bsKs/hA/!d)D}91*b 4$1_, .$I _ܬhՋ;!/Co_/xa+ ߟsp IP*%1f8؀qYâK}*&y~J-c>xQ?-dp/kq:K*_NDQ/GP=Z-AiN)1GetFU$[J'@BZ?IiI Q%aYioՑj!rx x1~|hhu[;`1@l`&j\^62.v7}a\n&MNcsh7~*|B0~xN?P?۞չZws ׽lu`RG}f$Q1IO26>SKS pEExM7B%êK88(y RpzgLm.H-)}M¹-;wu"?ţ:XfL}5/&\#p`ppUg~a5Ec~ߏ^z%g_ik Vt {۠DXH@?iYTyNTI1i<}ohh J$rk^=>'Я1(5_hM1Bl FCHmi7Kv4DaV'޳R z6Z=ZN:&pHٸhtEEߗF0&_](- 6 t,͛5Um[&Ys[HCO|c<$Hw}U!@eK'5~S*x~J}*QR_I^Mr~\D*`/d4(->߸# U_{}fxO&@ Ёt!+O+',, Ά0V=V1ƞQw`HNaU} 85,,\V0€G%K,!$P%K]w6,o]O? #}2/<Ks~NtVo(+ %x `A? _!GҍJ|,)$ s?eEAU~"*K<!)rjh!nTv<.%inXYYE JE#ZvM ^)(@d^k~|3hjjN!sQ۷/N`@g)MM;.*lxk|/W?U*e]׹wCd"2mbDoilJODk%zxϿ~2 Rw@=OTOybɇtY.j@c:`LHEvIj*)W(|5-.:tf}SXƄJ:"3g̟ (8K-T@Ҽfrp+,;묳w^=w\6P@9K&Mm+g`;&#c#pooR$|uvZ9W}}U$`0]{\XiOZLrUO~31/c!?X/_֝Bq|q:R{# b1pcbb,.3a QLWDlP?)HMo-Kʹ!Zp'z,shP &j7*k^Nb 6f,s6uTB{ĉ>}:ƔL@m9׷\o}:tq> zx`+? nvk7#w;ϙ0 H+L/#h>C7#GgWTИ!(}Lh'YgUh}ae蛢z2xRNЏw1cU ( PhAXHCO5}-:3ƲwAnpaReW~ne_.4Ă!>& 8f8?^.@Ԅͭoo{?,t9|Zq_uYSn}gèa8#?ng/V_VO%:$ͧ~ ;eeeuZ0nxz>& 4( hc̗D+@ %6 3fHy X[^ 0X@? 0\pύ{-'*ǣpǍJMcR3c#Я%m7mD dqUCUIlܘ{/_Ꮏ‰'@NF֟J`ѤEϬll~plG%f2Ime/>UM\|Ծ@_CDzވ  r#LZIR-M* W (c: eHs"I۩^@pm*NV _x1!v[[!N8A`΋κDOS nxO÷? u_Ǣca9;'%Nsջj"i8(X">@ F~}w^T) X4: X :4dA> "RTqȦ`ݻ7@zŲ  a#DST&lu!5\-Z۷o'wpp12vT JCۦ*X`4.\K c'9;nk`z2U-%~c5j$y$tg 7k0 y?O^ƿ/Gqsb _b™q*XjV$Q6޻I0ux|zqͅ+ ?!ԧ sk, .;v@__niim۶ŻP%$67 -7'FOqZ5ayK0Z`F?.9! UA?Ʒ9SgYrw}/;RMR U/>gXLJ8f(V L@Hl$WsG!R `d4rp "^@ALlݍ_@TOGX7 @mY-L Sk'il৩ :;;lclx8 Eي6ƶaզU7ܗ)x7IX}fd6GЏux_Ԟu,Ƿ3/ZXtwAp?L SjITQuWuvK U]ƜZbcjΫ;:un] :a!aexaǂ'rt ^/2D5~қxWa,ۺuZ֭1F֟X?w^~Q|x*o,zldl6k6wNߍ*Yu|._|9,8cmךR2+}ؠ0? 41fBz`f[iΝ.'(ǔ nӊÿ3qU7N%TaxO³z:t&^A5;o?եd/ye̘MFHx ͜9X,)bVW 7s[GwBï 6NW?d9|ða,Ly=QIKKK|̯9H Csk P pUFNxG_> g՟״]7f(+*KY|}~=IJb$@RiAS5'k6`^V DB aeKƣF/Z$T[[3߷>9ޓ\'Sҟ_節/jkF"8azPAi͛7)ZZqml_SX^f,m6z:/Jå*ؾ>o?y>7~x/p5!==yn =dQ{7~//S`~7H=NhlW|>I_1c:#&"܂> W{^7ј'--}߯c>?F1'() DLyg=k`K/} S4)-mZWt#ٗB)Ʋ9ndg5@9vjbaNj:#)Ɖ{8Z^TTk5̝[4bJZrfpmm{+|c_#ŀ{c;Sɓ`hh(M ;|dG Xk"Ԡ=I캳]q_S!*CR $D7fH'Ƣ߂s @r{+qRˈ{_Tף^xe" >j@@ 1Zs3:(P_nEmTm`Ŧj"XltpK2xu߀H48x!$:|qqh<'ĿOFboLGh$od000'P N=ŭ/3f۔)$<ʋ=ϕ2?y#K%x]w‰S's?߶^xQ$~mnupG)EUr ;/ciI0]u)? LVG4l%P/,2>CpYCyWk z!! k=.U/ v:a~>.W=y|PZTW!0bM~ [nÇ}Fаxu-3!E<UU@sc3)X*uuu\Ŧτ DLةSgxk[A?q$ۑXWpgdT5T-@;Q#28 4vr0sҧ.)]SE qEc#:YQ}On'tLwam햵p//Nj4qXHp!_'}œwX08IwCmTرDBf̀KWMd9vXyP ItE@B%_z })W*d~H(i>Ҝ9EK۹Anw]U5k0'!@>8lwQjȐ1 ~Ai4ML-|(.JOD=Xcm"b -,C]:hnX($  SqN0N۶iS1VՒKb~zovN.,- >h =v ;v(& SNVx7j?[jl޼$B@bDἣσFj bNF7.hy1Eg#Gp ZqK W>H&@E-Vu[T)#)V%p&D@IX @b匕O/ hG?' 8%b ZW+6-*t9qbasG@ db &k֬aNEP삧w= mƳ ToH|wuuu @("!%a/X4g\Bx.DQs gͬ96)4syV,: m݌{챰uVdEb[O1hl-5-/*b<#B}I #0x}뙉W {3̨Q0mUiaqӼ2]#uʘջ" E!GofLߦ׉g.$% $vtt غm+?SC:a[4g⏯!lEttIq &>MUyD 9? `r n& d߷S\$nsb8l.TVˠD0:r<ҹdjw^x'OQHSK-c%Sd_U[1#Y  qF͵ӦbzII wȺ9~E*:e8xNB3G :17|_7{X9ke滵W}@-Pc0z&[b}n_ E^.& $S qwTּ=0VVOO}R>W*y%.LB@s4U7qs}c\վ՝s~{삈',8k{߃~/ǝ?1k`[a#p 7Yq(ş@` ;[#Elg+Gb#v"Ur΄W|Έ0AD"9t] kA4gj`%tGMjPe=eMs'|;! z)^\[#%eNOJ"_w-W+** c ^9F:1!`1T,K;˖'ƪE{CsM7 :EFlpMR! D A'j|n5('Stۋg_5'<~޿}Q_f+Hxr^wyb"SQE+3kf)Sd=m^VeEDuKb@ɿn \SlsxiBMFvYl\:z@u3`D3ھS]^ w^p'TD+ϻxp|IKN@fK`嫉#0AlFGKP^Vn?=wK{_|.cfÚ5k`ɒ%P__O@006kӏTq)Ѹ0VbτS9le*q98, ).PuGGG⾗6"@gy=êN&'ĴSב< `^>TF4ߟDe|}"1DpUjҟvVǙy`fkq-,h)ݓuML%GK JJ=+~xxa ,ʕ+aŊl+rB'',SfBZ_X0c$0fv?1jTJw`:NE$~As;.:) b0 $N SS];ŇYWi f Dϝ~c̓k0cAgR=nqOε 'Ňa7\{-Ɖ~{޸~$H'a1%N4  J:1 4^+``XZ)F#aior Y y{Ԕ՘)cL=PU^Eӯ> o];v8Y,_w;zǻ;x!R~;D?Z`cXt ˇفs0}ٓ׉A a!OcFMDTc!֟>mn/F).Gu}dc:&#e :n!b5UO# m;/~?BKN|V4OgPv'N,ؼc3~>/rA/[k5{ZF["Uޱ'N;"$_4Xq_cU)Clߍǜ_߲NX!GCRb!07_-@ aLԊ/O4~Vj1gUۏIDj51KU*]4@x  :N<'19?QP "n8oh/&qx.DY N\] ΪږaNÙ 7p"_bǖ[࿶`wwjn.(,f+/-@o_~ :;r?F$=lXڄFu?uTxpTZ1cĀQ?R1HkH~g\r%`8~tby.03?!xgM?w?M(\~&,oY>!Fcŋ-DRK1HB1Hzߎn(^ 0ewhhMWeIBci}.P@¥Ou{tm6HiA'Vu]Nm]mCK} Ե@YlEROpu;jr?L"uuu"~oKo+`^d=?Nm=Zv텽0v&45 l_ h&;.Ue| pD80%\C% +4l1Л!Z=E v<'B)(.`~Yյ>+ߗ-D(~~F 6NFNd?jƒUUz'V+~]y,~񺨮fߟN1dR/̂Y ƆRS ?~\:Xy~TM0)Ds ҏG3wxc9xRRN99|].q46{$-S4 -cM1UޗAEE9s}`d$9_Dz}cnt.^xMx-\Ixd;sw ;pؿo͂8OVM(O@\pc BD rDYȀ# 9n!J$A,[-mNj 1$>9oO eZ k{MJwI@ҏ:W_GG؛ysqss38p4q\eհy n^ mmVٽ`Uֹpѩ@@;oϿVcbT'PÑ~Y*W+ T@s^f IO񌏺* dL8%Kȫ_GmV $FX J {o\|p7BEy=hڦqOT;wUsia?i/~:@B0o<8|p \>'ng([X`-+%ޗW?Tq,lY^a("ҍlH~/ wdeEk*H^~ҀJqG׹Q7?'D BPU7Ѥx 6S{LrOu(oRjZx-6+e8@qۊ >בݻaϞ=It >'ߜ?s  GKK k ; bI>/g]1ºEc >ncbûBq`9sn8U-g2 *q&~TUJ*.:F4;O't_( 'ty vE4$1Bd ǥ 0=ۇ#ي*qIR|u$P\/dHDPao1I?ڏ1>WʳIs2 п7{l1c1I>,Ynqn-r2Cl"!V;XѴK{_/8|μLxCMe ]>&WO$_W傒VܦH%q/bC,\;;r 555ЗQP{Jh#w AŨzPpr^EM.}S mH;;;G?u<_6HgSは<FB&3D{}Vd;'fk(L.SqR!D wXUf,';&q=p>فs&Uuuu]`35U5KNu [ॶ`O68zp.@9_:9U$ߴ Hhqq*%Y?l(-S0C!Tۋg! x VIJQyQu['ڧ- $pdbՐxE"@nfґ'B""D {2N]@(eA^GUr @0O6Bw>B OPZR\m/| xb8ؓb!hP$‚i"ζ䟸oK@M܂F JIGr"IE@UPq0| Lp!`c E6hRR1'Cn[B0eP.p ~$Y,2ӕ3Yu_~M\t$Hgqԧ]U_,J>|A 1^E!]Wp3E2]m=mY##p_~&&y:6JJR[2' s6/W(z ʉ԰I+2.:IBKڵj!#tk@whŲ@.I!'@WѾt…I$?w$D{A?K b;̙3t\e%ee-;aIqpV~_gO'3`.BErd_|s"U,iZ(Sڣ&c<Ko 䜓oea]!9\FL *0<hd Vk%22ObnIGWE'ȓJD&.4DF S_喸rl[\gk~؁-oGܻ]|{hkkcՓ+`VYpڢX@"o_|hI."'L Du+ h$bSGsY@By@rxqk#.!2b[9DGG]poC9+b#a0 x2H-*{qN.P^ə]mMubDR}f 'B RO>>}:Lm=i᫬f,6U+]X- /̓s&\qGYdz+`0oz'?2+?&Y"A'LgՕ616=""'XK,83OYIHO$_tyˋ?V!&Z\q Fd8o%|NB.@UTP%:#|~Hc1˦}a VZsZh !:u*;0̷ "=w}t\sjŧk11@Z"u.!'ĸHy|߳q}Ny9ԹS1dױ 疮Iy%>fIm^ʎh8b# ĆNM_I#'!dzFtA_i9cmI 'ش_?^&2boS_V$~V|b ($p_J3]'d^f 3+3+oeW(IuV O`l{a46:Y w*u*!M$)ɗ`3~t.y,ØcS%P8YuUy>sK,94nH 3 H 4jkkM && kߋOgR xSβeuD^%,P(k_p{&䮀iӦ@w yuѿ7 H=^ @ XC198_3z"R%DL"rBPSVQ8iIkދ7 ?g9G'AUDd~{,hq*^{/I]>5 Y"AA7Q0![UuQ[`p,(ۭLL{&S%Q^,@ (655% DAf1c;1]} W^\:a1,k\]]J+p`P?~V,\AED9'L==S%U sS!<#1(!n8rAr ٧qC1 >%3hp$$ Q Nɩ|ۙ c ºb^}Z` ]'ɥST)Q{c:MRA$;l{ 1h=BVxrJpqogΜ W?f͚ u\YāmJ_=4­ |cvu$ 4\3%MTq~ZM{-r@AU;,:uId:b9\۽T@&BhL1b1ߋ,-/F%f8j+_uʯ'~Pm&EU 0g%D!<fVIpTUU%KX:W[Qri+&U{nhnh+] aᔵm^FQd&*Ȼ}H {^xU$'e(_8x(D0sZ<]!4G$=FYI?cÁOGB+ѨOuuiɿnB07Mb:8 f[!ʰ}giy\_jsL>=Aq<㠥%i U;wdI!Akc+<_ς;:Dm'_t7-N%~ g:9euɿ^ׅ,U@G a?fuM7:" =Ei kP{yƀT+#\Bujx")M`U{JyLQ^.s 2\"a\K.e| NA&$! @'dھ};cUwy n/r_[ ͡[S1J1E1J,gy?ɭx~x"'l;Wd/9B=qƒk)z? vBE @vԤ 3dg2r׾LnQrbdJ5 A#Gww7#xk4mHqDR^C^ø{#<, ȅ!P-bnsq91w̵:6YM&+]L3q?,-Ek7> 7l6=bJ Q|$6@#BcHe@ĸf`uvX}B(qi7$ i?vg1dGp @`0噾3 Pl1†Vŗ9R2M?t@۔0* %H3 ?da U,/~Ѩ р6 q~3_,%2]ILJiV!+i62xד-FQIg> ؘl?5+~r(, /@`O/2SH`1 $.: k XzmjaL>†Y>?x xu (7o-it[I~/|rďhkwSp''6{3;|}F?$aʝp܎zQpai0-t  ',M>;_ UD`- 2 :نßjV JMà*2`?@_W?}/G MJ/r:'ܷ.I _ =0gDco|?q'ã,p Jtt!p <1 _:Y '0BЍc! zrX { 6\Ocŀ9| K7u6e&Zs`jV@a@&`f`?uW}+^=}qq.mr+bϓ6[~`|v7w$#Kph:dP&Q8iTy+?$ Ll= pnq@s3v2[fKw8u &@?&MZb)g1̦apʀӲٳgkP1 MH$~U/ݗ4BE-gK9~F-ܵG $wmqъY~dKTGG#e[Ӆlq6lϫ08Ǭ}ڀ`:=]`0?Up7,>seP~_fqTm lFS1jٸR1 $W~О+VDƬf- 8@9#SU//^dyvo-V4bsjg)u^sܩ]KA*1m)73~2lA D.H `fU%g-z܎I:%5rs2+1lJ~NfahѢ#% g(r!@`]\FdeKfogg*$Ϗ}&䆶HȈ5:3lhJqU} ]ݴ~P/>=mƣ3ЏWHXГWV g5&SxN3 Њkl=2o@_:[^i6 IL!(CR17azS/-.6N: ӧ'? }+$` @9 ?h{|6}toDg#Mk ȃu䮨-7 ?~&~MhC=Vղ̆+lm:&$I\ž!Qu )aPvQ3-̟:e*f㟸+S{tW뺸v=MǸ~\J2ffff^\5e4=]G$;lbn{ 0d'$$AZ<"oK2#q+v tt$dQ=.衂/s\k[Ǒz~* ݈333SH,- ka+'K/ཥ䙃(R2u%F*(ǩv1,ej-MFUo2> pձ k!}SY;?|A"ee8īC>Sr,offfA*>'6| Ry\bM98@qa IT;tܟ> p O}q(ޫG*ՀX5Y$]ȇ5!1}C:]k0,^`/ʾCDUuJ5]]kݫ[aoꛇMY70+ޏq`ƖjºQ*DSv{ݓ8PT_{6u1XTffff׮*O .b>"r|:gX0h+˕1?99)< Z`Qs [I뛫Z[Ih/Q}-fk333THT]ۡ:mI" B? @jmlĚx|pR%2;yG1z ̖уźw:,L# T'b$_$9Q"|T n!ƄXSPa  $/`; #@=Ů_Ց1gVC,NUMP@_{|y׍o3gG?AQ|oEG"*r'<}?h_trcC^_Ǚwg[5m7m7kY >evh`(>Zρ|H ?ךO Kթ2 Ko\D3>YKJ? 1t. (@OY|cCziAWUG/r]WkK*:9澃-c,?_oZ諦܇IӜ{:#2g:bac[5I0#i:l (@}An(,5Nȹڼ'Ƥ_⦆kd*Bh:PJ4vѷ T2B{>Ủ-}Ǻ|UŎc6bTJ`l /̟k6W^Չj}:0j@s(@X(eX.ړ8ה!ܝ-μ=\Z ̦:>Bag9%T{̆S6@ߣ@v}a%jZ xxvpVƘ-)% -|strK> #qC)4egggIL@sy tWislع2@vI SQ2ᮍf z߈333\Kc\mZDjBZD쿠?ư dkgyEX;yk9qîQ(,~ԓ://gWȣi621a\Qe]|̳!дй維04p!o}ffffF0ɅKp(⩫>b? R`o Nw(.b6$[e@K}$0 *@sFj  UG7 d%=vRokHs^6Wr"%Dz#;p{1Ac˪⽆ưTo)&J|wbl0>ALf4+vc\9@FOj@@-`@.y١%<&1I,3ʩ{=DW%O֒8! 89Sefffff>aݶȮD>Gc)!lĦ6m @<㽼{m_ w"m&J2 @JI\P9n@9`_F)TnhUffffwLQOM]eZ|I/A)!} 3a'4tT&DOh^|h{51y#zPNLxߋ;_${s20F`e<EtjֈdVY 1eVŜ<2V5<>nH oV|XŔ7:۷T'DOO>E2 Z4}J_LtK#L0Z[;֪ -ߥ F${` @*QL ffffN1VKIhզFP2@bF^)[( | 0d N[ajCVTX&D@ #|S@@+Ɗ)o.;mK: "q-#'sz?>_*Uڏy6}A, 1e+T&Qn38w:ٻF t-g4 G +Qq|MV16/; Ɩ9|l3v͍ҶM*333X1{߿]]m Dױ$`S p6FlQ9TU ^`@DŽ 1E@_y)l\*y.|7_1|bq~&t3333#/S뾧]c@mX*8ufbKQ,&2~@'LhYoU((G'r* X-Pc$ ,l. RfOc,$FOzrv)*F6ɑHĂX^2O-Sd$6Ci jLČ$j[ 4yoP8[@7l籶 o}0b!-6'=d!! ;@p\} n\0(-*VuEGIRT244p1NNg-zybb ?㩯`X2lSneZoX=J]}ZuV*Mk*cH:O'a Vt-/!`D ?B59MB 4t5@Dڧ~PW;Qx,峲xs8 h-I4ĝ*{_)F *П*_z]j b%__|R'ǷH_N l6R} UvҽvTS%/!mZ<zrtC's(5Ҥ. FE /.}ia:,Oa@@mc w f^Jp$@qKd('7e"cP¥9 |cwSw2V w333]G8ZpWDh?M\{I$b:OnAcx`fÃm6)w?H+Z`)&C'ի+<(krޑsfܜ_Ua+ʚ %8)@[s>@k+8dCa @H33X>)VMBP]Ќ99Z\Z4xU@ 2tD&$5h xA\2+Q_Ep._W#df'yTdJ! 9 ޣ9!s3y2fffF qMM}~~.' x{ٸ$cL /eUU@Ģ FK0YD,+!v'}#fqRH;w^b/e}bhN;3눡Ԁ_ffffC_R:Zpx!TH̽/>|#abGW7=7oX$@Ģp`友 . I-yi2@|xU?rB_S1>P mY0VppRϥ]z696iKX.̀2f 'ݏ# c`BC_,7|>SLTPK4!>{tK=2pimMrq7?ٸFhbcN+mJR ,4733۴ITצK_{&Kߡ؍-36@mznT#ochI/@*IG}6:{""3e]xrĝ4.Č~9ȁ! B,?s8:з8+B]_U?IZNpXbڙpAT7]f L +67Dq_) &E-ns&d@pGŌDGnr=OQ0j@lREP sbe/@t&d̑|`.Yo3b}m@4B`ݩ>09̾5ՌYs+bW*:s bV@߹T8Y@_/"` FMׂH5G G 2H~sSr#?*{r Y H}jn/9ı߫|Џ 8Uc )I}PtI@Da-aZ)zQ`*@m˗/q^12@->.AD>%a gt˜< PAnGȘ s H 1_:lLuu,2"*#1W|MZu%xXN | -0 `A wDܯP?vvVВH(ZSLuqh(iಪx$s Iv_:)3{'߈NI̲D]6)O=8\FSפꣻ?$6#+*Yz#j*xH:&4^\^E?M(ccJG*m?r?0=jD;drqw>d navO/>mK`[x:tXLp fqpK?/9G1m~Ǹ77A `I?^ 6u!;;/ bPJ鈘%-ؔna`*$YG#~|/\[~j5'&=oAJ ωX;Tjffft]5!AV%I_&X4cO? 4a9s!C[}R師DԆ?2TɀB1X`we=x[ ug>aη|rTRYYK Z*+ ƿH331wWIHiĀuls8,S9rG9E C, 'IH?2P4ŭ OfffWqݍk4&>>=R_#8P}M;VԀ3 u?+ca%jJd@=~Cu<+Uq1amtB@:}J.ќ6Pzise}ֳHc=cz o#̆}w(Ῡ}_xe_t 1!1gM?>O/]?n bRXĤ2?4RO6 T tw,"9YY^cM$>۠ :K}>S(nC 0}1W fffC҂"ǿ'T0YKx&') +pLԦ__=D0VMI?56cS!%'Ri g"0E`Y;z&A&&/ͮȁ11Ąa>M,E5|V/&;B%\Ix2q,1L?⋔[+Q ݸDvvVN ROtyȪj ?AMmҶa7#@8y?H8{$`sLA>3F ƙOH0UsOc UĚ IN|tdQ@ۆsl>jquPU8FTx&q%rro$[.ptFK3aiCKcm(cQ XxY&9>7 R \RP25off+)053IvOa0ޒ~$"OJĀ QΟH.F.XZ%yY]J:LC-9S{R&0E\Q[t2yhg4` !~) 9u|ǘe ׺ڡYcG 4OKྤKKhS9ŊQ*,G}Ry%cXk0 NHgJu^zթZegt1@|Pd&P) ӯ2[o,>|=jRƟ:II vb `"} }IE p_)G  3I1Vũ&dfyֱ#s8WO|-C0z[*}P%H?)'M@'W y1( &, CFw"UH̳@KbX$Al;j<$7l('0u,voɊu$/BC4|kՙp-cFO34O*~|JupbBV?RX%l%ClAfxH56ox&4"A-]B }eSp5M P"}2CCj `$Xה!I>|mg1gC*>BRڗE@d1_oz[:Ks:A+ mA+6 Zt`xxz+8QW…jn GǾ2Ii?8sٍ~ YH331}gb[}i>.sې ͌bFL\[V_̟ $ 0^ӄ^\A?bNڊ%u`qPJ&@tzIS v29#V]uoYW/ںbN+DsChR{Ί `ff3NU kYxM ׯ-igQL?^Ԑkj]PYklT6z}~&D?LfhqDp2dA̧ƐTԯjR/W|vn]SV)>ޡ,qhHQr{>Zb| tm1@/Z^42ת@AR~ kYms$ඃK)CH33X-Cz0ο5toʑ"',^._-G'FX~+Z/'%cvjlWԃ_#1Vn$V["mCcezUdvp*H.n{43VrT#r>Z@l$d߁?cff6=,URKJ}v1{#Wb}VN'ka7U8)ʣ?b)Otx:(@[pk6NE"Eb9[/?H4>/1ҼMLH@5z;kv=ki7ާַOA{co L5T_|Esr?M8a19stzmL;)ᖍu`@~ƏmTH}@ '{oN[ 2S. E ~*jk `>3M ;Eܐk˔bOIH33}=?t߿Ulo%(KG2Z)+CfG+kS1zY6 P:0Rml-2Dl.tl`dN!k4wLL(/9/m>}APP6o# WLɗvC*K1  b\9y¸bzEC;f=T ¡u`Pq>ONN͛7H@G7T扷H*v2-!}gwJe#FX0R6033?5e(b!|Xw?KUT(|^ UZSɿ'Sao笪7f"f6  O'?pJÈ-ĘSلjhs-wPrP9^tMgsBX Mug_b$iIrRN/PG3v?# v R0㋑BF}?D߷[ ѵJs5V1;2W,JF?0d Pr^~# cH%4zB`ۻ{31 68)":Vy-;>ȉ_֟:pUc4I - h$Y?VtftF HWJzZKd1V+`: 3BN%$t*p NC,qp"̄7dz-]{lem9YSsZ3R*` H33]C_;c?-ф`j-ӵļ)*Cdj%0:{J:X$,6ihd< `̜\ \dGUd1 UHB8fP+}ƄffS#cUl;{NoFB,1f$@<&Mi<1G;--i*)Y-8'D I͞9$|f5_zF ^޿-amffOM`ѱCXq&H(d},U @,'l [e8Y{vUPo?h1gEA:iYHY\R|VZQ&qxL蠥Z{rDt\>u%b~I 0*1$%b" `ff4J0FO$OK>Hs XN s'Or6^% oL/xO*@m8@,D@/v"+(f\P"}ٯ>S,t, X `[ٝmPghJ`f*cEɉ*Kx1J h{>v'meǷ-?25GSygS=nz4Xrp8^.w~5JltGL#Di#nW|\kBG+ Ϡ8ff߄AJ$@_kff]7?$>?gI^ۏ&zɿu5}ε+D-vc-8 ۵{n##"4S7 ('%!tbmM6aʹ*e1)_X*D&hy->_eT1J۔+MOh&hާĿ 1\+˜>\Zq*#몔<[ ؍.4~`ԓ5*(дR8,$S_WDHR3l 8~JUC}ssH331^gGSh$4݈~N*4Ҋ2vcF^[e̞9ŵFVTp8b;ܠPM'd 4;9N9H 5($fʧNiȢ%'gNq|~˖I11oR  8>cPfo6M߈3w?klgWlвR>d)esA&i՟&F5=KLre5nEGv3br0.΃t좵eɝ>‘?U՟SrZ@RAT > wAbA mB)X}D,#}S?=Bz%uXe}u01Ru\W_`6g1 6$X hAH13#jwQYXjݞ\+FV+s͞՘k4_5@Wƪ~_p 1Gз{IfffT `c+HI9V762fk뚐ϴ RGUSo:Z)S7E6:EaqP2;GB @0KRu'#fCn79u 퀦/a@s(`k 03.k79oZZ KK%c_Wϫ G? lxGs/@mIK r0 C$i ^i4AH$2oUqtUQL8Rq7?NNcVR9uC* B~#}gߦNiI9t$o2zxZj-FA5ȉ, GIV;,w_j(#9$(o DIl`ihmx4-$`"xɊs63R#?[_zU{6 sp ׌03qc&yw 5쿯g4%Kn1FoR4˶q7&W;)t _$pC?Z?@2_HrR&rFm|Y< }jq|KZO'=G>J2\5#¯%hwI\o<G㟗HeNeyjUW BȂ!#S)zvo.XPSKleAF)@ײR  b3jOIQ4Wԕaߤ'Em+ P=T§K4-߿{1bcnC|;"kq|sWS lkU+q4gk9Q{_h)=R%l//ج$yCnqyqy.`{_7X_d˿> Tch_~(JL^VRne9S,6Pco7$R#Th"9 U1jLEm}}ٔA G]?eY#%)x;ިDtAlֈbr 6;_9^*n@l 0#c#RHH.6qY.6gn*m :$psѮE!gff/)_#cw??~|}T#@*Rf)ؗJ-11bs`'GP-4 #ij%/ N_7?M8#|m#2a) `࿯5q(ah{:cX?齴З<`_j[Z@^:3ZkuفVeW?^?9@2 mnxq*̽8<ͱk[ӃoHAmnl|||Xo>-_Ahy:,CX޷vqWf<0@I+,YER}~=>#(D" -$RLPшzeVeugtVe7nT"չȾcr=/A(]Z\I^wrHhm2g [p4/9)1xqTNM7ajzϨ?BT3J$ :e e H>oᆭ(cǑeEh;%FDU*m*ydYm#)M@j!}G5@C]\#M?׾u1Z2Z ?W T4?R<7qߏ% X=D`u j2DT &JJI8;ӯ &+HHؕ~K)]F[ZC" l=M }w$@HıH^C}su*gHxVHs\easN{1٘l\NΉN);bP 6u #0R0?P@5" ?yQ|69BcWL_)5mж9uwb{)h^# U"`2w,!8Vֺ s$sNR?Ss?hX b.5O <ر\ /fѻmbn2wU, (Cfa;>>^2+X `uk;[,fd(X&Ҙ-2ȹ%skUgkic.Z_5C@NC]t:H14kz!ZƆ*ڦ)#o\˘cF/$N}s6K?fQMv@?`B@{d`F,0ػDj,8{oFߌ( 4]V6'f n3 taj)@C$|HıJo/^l{|]c66WHO`hkAUMQqk#%ݷA>`0f#eS.϶߈Cbx+M4) PC2ˇ7y ">q9$U 쏏QT;sc@ piX5;5n$@jHıg?pߊmuR$ )ш IɌ?C͔x1؍ >qIx<=ߚ׍(|Xp` O$$`d;|pA}'# s2ɷr297͵kj;VWkm l@\8"2:[ D" U]\/>br@ӌ~sV1I~;v~4HO?Icef 2^"=7r 8rp*qòm&G<  )D`H 7e" ,5'>=umhc1{YI%1 dHr&,.㯾%xmJ̺-K5 h *u}L%D@C>!^5ֹPsT51]3?$*2F _(1v;Ʀ6NX fq?DETY`H2?i7lMi7ivӲ 5\-f}1ҫg)-_& m4`u}V_x#&s%4/6lk$\Kp?ޱHKb|9ا砿ρw*RMc:ڰ8#~s(suF,s@6%e;N&;7pqGK.W#|/4SSTrߤ=j9`ONVos kC@[)30Y\Q8C]xNCG E 4)ϳ-k%u\YJ?)١|X b*1ə910 3Ѷ]:`_$3"`aEb '2} HA&  l0@&O7߲~RGC(Q2c*o2?ru=ojW)Ϡs B Rԙ[HDwA&]CYUH%![Oۗ<@z *f.,;>Lja$߭<ټ,SLm@D]Ici^ZBv(, YppD7f%ՓU،%AM&L+񊹷u* PZ ϽBK5rm3ԺXxUds} @ӿ! 3${hK4v $ǚTוK?/BÐ4=NC=O?ұ@n\dN*:"\י/[д 3S@4c,k2 RԊ IGpK'x Lȍl{/"k1lL-@|s]D~NZXmk >'(AN}]զ Phoz]h Ĩj(KK?W&y![O"xRb&g$W[sy2t8غEU׈ZcvijD%8k  } gfYmɌ:Of&Ww/|>L8#h*98mb Ϋj&L}HJ-" _;>.:Du@ /.P^umEՒ뿶kkd*,Zb4ҟ91ĸG#FٿCVw ;mF?qS?8*ys @ a9,L3!`PpRd*މ>J*8-tph_}]m$C@ (;WYk]8 *2$@{0߅:GB ,; 9|^ê+*f'1+A̔RL/XFhas!Lym.lE?,G3󿅉%kL!nݢ2(?F)!03';wP/@KRG7`f/ef;>q%\2dw\rg뿫h]@Ej 4 9 lsӇ% @7ytqmum 5trMkZ]OuZ"u1j7٘R0#OLBK J W_gkS@XPfXz`9-YM0.\T0zS/se8% n5|Fs|<-O?]f!TGRߠ͹@Iiu߃| bj*-ߌge0`Gf0ύGH&7 Α N05T#N۟nm}Xz!Vr~ix*xg /^5jX攫9V@@ @B* 3"_x!{tOHHBN&x$B@*YF#=2Xieco˨+66?LEoJڳ?#F̆okkkT3g %3@```6 TG{7„r3g4'(Y??sP]RM- Z&hȁ٪._>A& \]s.[W N *ǟ!yIdȉ F*ԋs㿩+-cF1 ;Ryauo(_s6 Gf\ @A2& <|xi<.2Ėdw359 v٫Ir е">b5 8 _67 -I)7< 'u^%3[f75ix|,I-w)@2_>U]io5@hhZ7D/B}S^3T~m7SY?;4~n &ccۿaRSQv:|*$x 4@  (p2rx|řm52@? 0Ȃ|ξW`%6^RHd@Rxu+.@AW>s ]C!{د-_G/zT4[*^} XhgGc0Μ}t?6;ml?I$![0$ww`e3@"'mfY %[Uy̹DNp4 ΘY mWCek{|;ϧ}o+ݵIRiBR埀\9C B[>e> h! |ױm`ݿM/㕌z5/K-Be-} R4165ŲJAɱ#ihr~Ǻ5#eTy]0#X-UJ(DHT E,xbnnSN `87:|^~yg7~+fVR/ɇ@"4DT " |>I.|Ww_Wd Vhr}, hzpbIZkj:' PO[,4̙JlܺNdmha4'JIbS4%nݚ'ύ$JkiYɄ-M26ym yڿ?YxG9ΰ]ǑYn`wͣG k8&ss7KY>, >Ow<} Kq<~d>/VT1lk]!ߺ[ wa׶O+dOGϽ6b!12?hYKrݫWY _[4@(W0) 504Iw+LYÜAt0`V$>=Ԝ|aZ.㦁Z "Ik彿CS]k .@U'Q Ij?߄]@W>}>O/ӵϯtٰOh퉩XbX8cy1)6 EU+/+j ?1/qD0u N`v Ε3Ɠ]132q|LQ n/~Es{(ѳ-۞N%A! l$@e 84MTzwm(.bׄ@[@j $yST&}:ye\=[)~ 9 #|ppg\/1g4A)c8 *P0\P3@0HK m[L' i#($r*~f2?]9#= `Wvm b@#m9ڒuFg]Ei:.]]MZ`_Ye|%P/ ٤cq ;aItrdbl(10OI-΅{m$ It#$`a/E C@K@RWdBoi 89 uRR7[@fa"flQnW7o}B:jDh%[@TK 57&_?sVt@+BMLz /k _*-  8K0o|„fG .# Qk7Aeu-4 km4@8P:Bar =\K@X2>yFR  #FP&=]? -~4) Zg+|]HD:W0EU!@@Ur2?p p}kWJ?)ް".CLMn-1WƸw8” 7Ee?rbG$*rX fI$eOKd>|\a2r9Ff1yLL^@mm3?b]u|?%%# }|V@t }uv_[6;4uWewu'\=. rI@۬^]a}JiJƲ_V/F.3@6l62_޼yzLnkh)^Sf#5T -Զcx-@&~} ym@^r D?WUMU%poKhU[I1 2bY$<¶A]0qK>ٽ{LO(/ur8KA3ȼj`xIսUSb0iq~s`O?1/}J6?[ 9emp $@ȝB w" LC, ZisUM[/Gb 0' v&'-*Ҙh7IUl$X/FmG cHt1f)SL. [&+j L3\J\Q/(Z?/ $%S@vuՃ_=O_[Gk>q@5YP rh$U78K_^.nH^m1]սK/SB@jK. / VbB6wDY}I8z %Hꄺc4m׀{Ie.qT˖D [R]Ig=B~GQ oQ0,'-J옛o_~4iЈNpSHiK" iu ,UU|]8 wk1.ٮ(SU*׎Xb9 `L15$n]{&`3yd'4YJӟi?*ecH8 X*& eDΒNtOGK6ZS#uS|8l1E% ^ Y8'0~BF~5z2#*ОwAhB }U4kbp(hq I}? /1Tuj|[M[ "1 *˖iM@U{h}BwŮNSi@Rb+X_ђ)o̓g,)X+f{A?b"2Y(P|NЀ[RdHXJ_ zனq )'lqxkG(})`UU ԯ" +puD@%|Gܾ >p(^T婢x "|bMŨ\/>0mV?5?,:vX" kxLzyILm l`-&K"`y:ЛD878 @Jmks @}\vB%&Uy=" 2!PFtp0׻& 5 TsQ_snw1I Ҹub]$W8Rrws-˹G{/'($AQ=x$ R5`-\>/f#& ` XNt4 |ec3sqϢrnTcOst_t-3x&ЖD[?$@]m&E[ ,ho[ oT5k zMr_XY}gݟf %x_M_+xp2>1?OӘo&Aƭ8fO|.2hC?U@80X 0l*)Nh@r'#l;[.Se7{ͳO=k]*^>P hI) A% EY@]@|yIB}pQz~NI_jǟh1 P1"~Z &7h#&lUGt~%O1uH zX]b.l'e@DL&*c `^QRȤ.Uٶ*PMu̩K=o_;he -PДH~_$@wCN!4 |ߥBB dmt?\w9d W5㱂ğ!$wRc8Z]x pOh-$? =cݾ}{^%۰nܸ!/9sD 5":xwnFkx7U;3Ś9“/?*z? к>hā- AFH2ȮH&.|ߵC1 AU]?vmMPs||uL|~{yK#z|[8)($1m/(vO˲,fԾ <HnJd`&)Sɜ쎓_nx\/|k~`iI rc`3 YS'$~#+ٛ--gx>גy+F x \gDA >G%;͌Iclkw혲㚾_٧}4ٷs㛼!}IR( غ`Ppyk/G___2Qs@쑋_yZǘnJˏ?nt$td A  1fD@V4*\@: `U%Ud*WԎ}] `7Uc":3?SGߟw- }3$Rv.Z{@ T&zbݺܷwokٟm*kŔz$)k{$Ϧ@l5k@̑KQ` mmN!9'mƲK4-f#xI ,Vb`kȽH Î0f;M2d0l:#B!3jj5ͭX+E4{_`m87,}~ۼO@[>Q0IDDS05^(c@4.&iȈ^Fq>l3 #0O˞ daCLsG8"<0)U@K@PTѪHE\e0 6:7_5om& @N{@T!0jKT4H$4n䀯A_*=/T/UU?cڡ <Ui>H6- +br7&xfqԂ;g\Z<xEN$$6ŦH&\T)1Y :pN#UÜUUǛ+.ta7]"{o5\4>^+HZh#U#|]Ʉ" pMTC"P 49!]mɃtzW7o3JʺK*@ܽ@hL$UKVĺcI5J?f#02 *i ˕XɗDo_HO6Ȍc3ݘ@ 4Հae$!OHC ҀBStkzoKJzeR72% 7I[ @A JyMdfMxVs߯8Ug!)>8_}|fCVK$Ds?~.zz.) BT)RS8cbBjȱ'%z65^Y?.,9b8Q8O)3,UI- Lf(f+4[gͬEfz;@;7/a0m\v8 pF?1vE`6|Mح_*emp ^ڏ%rQZb#복Hmxh%x^=`c4՞->髕_ ?7% |r?Cˎa䚑 zmuL|K,ccaX?e?*@ vIK7Hx™ HKx=7$q 4emތ@<2rəW1`&z 9Q83?N^bi&dg?8{o omdg~;g O`y"@_"5zH<СY s;k$}1mI6$P&%|u1T]Oe cڀ2IW%/L4?_=xdL@#4&{ҟy?o'|iaFdI喑)?`pfV k^)GK-V/xB\IltwM]S/ȍ]94͏cssfAFI5?SO\Qk RRpWVǸ6iEY+kۀ.e}oyjzlv k]3:ktM:}+ %# #&lesP+8_{PO=O8ߺuR?#_`"su@O `f @W7N6n*PDlK2a;J{̿_ͽB@j KBֿ. @W7wmX%mt >~W[@VgߴK.4s 52{?ۜ5C@M%xA̐MBHu1\g)(f1Yb :$½>te,/ TP2`4?r+z=:k\q ]0Vƾʨ>7?6_#,s ˤRbU1 'h&{>H_lWzי~_-8;=חY﬿^SE@㺒ΦdR'W!浵9U & cA?hH<2o=SWX8`,C2o/t @@U0@$ᇇonmIcGU&g]taZLt6>҇٧Uz ke.I-RFЌʂE]ZozD@}]>2ʱLgmk߮s |75RI_v| VXƖnMM^[:1x&x?~bsLK1h3iHX/0 D"7+3}/ uJU"B(Ġwq }s^ W]t}l뱭 }s@.DMS|67CJ q`I %$,?Uc݈]@40v#@2~E]!#մ`2a|sY/b 䢍$pga$(-Rk@c ^΋YONMi]q aH}|^Zwk;t߶mtSYxr&k`˾tؿNk@W-poH2/M?'27熀6e֣oA.ZrH;FF_|s5"vm M\B?y-f;Q>(U@fj} / dNy_'&9?bJw,};STPG-~x Wf_3 J`ɦ ](ʂ>k^B Pg? u}~] f!IRyO+*@"4Әgmjxv,IoxR$&YY?ݖ~GT *D_0\/ :Y@rzinnݾ޹/`NQ 06?.crCJy@9Un $ϳKa<>6(hg*Ϡ|&**WQ^uko W}-^R1M_wER6yP:US /Ze5!v @LP )I=\b/6o*eQ2( C}6?۷o(fQ&hy` 5Gp/'!\xNzӎ*LTAyqOoV?ľUh"I%b*OII X-] zWSP;puvljC?:Wk.e-ܿZk7 Kd4QSL^pcI"\Y yG^ּ0OMQX1D?xܘOU@GH.oŔ*T$Ïs/o;O j2޶#=9@b?mK.@|`֟M Õ})` ^|HJ |ԷcYN[DC}Lʀн\Kq}kspC?h ˈx ֽRi?C90 JxɫA]|x߃?y b?0O#@wAHdRE;HG\k@`̀9#Jʰ~pk=2JyZ)~גdd~]-CI ?b4Ҳ3Z&}MPY:ܷwf;ƅ\<}!|n9BN7qo#>UIs.$u&hr\I?CbnGc GD?1g TǀA\>Ɯ*ށglFTf@r/<0f>Xf3%I)>| L&4þkJQ%{,#h8 ?}?jM ?c>#1(:{keemϪ:uAϺ7}M) I ātRD>]_]hJo31OOäQt_& wO[[3yKMކ@И1 !1be0YgIH\Ʉ?Fv @h $mŕo\9ĩw3eK M}&QPg\7L=Ky3?% K$kԠdFPc@ ܩLHPr. :`\MIW9$ |U@Ϫ]%n0kz\?r@U[ӵCs^c#C6Bn y30fS~J7:$?uI*l UuT%CoKhXMz. rg_ڇmss&_ s5}Ox|뿽;aLt_8Q6ȥTaL!P??H #0kˢя~d P<뉙*io E ԝS޽{WwBX،\0x{@ɕ&Y{ha~ ?{,Gy/[{K,10ASNS)$۱+qSKrR~H*vUUy9/v\FF)cX-!$m]m_^WY3=LO{}ַN]iH plI"k$<$$׾SJ w[WvWa%En >V/׼idOzmv|G58c4H˚sΔ q_ƚ hz~G,1Q~7 j י3gPf\8Zv ,,W˭P|љm?y;ˋ]jڧe\BhrHHia 7sI:eyqAh\0ɱ;'IU[v_ aGdonԸ w~ louVqѷQďlF9.2a/haN8}dOBb u/ 5h" ִR`X)߼0c4Hy_gI*kEgk"hn6H29 Md"lIqrnY~| Ў;9,˹O߫#i>G&3}ML٤eN,?&cs` {gzK OwPƇ2٧eT"3L`0 [yB@ Q%dm*2 {beh  }},_6Q#<Յ~~Ό3*=* w}p;K"~2õ'U)\u2h jXyK&n%) p$uϧ9F>ixIM]8W?Il3lƀ4`X//,ޟ/qml28ÿ*::$Ol>p n} Uo;rnǹWf*~ s5}Wc,0g]p{K%_oe kL<68qC@7KA^c)M*0io ;Q'\OΑnwI@ e)wt42u,m3pK??' \N n| TGI@TFitxͯehmdz 47Sʞ-G;.j ^X̘!@` fq!voyW5r5̀_ _>8?u>(ΖΪz솬ot9K@8? 97q.xV3[aC?h ^JsQ?ߚ[< a?*JhW!2XKuc_A~hx@S-`A0 V{li m`q3oU? R؏B< $mozf s4GY? 2*D#g]"rf_f6mUwnhu1 j f6 .H/Ȣiյ6 U  Cy=r':gN͞v_a6$LEhe AI0>܇:|J!iIQZ5YJj1 "1YI{-$I(  I5o0cל;Z ] ւg3>#mF柃pi$\;Y.zC[ qG@!yWeA7b1 J߸7k?8z8| @ YK[@H- *F$\k*X@ ?-&Ҍ rl9E <63%[IM Hs%I9!$@n @_~W':=ޠA7q? }uNu"|UmsЮmnln}9/^9W?l$}%jY+(eۘ+z*xG/0h hFG̉˧_X[X7nȷ=9뾸 p=J./>Ӑgܹܟ.y9&烀Y5dz,b#9r˖ !'27d$ؤ!ALF |l* /ITȮ*/6sXLⅈk4,-onyb}KdeK@n 1:$@C<*w"{/lƀ<m dA۱(;r @_0Z@ :dvKos>뚯'}MI-l7if9@_&Yˬ4 _3Kc ܷ>x{N_|4c<sa7z7/aGfYs~x`H9  u h浪/~!ǎ߶-/\l}֛/ P;@MG_ú~_~67mRO5˲#ܠrn3 5/ -Y6v:hHGM)Q":=^7A?Rz8ؗ$5\*l~M&nq:De6𧤞^_'Ͻ9ks&J+?XP?ڷ_0,L9cu^ xd H}r,>ֈ=8$ny!路@YPEyp~pfZ)ZI2,eGW@C)A\+0N+Mp"WY7 ;maiƭ6/%hq,MϟyO>cYY` Os'#;r2 _2X1C% +9 ALBY9a5 B^Ȑb.. $C͌ZxUËȀf_NӡZyJ *_M0=os2,Bk{tE)!^,yd0j-hy)Qp-N3Э AYO&b^@?q6ŖOSo{p|VioN 2gm_hguH,cc84S̱'Mau+S‘0kqAhG g-~aR0rLCF-(0 [.ЂrY!qR^xu#5v+caZ})hL)S.>q oS|pO 3D<(cIM{.._g @q^Pj!O k~sYu@7?3h^ݖ{߮_q6V$'j+`Ofmh.&/O,XS`6)k<9c?\P# 㿆`6Ee.4D-k^f/5':r ݇GZe ,-1;0qvG,3@>$9ۨ*֥A.@_Ro1qj`R"gm懣N2 *vOMq2J\-= eٟKykf .spag 䭋k}3BK5_nf?$POPc2;J7Ã+m<b*\ (1lZN [EW G/>u#&"(K֫FoCMl]w`w>Y-~ٟ-@y\`@$uslܖJ(AڏBr[tom7/?[6_G8 jm_ZG4^{c س{T0ʟϼ1AК<̃S79NG@?b&aWӌ|?O}i*bʂ2a3TP J @P LUN!1l=uQ/gO["m KƑn91'h}+ go+O^h|ɷs& 8k9A:4x .ϗ] '- p @tkN? B`qYA8=9߶-}l_pe]m^v=|7/T_79q[FlΞ`@IH$Gl~o ?$6* ȣ9(+ (~i+NaeDfI1$@C m4yw?=|DP&]2X@ <Y)x_y}OHR `R!5hNN2ٓUǀ^~^Ic#A0IfؚD:h ^ke5B/B=Woym4/;.z~K%Ќ=?h)3g=2BL2o0D@ bA?o>7ۗ+ϖ j @~,ds {DaΖZL<_L?3d:}>') ]At'jdMo/ȀN?-8(dp6t'E_f%ȷ~VOv:H?\CUWCo7>1̘8? Lha ,3d if= ?0ض"f#qC",J`[=~7uU]1rFrQNLOvؔ?$9KWfHj4f]0D@;gIdI kdP:  m`^^3fyf_6ײz۶KOxZy'eb2Zۿ3 @?wg7W0ct4> ?w3noslys h6;Pw(׊'g>unǹOXx\Kr0c8cA* H8G0ƷhZ3 y3icW5A!@ uJ7)fȃPi0hHJi0kuAm`ρ<.;Y~6$;}ٟ*XrBċ+"E?\P*CMɣ˗,؜%DAR+ ?of%qrfJk)7YelnZǓ;U0(kc'L{I p9~ze]ZY oyΜcr<ƣ/= |~%o w us|*m֟O@_ɿş s@gx6  䟀I=sB3Ǎuߓ/ϱn7qa @,+? RaH+Uo 7%E)|@*sіvDanR }ُ,wTmKHKƗ 2(r*D!5@]$}ڠC@oQ$׹@*r~.Ix655$ˑT0dY}1TCWdZ3CoG? KmO`ܵK/'l׎?ik?Z$TͳܗXR_f^x˛[~!("7Xk$G?M㲏khAN .P]} n][?Nu H,|'ynt=- ΢3߹@xiwkޛ4??7,NέhzHoZRo6rvi_G}͔RaO?6V'<<[_h?7 } c|z32̿Y "GnGmC2`P*c @@C@sLN(uYB5P`DAuv5%@m6lױԋ@dΓc6Y!3Zi7dd|a~uޚ@R`Sęm$67H`/>ח7+oKPY>=jq +/;}V֔Ỉ4HZo4Nm(K n5[F?gB5<<`%f^B$0!~ A l "cí~5sȅQP UR -nᑓWBKȿM*r%+ PK0Pƻweg.SHjey_qJԂ22XDJPƸZ0.jZN6E@R0Ev@wVɁzs? `xNf!𯙿ka` ]C0 !Çs0l\ q8hP MGM4~Ѐj 0Qgv>k2tYڶ5Pv9`wIb&5 L f{ d2ι?_>F$wv5X+>8W/Kک%3_/M_Jm_@j S Ҁ 9{^*5#0Gp HuPjH`\75jG)XXXhLiȂ1랜R2JXTpИYܵ?km@J% &1a#͙DKG"귮[~} kňԟOJHB=.P h &- qFm 4M7nAP~w݋-q˿]w m" < o#%df+48ӿYzMjhC^dGZn~Iߡ )N1]Σ?'P k㿄=| 9VW)2vYJ -JZxk>q͉6j *͇G%0`gi=5f>xd*.׈ Nl9w<{,,D܏Q)Khh"AVKs4jyY@ؖ2}2XieqNj!iKYKeӞbTp$/o鹡|fl\K_f]4ImDoif '7K`skO^l'sFJyY8n}؀oJ v.ZnH=$\kih(H]ޛ:=utSuTC<xº 9Dw5{zVU/@\ͿzK5ߖ^|f c<`;!v?i77^=m/2puzq.~ׇgy^4MR'w'2d@Nfgk5ڂ>("Umd?oWLhS54}Լ߬G?M#@OQ~ T$͐Pt(fI B) _+n͊@6\i-13! δIp%1Apӡ[2:lۚ_ ؈mYvw'?4i?I _r%\튁8O $nOkY͡?NGD\I8p偖gUz"H]י9$'JȎw܅%( ?3p>?+@tT0 /K zc L;Ci<mx`,g*X2IpLeE`&3RVx8sF F}8M I$8S R I|?IT>I K A?~'nҷy^Ivn 5Vx]Iri~tÏȶ#B:.^/k5BT2񮖁8X')?зKiq' [aoF )Iĭ7^YP~Aր~.mI8oͿ,O-^ I?E.' c('?83o&~@P43W%W=GIHŦa#oB,sad*5`>!Ь v7^X_r}U7+Nк2su q]bn77v5344+]fihj .ol̕sL~62ͬi Ϟ=*Cϲ7O[`ii)P ԑR`?,غ}Ǯ?viX2Ag8_ g, K}H%~P퇣 GoR, iu7Gj<_+ ~] }">8" a`NsVꀬ{7=`' l1 qd҂v~.Z62@s3I6?~.qb`߇+qM\/[q97xr?W!/D_HCR^ ?F)>˅ T= r;+.?ֈ}3Py;z>o\P*[Ng|l:s/VO<>π3H|?s ж|mGn${'uK6}$kU/ sP}KIZMe%w$6w?#"+k`sXSc W\X/`h' G?ogu.7x{&bK e˖:dCT:@Bk)@@yueaՅ[EL,'8V?Əhw';VvU} ;lfykK@Rp??.m,P;5-doJo}vIU;WAPq`MПyަHZo[Mʟϵ?.}~U[qe%p~wT]Oɐ[+eoϾjޏ:sFTIU?fI FیOHu0!)hP@@?nҶ'L)T75qxg@u';_:|fζ(&/\@n:& g "N$OZ"5) g^8mdj)`9uF]߻C:vnq_Kkݟ!8~yl{ebhXP͍!l H*l s*d^2$bܑj:#x>L}{: L'nG V@D,@6`.m`-sHRЎ*m ?Kr`iu)Tvk/b^_yye] sUoOWJ*'y^)<(O_JkyFg[+`?3wU?ǣbM–5tG 3^ ?FF!K ]r Zr@O۳g?_޾ kor~Ԟ𳗯QYDK81k l;~pK~Ym|>9tln5 3.B KU@d@ Rq][ޕ=f:+>ei@@+'7KE]us\o38Theq~~|aif5괹ܟs[1?xȸ&'̉p֭=uP\ T Z FK=`&G)Ll g& r  " l=gM{`ڽ堵$AG QIpA ?8`:68II:m.՗S0 <?. Σ#4/}R55!+Rus;{Z 1@#Kߍs { 9>_kn=U9w-3./)< 56%ܵgˍ#y˿{2w&'~b?۠#71ϢAzJ"@%5 $k_ŝ_뛝7>= y*?JZ]I^ ?۞.'QhFZ8€IKd_v 5"r-0P;NVd@8 mzUًgJb'K MG!;w Z?-eefr_ەk4o+в9 {o GLfm. Ȥ#dc7_͟襋~D/mnGm–UG?wGL=ZU'7;;\(R[bYj|?,`mn{% ('*dϧJaXY9zqM z@n`15' lN}f'I$qvȀvkӪس&3h;ׇfgۖ Gv{1K?~AIjKGO'_Sptq|8~u= BL <*?A(QgrD{4r5njM鿉%X?TĵC?33SO1:$@Č?mL@rYZ &_"bټyK|JVC?,$|xrszhN1"' PC x-փLy&~n`+ ےLc9AYc!nIOܷ]{|oYvMPSz$dAR,Og%9v_fܻZ bpk s6Kɿ9,clkIO$@/PdgGgo9b?h4rTCJs[bߴYǵ HJ0j0&Zz:Y-מ󵹵k/I;P A-F~l+Ybd8i] ?{$uvK YL)%Aő-ɖ"+$\8~pAO~CS)WUNbWE(RDED % č{ٹs==ovv]f ޕ^xsģ `vЌ==}N,p۹j{㱀xB~_wϽ. 8@Csn_@ ]Tt >?rJ*K c*Qs6<;c}51}~A9g*?m}-16^{Խ$EkW-Nx'Fm~/K#3\68`'׬`{%_7@unnζW\HPB+Sm!A},` &$7+ei73'&F+ʈ8_vot>~O~h uqɉpҬo/7Ixs0<Ȗ tj_s\E-vuAۧ/r1+Nc (V'Caz]pvl| m϶^еB_|~ 8g =0SdTwODrp_?v_DІ}g5Ncǐi2vG"Gϓ Je;#Uи9V+8p GVsHl+@] tƀI@-0W]ZVOWb.Nb6dtqo ,֙vw\00r}YxS-v*e- 1Rş"HY~,1 ѩ)>hi>Tu_2~ ;>!M:/)϶Q ?v_2KA$gi_?r_(/J#ң/A)_j+HDFy:6kh.V<ҠBK?=r 3kjn@XoP:: .`~ϫ_qRQ.h0>i0U?g=Bh0ϓ6ns鮷V ύ':Rn(kx!%Sp%`B؍1/> fy[lHO=h5B9'H7x;>n!P@mYǷ|iTZ܄_ĈL 8?zzo nY~ &~>9 .bX=dx/W[:we+ k_x|dO%r|ibh+ RoWti/Z542ԿL5APXYc;A1_; Si4Rx"=@ |%~9pKMIŀ3) h'vR1{}ߊ;JZVKq3}u7[k: ޏr[:pOO9~ sx}{r%x'_ޅV& l;295ZO$yA%?~[2Ϻ&ү]|wniK%Q)0`Đ\yޛI%+\5ͱc }\M#<7j +hVCC:jDr}qBA`l/M ,~L׸j)^mk?*zP8v8SӖwB fݵp?@ . |s]ĐvvmGĒĨPv~n|%[.Ӿ2x 'p΍€6%pztb77r.{9?_jkt`ÿhŮ G,c3uDg@dV̿+7_ wt xСdl޼>ϙǹTs.7DPrnM"@<|y[W7FE."d7АD|Lv&@[N+^M-%}} fݯO_$- =z;%! z >_?s+sas @<c{7觅v3TڿVY-b~1OK@G39  }/{ox1SwVjFK+Z#?l&Krv~۱m-9'7D"rO \'o UL*{G"@[~f uY! yeqSi1\Fց\VC-|vLX(O2@ƫ;_!kDmY 4ٱR? h?T@9ǀ.-֡ Bb1!oWX _/94k?7w>Yqg;PZSA2 Hfh g/?2+PV៚:T"  :R:f m;ky•r}Eo8k߿ Elߘ~[2쭎hGhn AsIy" !Ϟ|}МPmB9ݟi{X bE jj?RV7 ?_=}豖}_y = G}/baZE2oZ4"g,[J*>ܾ%kfdq-tEggd~"t @/ E? oH+@)@[zʅ}[ gmڧDc!g=lD,IE0?49 fOh%kb۝&{N_0Iq G/?? ۩ߏ__ @~'a?!FP`߽A>wp?TU{NZ\?..焁s#SS/96w}+h=~iqU%Rnf75 Etcn&ƪEJyX1l;@q8~ѫm* ^HBs*h01 (.$khc [` TL? X/1nlPp"|q _ARsҰ+>GGi`t5=`OE)$>,@?]Fl?(s_ smk֌ݦ7MΌi>>3/we$3ca"džNq/&7.G5eͭ}*h%D$"1 #[*Fڧ&@jVA{l=PSBJ75 0ÿ yp [#p9Mu@siv+|sq"|;_ sdu> ;v}[Jϕ@?ȇ?$p*ƍ JcFuw[^?c8(T3Vwq[{5څ5A'KŻ3[?jpwWP_5TX {+Xр.$S|S%fv{PI`r~y_TkUo@6w|'|l? FW;m \@,~N i{@_?~.U  C6VȮ#ޗakq?0_Gyz54D ?4šoA__t} *V{UN@~00Y9iъ釦gBZ2<@jV&y]Wp(B[{aPOoJ bȦ}I hE.瞇 Ю( JH W+'e+sW׷ lqo>طm }ҌLұe>BЏq0}c2O_q3+!ru:Z9d'o~+[+XǥcUP@CEQ~irɫ?Ǎ/^\`? ڲ!k BB3 m)xBBkC0>3ޒyi8ǟ=-1SrIsd_@H8bFov [MߗݏP?ωR9_} _{<'&pif˿/Ͽ`L_A_*č+;15C9?s]n״_CiL͏? \5j'>S)2 VC#g -% S*؅=&!`!'B8@(SAi'}JQg?Q#v& t svGKB'łl>`޷o:s>78 @>6gfG^{5kjp+ʙѱk/?>n3h1//3*o v7.FUh<`S%v;ʾ+f6\ ವBUC#"OBSfa7 KA!ArHI֧O >1|_7 v 6ЮԀ*|פ̽c21G[|@׳/M8PV$kx6[FBk c/wbVn@ӿ\w%?+h߿FLOpLF~(}\lQ 3v9Y/cgFt_?9=ի{kv<;e?岚a`-kt.p jnekFn'c^u,>p@" , $8gC`N_q~a?w¢~Oέ瞇 {kIp}* Hmw4nD~~?t]Υ?c }-!@j K3;y]T@G3h??6Ac;;^!Gqro$ܽ-_fmkr54 w1S@s ]+9QOvxOF*mm9F#+s TԏQ;%7ߕ\E@ 7r Ee>ϥ8 bJ۞. S&}G@m'ii9`Y'>?$ŖKi2OT@sz_r I(ktGs&~츿_kK2^ǦPV? 4n2Po0>a/I"ȩB~CX!@7:F3 {y\d!B4 +@ tvŀpU ĊiXq fv_W >Jp0{1Ҁ||<ƃ%\?gW*5&b]z#ف=ݸ?g_M4TX/DZ d9C޿uDd  0 .Ap"`&'?$佈-e}= 4%Q`b@Nu}߶!탮õL1K^֑Jm6I@暑Hch?G5 qXߵn='f;?]*K jщP 4~M?y'BZ&UƜ/0%qs3fN?tW~)kpqa.?X?v$Xٴ2m/_jr}" wmy0m'Cq/} /g *$HT#C"9K( wZBjEՎ5y{c}o-?L>^a vU৏: %5h5U".'L ;^BsC2M+V%Y/c_oo1;s pСdXVQ  U4̚"Qmܚk藅<tUEyF !]-e4A[+Bݺ1~2:&W%^8 Z\c8B1~!#AZ/ ! dZ8\{+/M/? 9O?- 54ڎ*Ǚ":id߉[w7/9[8?Ϙi_C5V0b@ޜȬ4D f&JوS3dO2bmO=ԀN?[x}sE /ޤRu{ %x֡Ƃ"@Za f?1pѦ + `>TڎB?]g~ R>t4s䦹_߿DzUcO%X 'N]}2ws]T=\ߚqot韆 Ev7Z *$!x_}<`W] `IpB>&<"pBOΩ,s'p^K&\e8s9QGb<څXρjc֏mWϖ/}}F}bGK͹H!z:p~<+pfL3KGq_B%饪Z?_BeD]qŦBZ qG桹-U+%|HR}>x'o 9^z.yIIbt s* mA$~rbs:.ecOfuX*/ðOSY~)Ͻ^\?\Y?Đt N rU:P_v?3>e[nkoy?)71vܟ53Qr8m\;pƀuO*Ā;?n9+-ƕy4n,#tՏxNpǴOd><02;"Ӫ R} |! Pu0B=.L}חF r8[NSȁw8 w?v2.m+O"kSSIkO7QQ>/3q;PTM24_-|mS_r_7YG%dDP? 46b h' A"o.H"@[`A`~|~K,p4g H=TبB@<3j{3isu 1UR~* V yHPj. * $x b@iV!~ 1A<'?꾊Һ1^R_z/oG:7R㌽ O51%+Sfu \JW_¿s*hQ"0pu" tB@yB'f|?иnh5 AaxꭧUba; K^i-/;S@H ޟ ^Z }`PbI, wj /Oa?툿s)K~t_/ ;:K'bɝ-NakUZ U3HB$ )\12 WB{n4u,} }N*b?fspc7QA="4U܏b`#XEߵn=E_t9 _?4Tp"o<)kjLpV[ `U=\ܼNs䠋$ u8!`+2 ǓiV?$ *~|z@(@?3-@j Mv4ڏvؿjy8hR?7 Di K+ptZ|視)j{_9=-ܛu4NE¿ `+5$р%Weipip;J$9$dt' K ^fq2AO< JiBd0j>#Ð 9X@@zk uBAzq\'8 =]{_}%\>x.]ZcCvDPF5௱ x91zjl+od ']߿-8q*hiہ:O'XO<ж8!,mL#VT|$@@4nPcYN _jIB{Vz@"0:;C~_?m|=>/ l^1i$ץ>1 8'#&'`{99w č+MRv?>i5 \0Wxc7̙]{ Duܟ wE[ ``\52lpd;~N px^L?ޞ|1澒8v<⎬&H{/squ}1~{N8&7OAK +I56:ɱ\3c=o~8GEoLF柎Ǐ2.-P@x@{<1`R`AL l߈\]?JBs?4"PE(,p>"`v}f "1`Ž `)^ H}|˩ت|O}f_{q|=g( }߶>3XvỊT}+Mhq?T ]K]o>L5P}o)oe]Ͽ:S_C;Fhr.y2" V"@yT PLdǮ|T(ELri (Pa+ hU@1@:}hܾ|Z[@ؗ 1&R ڥޝj7&0? xՠA Jd[_qJÿr~ͼ9 `nϕqmٮ*1 x@ P7L&{+ C@'vR@DU4.wGD3Y46`!N'W?AymdfQl>ځ{b!HGqY1B鿭?~MKC}NO,7)?SCf]3eeA*=ŨJ~r۾+fS_w\O路_C "i pUn2@t;|ʅ+{|ƈA}Դ F@/%1 ψ* LA -[@Z*:!Ĵ}PuuץǒXVU!]x2_9?H~g+&VMӍJ #h)42Fj,6! _vj?\$`%޹cq*h"h.2v2mMBJ=-W@gJmиDBT ck_ 3v]ۯmWmG34 VP`~ c ֲX؏Y&?t ¹}BLH -ekpi%8 ?>%?i tlWe`QE߉29ԊH{cK]][?Nui$o1WP@ND *+J3$DsL<B" s@FHو܏Dpt4q9mi/ tn hS .uɝʮD\lk !A2!@a>$ HE D#t+0#|8BYv3mcک훅cg춳p~ɩ`=$ĔF1c$_NNhW*11Â@h;ب/ ' ON ZOhƟ+wpKʲkm_A=EJ֘FϿ VpoZ \Vc_ 4F cDNēN0 dL``7#v Ct~ w/q%@41h{ mb;`ݰnn^(?N J4uIPz9^ e}&ߖ[8zʹ9Ec_f?:ri^j)Џ[V@Gƶ4n )ߖDW)k"3"W f.4᥁At ;B+ÈX&Wŀ}ߩ>}czGr?~cr\9i+C1`ێ&" 4i >a_3mc0y"q뷰ogHaJ@A{ seY,zyq&q1%$E|zf{N5Yo]kUTPP@CE,9fF)H#S{>8W+nr_wh~Hߗ,ڎV U0,]kT XaTw*k%A} s"q Ƕv} )-7>0d"h],,-W?^FL?YNM U=Я~q WGό~>K5TX? CZ" (L=0ޅ- Bݤ`*ײzpyɢVpR,R VX#02{6:; ÉN \hBZ1 T @}a[̟u`j~<3q| O{k90q/BƽU=1hFlæM/me X)kNةEZ `n]t:@]h{~jnlA衕8 DC(gwV`a kEqfcVrenK" XA M :.O;/% FAS @''?=0 \% >ii? ,U.8?u/2B^i܍ύOGUb7_|Ĝ'DE/S 446`+\ [~ͦu؍w7p{ g69 P1U 9+8 W PlٳsZ`fmM``qLg*OcZ>R]Gf9ȗ}B@+l, '}q <2/s :O_^aЉEuw'Qr}^\̿q *hhV`6${`.d\ Ť컱ƯO0lHg:&P^|#ޙx7r^W nYeɎ%cǓLb'dq>Yqr88x2"/ŒA(|}U&wN@$M%3Go,&DC^;1>iI'5x#Ah_y"/ ע=ԢO".Z7VzL^!w?Y|dx[]>A(+cbƅ94P׭GhP|O|w> XNwGmI/a` Afl(fV l7`յZ5ha!~yem'tTB8qFu4,龥ECЗyzn__I/cC쏔_/$ \G_QwRlLR;  ?Cq8O??C0B&@7hec'['=7I5iR @ G 3.5u] kn# 2^dO 2RS_VVՅ|4 H jޛ`Qeձ'AO+XاB_?mxv &OW qmdRKb}wޛ+Fwv -ຒp[~xf4pnvAَdeTj`Ȇ@:?) |z]7ϫy~VUCKQǁǔc`຿s]_ΕHooϕ73/ ̿*0ҕ2e|`$ &\_Y@Cn]p@6nݿkf|)䜲_ (` T 3@ :Gzerӱ}_׍u"^ŧńRˣl)pe׍ 8h+?GG78n'>lόnT _X&@]`&|m66p! 7]O=̀J$]M',h]j7ʒ~f ,1_Q"4Jf-ѯY0rU}+q<| ȧ(_'~Vo~6jZjjY0``ssg"6+H;(@&P2'w<_f7! /,&n--G6m X#S@wϵ@(0 C`Qo B+%W mqgq/gc@?fD>K?&WK^=OB_O@rH߾}[/ 0&e >@~l¡H(7mt} rg2')P)0sb$9oҭкPw@(ުڍR[q}m08eF@6qKpƴxU)2uhM`%` k+x@՜k$!'q:JXVJE_4K~}տlq|Iݝ7v)*,´O1%|e0x0&-pYxM P@^(L ify;p@9v.?jw.}Յ^'"C[F@W+#Dsmx7)΢S+nʹ3Z'tysM2&u( $3 <`!І(ap R- qv^Hkg$%gP5^_/e-2ߣ4E&?a X?*C0ߟm,0+njv 5cCwE'$Phc`n-֪@6t\~s 0*՜:w>0)Zb?{\.ZK.I?OG>NRyh4wA\TmlLu *.6/ !@k&. -i؋~=k_}>WW YmVhq)oة?j??#h8m]$S##m`eyuE@!}Rt4`ژeDee)YǮT$` ]7  Su??5&zjY;D@qtC 7 HVk$G+b%«E>'Cd*?+d?~NKXTKfȷ&#Qm2  " PYd@7| al 2#g'1 {wݽ942H,OKOiȏ)ſ$$h_`p st$Od(ƙzM`Q6hy k/| 7@\)|ͮ+3Y魼?%C,AO"}Y??gyM t VE$#^(FrM wl7;tw/(;@6*Ϫ ۸ֻ[Ʉ_ϕ1mG)gĿcZ`pMM2_i&up&o:j5< F8`8 MfX[ br P=O֛S+Tl_ PhP'? fr2߰Hs'%]UrC GW,P+D7nsmP;pbC`*O[aĿ5% @_& ȣ:6ґ[}rsN3MkK@Mr7@B,y֟̀9Vkky{SKO_ofCkJD{O ]H߼yso|AJ%oM eXX@SLeр 6@U|Nl C+d˿{_6 :v*^@v_v͟{J  @o 64@#Mw4v8m}fKh' li96!Jy+jov7?Y"o(?8o_& ! /yNmc6? 蕁i.@%-4aDP <{\o~#%Jook% aLs߼IX #B6\:/5LFlTOuot$$Q(; Wnl ϛ+?ɖyLyIۿ0e?!pt.@zFOx# @k$@vT  jgc >'.~zWs6su_ ~w&D?$D??0L&@цHY M`3 4e3{=X|`nkU^?4o[ ͍F(z|HG^i$=1ˤ`4@o d Ntmtȯ lP[#U! Pw#z?L/G+^+We{Wa#+If&T.ీ M\vﹽ[{_O*;V` M~G7޺-o3V@g'_?o?03\d¿05GR&wXn [gG⿠_λ-v+:dG@Vr؟g g?` MyrD8`]VP>Os\0t6@-`.!~2o7Oys??o1G+߿It؟MC5;P8 @fLF h|=017?9SbnU7 Ko87'+\ZK7hm۪_?z?)  +Slpƪ: ~9;ݧvj>k@+\U_켵}w&_@D՟%CbGk$LmU?h Q +1@]րIG?{u;8-2_KϦX|nRn*~9/Gt?46M йV+=j- &| 덳wQ}k$n/M s oˊ2h߰Z'9#I-{ozFPBȈRc\V#t.ȑN]e˿h{k]{rs'On2 | )YKj/?vW+~o[#i¿hJ~V?U4T. _!u: .RW?VBge(Joom[4I+`O˖OfhlrU7#u!NݝH62 gh?Ь߷mV{SjDY&u?OD?wd$埪eZ?~T3*֑^f@ [#EƠ_2| 鱀+ l`yŸT!@@u?suߒJ2P[[Ur_O*yV~9__V9Q0;H$IGdU&@N@`;t{,~⨻tX @׫h)gl~o?'#j#~L˴y`(U ƖnitHcꥍ)X4H ̕_c`fW}?^2N c@~Qٖ\5#ЫdnnP@ m|6xyݭo5OwE[0'ory, ř`FwHr䖀 3sÝNi#@D8,D\ y-!]yk~=ǹ/? ~ʄl/7()`+Flr'?oݸѽ7>]'ueTlG62,ϳ#v^ھaTβY~7 M?W#j󿀪??0K0 C=umU56hv?|vp/͝X~9 o(# sNKIJ:n^Qjh~#⟫k=[ɫz@v Ƞ@!e #!圿n/A|~7ϚYh*oVOQ- ̺j+U*$pjxES6`sfi@Ї`bڲ_/0_tv;ա?4'F3UOߗߐ- 0 Fld],puW@= HMu8ks7`ʱ@:տ[j\wcw㧙J/*vOz | =rտc>`l;`. %hu@ @YG@D&+H@?30ୈc{F|uaPFX% ??\`DItU*I_WeȟO ?_[[KoNr𐍀Rd*@:NLH4|5 ~ܻk/Jq1`FF/[{V^zaPO*4B:OCGrNU2yC|- ZSl'F@h] lph*rL~Vg++'+J/Zgt&9?.GU~Y?UIupP7!*@X@tx@V?6\o56:՟/:?YKͽoogBB3_T~2/\ h @WB!Yw@$Ce7aԹ+@?uhn~}_|PҌ:۬AW[PUn w]~nGUW=stPWl?dKOP?esnY`.0W7#h,`3 ԝU}.1`e 0&@(՟/ZO^{jR=Sm99>tPUp `H`G(u?o4.fs(DX~Kps?|?qQ!\O%@@PZ {/e3d_H@ǂW`c7o&ya~Su_UcNIOv9OѹX 52 cd|i৹, Rr k$@ep# VN^#Scn)Y՟fL3}ߨORUPKo[9pLCX NSc8 c}̚@zИB] aX`f,M(+V)ux>?2VUGEYHˊ?05J׍ m L w!@lm|"9@NK6e[> ;o$aH/[꾡^?<ݹ0fuvK 57 F@F%@n iV@&kjc@ AŅ;x1o,?VqvWr>[u{eDoS%GDY#;/+tv &@ \ .fG@fԲzT5cs#7pJW 3+57A@W?F`q/fѹVyQZ J5~l̴g?]qќ_Ԭ&?0rRcyH!@l(#. U ^6 W2#mHomF  ?Q_ C|oq?{s Yje 9/QCc=LŸ#L 2t jFg%fQ2#eQN@O];7[ׁ~c!c7[?|&lNZGH3WRM+$33 Aa4Bl|iGuȌ6X䋑ZI#`{Q}tc!#(` MNj׫ي9ڰv`}>o` 75OLW yn:p7 $@H 0tFOGG<[9{fn+Z@}$0Dˊnע__ub?i6qQLďd;Ϥh es#/e_ޜ`B``XAb[@Te.mFW{3t ;:];}!$ydQ-3@8u.$&k% .22~[V^K*S3cgg~<## v=1@ f9#3Ga AOu>pN<םV.e*c4U:luz[TT~y\+YN])Z-\3Z%O@?yŪ4D}sP?V$sVA` P Ձe(iPg @ }3 Fb?4u.3}xآ(O'/6>vlro\~rS㌋V@ZՁb,FQfL*8h vG?]=}sVpM2ʚׂ2_76DҗqrOƮ[@ݟIV@#ʰlm :'!#~UGG 3*j Cf6ByVbߪ}.؂-tiM?S/sL# ~+ܯHU #`IFFH 5j:'@^ y7fcG}V@{:˚ą;c/ȆbJ??gGVag 873rߪU~?o.`#@T}Ҥ# 3R3M9&`uG2zk7?W >7zL3@ǔ_wYwnJ/+G~G?kޢmZ$~ߋyX*%V?< #ZH@@fiD9З&1e ԒGGͅk_8\nu?q(ڰvgJ*Jߪkg'Ÿ?ʏ? :gOG XP \_ F20rr Hzӱҿ(8#;i. І%a`uGx [[m.Nxo^y|/}'͓LW*\^s?6S?@n'F]d@@+e#ЙbPwLHr:&Vj87]ݷ,p☸,/w$G[U~9:`\=ioj/[ǭ3j?_ϫf@lsT-~:џfYw%Ilй@ [!9$ O, ~z?dX]W_/QC "= t[O w} l'6~n+l7(sx<@C@w%c^@$nKyuJck Zȟ 7 6 TJyka GE[b[|৏gekGPDo_+y'J{aL*oF["oT͟?$!02t #L@_h#W% Q6;'gf wX<39; _W)}gsPeު}t4RE?Yq`?6B&m\7>/TKZwrr%s¿HXi 9x81v+i0ACOV J ̀jq8]x|?h7[1t^3Xf`СKR_: | ˴5|!/ʟ*ӕ7VH꾘ZȗsRP?͟g|9!0E3Qr8humIOO-ɚWb#ىdV@{s"(Uw\Ji`2-ƴz)`K\S@ !`}m2̀ݫཱིmGC hC}@zՁfa Bri}FwsB{7D"ZN:0$+`$з?D/uGGf0s1J e$#@L7-68?>K,7ׇ_MwC ҁC Ch10>o^=WW~m# }@^V@)+ +`T*,*AP0* wK m\8 ۫ob;ah*L``ε+ ԘM'?FG'gk#Dt~oY= ~$ 8?z+X,]X(/#g"n_oLWz$,^7y{)Y+`^,3i?W"`e3`aǔ1ճX*˓obVS0WL`ߢayOK5cN՗RD}.UЄknJQGWGB?HkS@oDW~:WBk64?`Ȱͭ~æ߭Ϟ=kǏ7z? JZ@T&,m!+@ MnnU"`E{a1`&--_h fA3B=Fsc1{{Yvpsj]sJ_}+}9/Km~kLJu_d_S*3 @_-#)h*_@; XHSA-0}x$͝k3'wO?b?oz(<>|]w6nTD /Qa˥'QuK~̀ޘkH@*3բf + 8}fuAeヸ_ߝfWFs{^ڳ ` ȹ hBq༆ZC6J+l_WƜO nB\`Pٿ'/EQc/CS"DO_z)zL?wC}ݷ ln'_O5K,B!+SYe2Rf@P aЪsV7i*<:2 @Iȩ$Խ enQ8!Lgd95 ޥF[o?W8m.^s Ie_y"{n7/c-cq0NqeXn7=._6/i^>I&W֕4eM 2Lhedľo@P]z.tw___3팓~`S w^} A yAP2 yŒkkk oMks\_MP)ǖkXM}RQ_//N.O~/NĿ0 ` $l3?)ss[5ik!3`nFk Jf^f. X!Nd0 !nK X*%eK>/c L[^c¶\;9%-S0_{&DxMW>s}MT ߣL7ߏ~)/N/N"3|z_D~7N_ 5L4+#02r5AW,'$3@1R@/`OZjp}p"ẃ:C@ϵ8Y*l;/;Xc !}5A)!#/5 j @SMG ;M\o]а0@Qj ctrq%?OM;9K59/_D_Zo џ;gckF 2ViTy9`ke_zt`m0S_b@*xtjA2VsٟWM(/Wu+NJ +@b/GWG/b!_zgR; ~7_Udk?Dׂؿ6<џ{jEtqejC I11Qπi%126fɉL3F_2P62 b/)puxuvsxS)"'#](gU%!,b$u:>xS_FXJ_ ~ȇqzgZ Sy:#D;گx0\#0'џDe$kR4>e g@1mHfP:;`_&se!S ^ `9eϓ)Β)nqI~qrnAK`(#xk< -FWb?מw`g}`cߤo~Yk䷋O_f'A ^^`*1@) -[UEΙ<(߮}OXGܾ w^^CEZӑr_JT_ O mZD^!"~ c0 Ruv̀d!{3<%TE5M(P@m hs`0B4gi v x>OlߪAqts:Q]D6?^sOYqDK~wQZJ/~%7R_zZ#006 R/;Ǎ; =m&?1]6`3<3e8@2AUUlHỳx;IN1pmV8+CoXΖE^m|-.?y<Axmt?+ea߇qھψ4˱:_/">uǹd d]Pۇ@Hmm{6Ro9{+擐< 9\+A9!ٗ9/_Ż3W"ފQͿ=ω6/k<`ב{7/B6qK_9N=? c3 )#&j_e4*K1@ a(Z{mds #U3csnpc9_!D ?Vi,*~+p%n 1lwn;{NF>#-̃[hWbЋO܇ʨ}Fg Gď"iމ[ -Dg~?<–g9)C@0 @z\ʀ.p`cFqc Mk" :/%|[L@.L3{7gxߎJFJ>M4_{՟2zm^Gu?5 N K댍}D?| @mj?2! ! `M%Ż s m ;{&*5f^[?%0(̈ ;e{Y^9 г_ /k1oL~_!%|.c&$6? Q~D?3`+CT. m5 0d L)`l7؈0h<z=Z%E30ǹb1rn0}9QZ^6 1ʜg x怽mΙ, /FqD|s/+4'O=wmnkg\J}OW?b0S0:S`Wc31ϱ&'m/ݏ'aP#3?۾f\h{%@ƭe͗kע  , *@g 9s@VKYIXԊ|kRm B @-K怜͛3o_Gz|{6?!=>G#0BYN@93xZ 7w=7 b}BD{(cxDxZ$m}O|+B)gc _6^zq9Pcx&7 ukγ}$sX!.K 5F{ '_}Hmwș9 g͍5rSfﹱωVW }>`|0{>B(ș5\! Z!?%腔N>D<"0>ScF9x%`#![|_ `g`f*k طIõ=]Hw7>%W11s1 C8-o```````````/E߶,IENDB`gottcode-kapow-350ecea/icons/hicolor/128x128/000077500000000000000000000000001514263554100206455ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/128x128/apps/000077500000000000000000000000001514263554100216105ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/128x128/apps/kapow.png000066400000000000000000000317701514263554100234470ustar00rootroot00000000000000PNG  IHDR>asRGB pHYs$$P$tIME $@×bKGD3xIDATx]|TEMOHHB*I4rEbJBIB'&]:HHGz&]b;o& oM~>&oߛ63cL\[ p bդ4F%NmoOGz]bsDFF'&&Dvm qy常*];}*ڪUTVW^zVvn>A DqF*UOLD y 0)`te~ }n]]~ 2 dPd{I < g+ZvʈFH&$^I+W+vl>!9~oy}+m_c$8LpDQ~X|H\tga7W ųLb0P!^&!B+4ޫ/h+D,x ' N|.@~^wq+xf􀕡=C{X!Fx3n1@ɤls%j+vؓvVO{T#@CgsnyE31 cqGC|a&|ʳV("QU6/Zu$I1A *p c 3`,u1V|Z3#'8Ի"xw^m+':q!9a^GegcEF 4f=i.)48lz{ ~w+a> |rdwV!iaOd80))b> }Ftaʋpʟ<B̟#FvYsƴB/D9)ΈМ07b"uSCț)>U+Y~Ͷ_8 zJ!H~~ 0ǀ+iΩ&VT4 7CZCݻ": ~p\1aHs"7I,xNu}wm+Bg AD p4 4\fR_V-_Paۅwe;BK9; 'D@8.Ÿ dbڵ$ ޒS n[g)#8BR8&8 b/(U] @\3yg"$:)&~pDaA`1\ ,>CPS1"WE7P1^~S GTX0eQQO?㒿GH$'ఁL'HIw7/5E͒&PCqfcXco|p Ŵo~乞!#p 5fRi1AśPAxGrkI@JP{ $lEeD:uXY>X^<6x`6tPVPPFFƌa3|k ӵwW~:uXT(X-i,3{b^&Xb"yJJ <ʠF2'AJEu` !%d$~ ٔ)Sٳٛo.\Ȗ,Y–-[v3|7|6g6c [=3fg$f&2{/n>$#6ZuL :<hLEo|_Ad=$#eds;v,:u*'ŋي+oyi&e۷]v;wr;vᚍ7෸ǢE8SxVV,ִ{S>[__QXJfHL6I%x'hvNK}-z$ܾW XbD+K%7^t)[v-۰a۶m۽{7;p;x ;|0{ٱcى'|=ʯ}=p/3͛ǟg\`,U32m%{^g6?dϟp=~{^` π6v٘9s& ]V;ʵ$sp9O < G8*VEj7LXHVkѳ6 *v{ݺu\:AR|"B_x'|O?]5ѐ:8_vDž;X]X"f)X0& cLBz9-.$k()Gvgj+t﵈w^}YjT?[8fP nvy'u6Dx0E<a[JBn*I7i,=+ 6{ ԁP S=^^ABχ纲=1AiĘ1v!g0[IpKllD

a#ڷo>{QSFbwo 1sJL4Bڹ4v>vɓR{rCO! 2K܊k Qs| w<+m67A'ׇٚwӦMQUaRA|3«n$$?~`]ӳMoQA alƙID[oazb>|gw&qM]嚕#4,)pGj9l=9I*эD\|/ >|}#17 v|.oيϝ vK4FX+Zݎ ܕ~&"Dv#2n68#5Ĭ^TGćʗ^󪪗W%HYy}ׅ O5nju5VZdh=3m bp0oRT8UDil+  |F÷oq|lȐ!XH#'oToFE?:n]_qf`??{t/#L|;6 Kgi!gmjEI]t"oԔ/{p`"=JH~z ~SH-=ݯ9g6puE'0C wިI;Dh:7rh˶_4t>[{K61Mnfs7#!"#«Ү]u?_/\!5 $0As؁CcfsҲ$Una%фhs rg"kIW)h6 A,w:O FFO]IJx3K"vgSVfTf0jJ1LysGR;rBx(4jDnvV$xo!`6ٺlC Id۷J|+W /pr%-Od.%7P?d0 ʠnt {H)̪wnDrњ bBTYJwa^ ;p-C1q TH|WRH_իW,dGf2g lEN!BrCXQQm"Goy1X%\= U nEؠ0qkާ9W}pCGwF|gW. kۯ,[LfLpύ9#i3&x54:ۨ7 `QQzz7p^.gmڴqZ "D +C -:C]va5s$DTկ}3o=MxJٙ]JwL>1kDhF5>V XSH8@P> EVaO 8;h7S9|eA/>BFFآd1AQeE $Ob{.4e*wE `E`_}Xiĩ,Hha`/ohX'X+Ҕ#m,O:lNAu|5g2ԳB|O^f}2K_cF6);#u.LA֩,!+6BT -PD E"gfTaTrok ֥?h4pJG̏fwdoF|OIj}FWzwk &)96{hdH 4 '?~7q\-H1mZ4&m~YSߑݿ%ן_XPlC1 v8a Zӯ8HMk{Y`Flh,pbߞ>}>MX#n l^ ofoTm\.~Ϗ'>^;٩K2He *9ء'Z | r\ p=*|)izH;1 ⟶]ٿ5"",X B ĺѽ+=Wߨ7ofggz?[{}kv##Tl[ѕ)0j%"u|_ww9.9ݮ$ܑ}ޖ@ W(iې86C>Zeܯz_2G'r!,u"_w3c߹Uq1;N-GjF kܠ*1fjBضp(tj^ j,J!9KҠQ_uT_} Ē$1GYLÿ(K4VN|zFw \ƒ& 'zINNI r˅-p#C6K Aþپyhr ~U/{Կ;~|QcFmj0-UcfUl`9s3RLZ8"_'xFc9Ѭ帖l脡[8p cEh >Q%b/+ >d y =΀:lȑg _VԿKL4ɔSؽLrm>੭Oqljw`7 Li i-9^C{q' $ >ͫ~tX;oʇS|Fo*[Q GR\H qw.E7/c~~V lm칡ϱ\*έ#y"mpG~A`WtLJc~>xV-f3G:',B@͓ص Y3;F ~*_ЇeOf_t;Qx yF70Zj^'r g1-s\U.T3nܹ3@j^agYlXSEf7цP'+$ iNfu, /1s32$Grɺ*@s |1p3iڢ4\_ x%`7G.`x'2,(j$3ؙ1`->cu`KGɒLvHVTZW!Ikހ˻w Pf22ɜs8+  IE t qHK7]N|hCa lw誯DzlG ˾%LGtm $ ݤ 'CjNa, *H~`<0_4ИI ͘ߒ1; =x"V:_eUkOax&28p!g #oRW߮8 4cu = ZBͲ31hFs\<0,a27ZwmN 7kB# /DpZqB=0E 0]H;\_H[f=a)n4k M/f`M8&ۘo_x~I^%12x ,LUz Z"ֱdP'c-_Y.@><Ք)|`w X,iK|2h]=A,u*Ky$1;}}= 8N p ,Nh+Kaln\mY8M@=DX m?DΛJǽxAk^2,> `> 񧸀`3 1+%<GX*j ˯{[_)1Ӟ@,+H1ts@RM#h\ \,Կj嶴F:H_Ù}M`wKűÛ՞dP`!Ed)1 *I[oIUߑwdkHnz.fU=4K9d Oq-$Nn@IւPOhI#/Ȟ@F:*uzih8 X^*x ^e~͎hiDK@NI5xg C .@UF7K5V0J&'%^h7$HLoh$i LRn AG,+/A]&ʛ)0~cL).tcнr{qr'|EKyK48JGPT/UN~Xqq@Җ͆6+JFR k+8%?')=tk"x*}-Cnٯӫn#~)ODYz+7~W@R*Ӫ8AT+!'>*پNw X#PD5amF@ژ ~8 @y&$7Fկ_Mv_oЈhUJ `BH w_!9nyQ8gB(Cƍ"USp37Jxl@?$T (jNurףR5er"rhרQ#Ԡ| Ҵ4+7KV*]_U*UoT("i\&AzoaPmtux4ػch/fy[- YrYx^GFfFzg7jNnW_~+Gٙ-D"AFb(t)b1D7Uo$\1g9s̷U_'$%A;)U@߯pz/^JF NPPOqEx9#>[1W;#t拸a{#a!,G kwA{Exٶ,&?2/lLIfc$JxgW>UU˳Cdq~x;AІC I4NK+M|C ͋csy]CQ!7(189gRo$|CȇnyhT웱z?B\ m@SCc;JH<"_B=@U*&IZN:fƓD^n$}!79~&' ؞]+jv?NG z,hAo;.;0Xw6jX+ *R:H8c<:V=WX=\Z%$>}iYEGҜ1w?w]֏VZg#j&$'jA tﳚοh8Iȏ#\2;<#xh/^|Y>x+h&c\.&Im+V%f[R8>;&&EG  *Pöꏯ"#Dxʍ&A*#說7cRgI(~a.G*ެ4W7&&J\ʿ)%:  HR1|6T,`d!Tlo#.^{)c/>|z՚YK߾@! pMIľf[ H͠ڔ-a`^1@2-[2d 20 P6#A3fP˱L7>3HtiU%]H=ƈ"Asb+{dʶ8C>rrװsJ@DD=EQ1u$b :uԑLd 6E4H` *Cw9@3;)x$<$уԣ>ƞ>8υv*Dtn Ƕ+wEB>敬|=jq'!Z[10ýW{s I {T,ȇi@ADf`I8Qv)g5wFx) cBfcX1fsa$Gi* YK8o"2~~Q%f?Sc3 )W U!|4)Zc$3 f໒3!kڅ[`?ߖ增xV {8ۇdzᣠpK8~Z {?豳Hݽy굟} 'ҥcvUXt="-@A 44Bc 67-{DǢ <FhTYRE[w%{?'\N/%e\)5LXbQ9,1%> #PVHǫ,H6{`6w0DCD}\1)ZJT3|kp-T;~{^' cNXQ0ޏ?Xaη >~pڗW8znc`$V=S3fW׏bR1K;7YDhR#mP7.XV Ռ 6BHEnKLBp o@p= Ɵ4?:FxOα~؄Ws mEEEES)SP# 'H7%Mp <Q}iBp^NO :+$yx{@;\ksWhpygxJtO+Kpfof cNqn=I|3_0A+x?F>z…l^R0"O kzvx,fM K^R榰:s3k],iI75׶[I{yp.=hj%R܁K8<}C 8 oCZ+޲8S"!{V :mUv9;M+Y\q/إ1z՟%u?%vkQ.@s!-ٿ|gE xiG N4Ǚ!!\uΰ2U_e1D؂FErdڇ֔ƭ]9DN^@ DQ5&z7Jqrz7!VV8Xnd5Yf,5WI{%ЄqgG~g1禤O e]a/m/SPOC#<~WB{C?9#Ӯm'/{k9 / i0 V)s} Q"4 .k6׵ZSc_K)$q"}0 S+D!}mgiW⣝:_ɜ|ME'rK v6[gnqeY2>X,%JZbS4|s١FAwӴ݂nV<cb1 Q(瞙 ömalPBO^3MB2%L hCgı.M,%2 WqM柛@ @Ź̹h:=58hJs=D`&Ξ9 1670$./sp!vQ7'Ff9- ij~. YObme 1t:?$ iEkQLH)F b僕!Pk  m-fԍ/kJݫz^pCZ 0wxWI{R95^>1+c !DG6|HZ{֧ 2"BtI9zWyń DCX[ml ŕ w/JpʱlLIPH D -ۖ*|C;?DWL ˼2XߤPS(P(v/;wx|E"#ن\{R(C &>i˕"=\/>c>=(y{)y* \`˩ʥnE 4]o46ZFBVqSbbbk!PR Ò=j{|vѹ߰Bgr5[HqAǽ# hlޤfg[f ?Ϝ ۲1HMM?2>?֢[ GZ ܷ2R{K4Ԑܪ܈ZBCnʶ}gђt0_@7oX,Kɓ9f8ggN4Ϟf-YIENDB`gottcode-kapow-350ecea/icons/hicolor/24x24/000077500000000000000000000000001514263554100204735ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/24x24/apps/000077500000000000000000000000001514263554100214365ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/24x24/apps/kapow.png000066400000000000000000000027111514263554100232660ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<FIDATHǕV}lSU?oY(zq I0 I(h?`-IAѱ@&FDƁ-LaO702nr{s- "<O}xa9=H7$rgqqQ߬?!Q9seRe3!>i):5nqV9HH ݲ4Ul|zMAĀtFJJRo0D8Vhsޓ` Ot@$eP716oټ[)^Scߓ0(7ɝ睶1 OZsO @smq[-ҥKtIf,*Ľm{QV)D@(rvYvtdCAH$h5+iB_؇jCDF5*S(G#0i 6 קb2t:_g"Ɉ4A䯅C#d,u:AJL EB de3x<Ǜ7obfDZ%$ $N#jۅJ0];O#lY% kβɏ<%H%s0`o_þ===D;ЮI4ydMSwRF' so+);ѯ%,(wס2rʘez;86kDe6*J,,%O~.*H*]]{@u4lmƭF?KbN\K 1 u\@>b2oe7-Ϣ(PFz")5h`gPKby(#>RSX/";uD5S)2%yk)s.Eo])Z|EpxGUZ[$W Uj"Qe %V.չ@W@\WEJw}2)'&er-VaDnېЌ>u1?g^v,N3W_LP./G6nڸKUd@v894Sn+/<:ujν3?#zIENDB`gottcode-kapow-350ecea/icons/hicolor/256x256/000077500000000000000000000000001514263554100206515ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/256x256/apps/000077500000000000000000000000001514263554100216145ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/256x256/apps/kapow.png000066400000000000000000001010571514263554100234470ustar00rootroot00000000000000PNG  IHDR\rfsRGB pHYsIIEtIME #2jebKGDIDATx]{xy?tu#ljC.&qB.4$Ű!<@Mȅ4ᒍli`{.%@0 l :Ķd[eY>#},Fw99y\2EMNҘ:ԡI{(u(uC)uCJCP @PR<ǔPGmZ;y__4]}MPssH߆gE9R=Rof s`gvx]3f)Je2:v8nZ^p{p/сwPI1(e:.eVXXl\]>h \.' yP j$0_N/ g'H7 "q { =^"E+l6F]P' uB6KP=dw<@ + +AKO$8M jD5iD- <>/%i3\9dĺMC7EF6DG[bSRץ^2,*{:ԌwTFԅ+zQR0eʔRI!(A)c%7x: ΍DMr3\[[ѿ5r8򭮧z䙗̫gg7wW;'bwƞuH|maGF5܃{OxV/eQTxGe[ H LB Aԙ+)c͒`YyJLT +p띰Y0(qGkw:::qճJ_?j oȬMyr-|mCo2׭(e弹\ 7jvF.oNꈺJ mR@6R h+ڌ<<|ށ$jҽŒ8^H7H`Eb^:fxeݡgBϞy__4d-}dH{6]PRiEM6dN"Q'[~F%heJCC]P' uD]O_m<6m0j~JG '%gW xVC C,1 _7_X{J9'I| d.mc=|isѝKqp],&:0*)B๔s)sx\OwyG`xJAx ^{1R_a}"/Y{xy|i|Y<|OO>{OgWQ6Y_d>. *y+6 ;pgWw/u^Rذ-"FJ(E,!19zVOBYs٩yBȞSS.r}Nney 8_Ā FR R{>x : \.}F)>sD6SA!>97;7籞Ǻ_K^sBp`/Oc 3W~!y^yvVvr<<oPM)~ 2^ 4hX%/K^xcڀ!H9$KXxhB/S<5 HbnA }E<~mc| %(O-J]}C'G.o/_$ܬ44*ãczyCq^zXiEў$ Ww"4J>yY}LA!?A]G~qdQ!/$ȹL)30.|G<k5}#}lKu zhĨ" Lv`p8HWǒFR͉kK:x^YJ&+,7q^;"WaMs+zw>CQNE_c>*?04$| 6Čca5l6;єܥs.Ŧ1Zʂ^[W 48DQC_R6o &0fƑ^\} +MuA,i2yL3}wohbA1矌;tR@ y[1}.d L EMt˱> I>ri-~І;w`xٷNVfl|+bYhFGmnjBy7Mx%MT SoL8H`˪tCHcŞ IWb,ͅ=Dx)>v2YuAdؔDDٳg ? y)ܩUC/[+}՟XrX,r&lJ܅pdrq9r\~e'w~JB?z2C!T9$Om& !G?1-']='\~?++?yrnÊ3 !+޻{Q}!SӧO开R|1M0#ӐCij+d !AΣ%dc(J@U3i.qc)hf~faPprYqxO컧M0/Z|V9Qi3b ?=?teK!/\Q@9y]A!a/ S-|gL`bM*,SMG{4E99[Wݬv-<ϭo@8x@}OgDDn ۘ}YKS@~p-z Oxx?w S/^|>>Wvo^Dx;[M#YKYz-u}{ smDVCD 8\!s};:a%oTVkJ@219O =ڛ:E +m#-rj5p+9gm66ôżc|vj67<x<:w|$(|z,,~1[_öyzF:k=Z!|]0osJ?yV)w !:ȦPЪ# ЋSݏ-]o\ϴƓvrГwآEluewfk}k˙] tFs#YQTzN~?[_uGW|ĕ#Lfajq 2G),Nx2 OՄUj?2o! ?~?wYiJ-IybNXE>Kǻ⽅-/do dXe^Ȣ.?g *_( \]RoQۨC(J&W6C!P¯EaٹF*vŮގ{TsVVc~\aSZ[Xh;6y7A js] |2ePyd|7MI[.a /aޢ@mZ[66mmϵx 3JYΫlz"9h/ 0$d2J2 YMl+p1СYVf0YX-эz/s"gPȭ=~d<=&wx^-@i&D]$ }S]\h3EwΫ3CN;_ED]}W_av, %ЌP F`7SYl(euJ|BYP!T :o#sϛ$d\5!Bj|Ez3Yh~a''1[x5&J,>o)m'XuulW.vzw,eĜˠ-y%` 0ˠ"JSV9TR<9x^ryxy]-'P\//[Ð |?QZu,?N:OI_"%g]qVd;ޗB&_RcQ+[_v8w[=u, 2IRʈxZ$D&>;tw5^(Өdp!a\qD hVV~ȇcJB ӆFC!#d2.& ) 1Gr3;w1E}nZS>}l{5y* leuD-@l~[:oWE'|9\\.Q)d''gQmB T 9n:lub‚Td!+N& @!t&&Dj*zRˎehƽ9w,Ϫ`Od'%KFFٵĿa99y're0VXJǬ',4*T"5s1eUCg?76X7$ Ee >#{ƉE",&w[7+(ޏxDx<`/ ,?lcx҆QjP8C.Dnlٖ[l7G̬-w?'ez]mP%~>SdYS VIX kG~F.K~mz=E7?n$V NJa@7*M#-p/`;yn NJ>iswARt ,)".AA BP WTהV*VJ%+TRǭ\I,$YE|<dݝ}qޯ{zvg{03;y|*Z ʵ?~, *&θ$:rj):GU9 ;pkVS~+yΝ{A|pv+ p!N=G)7J~퇁jx\}W7^ Z+21Tԯ].hN4BH ՘ 4E{/im iZ0bEWz6w=a6UmpPz =k)a{h;S"5sOk3}ZʌIKEGKXV5=`I罝L@K{W"!Cr |*$OUv7T|xFqpW]]Tb-TǷ_ۜxr@@ӷ=mZ?#@:}Ù#S I=|gSV# ]:^ Zӯ%Ԁ O zu0NsIuƭɍ! jS0W6sF>67m۠.b#om܋4.3`Wй]@ӖF8}X!'3'|Ɛ(#( zug͵S]+fеG"`A5o)jP~SJ߹\4l( _KW'EJz|łNE;~›Ϳyu~𛝿oLT'wñRw$}ʖ4$Z5lT6Q娩_ v݉[2#pFr 5bv%k'a|ޒ\^SP{nIO^}`Y$ ȼ"EZRLpr WG:-X/~N=st~VN#H~P2cζ:$+]ID4=m Twk-^ROCߤK/OJ'Z|bL4q؟afL_ (Ek]v+Qa^>l?H;;z$ݑVkxt?4z#Pa3Ҿ}eCىШE*A_BӉE4=,^mk6z)5u\jlՑM JbsE2ʍ \og0fw߅'' BkxZ5eN׼3z׺d-Emҋz(K!U7g&Ml0j\$oR|WO^.ַ}/Z߻aFzCCy|qD:&Vͯ)1ƬmthyA#٩y x ޟ?FS$5P)dlcl7ă{9mgy 4EObEzGAwBUU64d0zqT7Y0'4(lkףoG*qvtL_ ~fr|n^41K 7΅uuZP# K(A<@ „%X un?jh4ǂtKcWG ̀c=EE9K_˼[y`:FFK2 @k?93`M R`Kdla+ {k GAwe=C2t 1s Nյj^j}PmЧN)}Z-@蒾f8 {KャY.0mO{Cj&<OکT68" T`~\\ Nw@ cmwp7 (dy'Ԍ uA%k9 ؞&`ΟU껇Ng/6\rQ[)/NGrq ~7X!9wȜ˃i*mېRR= v;j5ú:m%}H ~np"d7?eRbniL zt,,JyWjU%ۆcMz^ckiF􂱂,@'̈́!E+QRGIսwϠH>*Ӝj5x^t^gxzcYgo{z@uB:OOB@ m²VZ ͙f-#Щ~V;={",L–ZPB ̄̔ Ӿi"uHU͊uLkCSRILu8 Jo Jq"1,̀Ԍ d%N"7:v1,1'+'vr?Yt]?EE8>nbz_'*acӃKPCm(aON&AO7XmILbU|T%jqXX.-/ֺ9Tr8Y[6@{{ Ċv;nvh g~XSĬ M$D[⼫z/ޅ(V/5s6fD|%A*/HEvC:E@ ~/X@vTѝ톎~M 2 136ͬJȻb2? Yb0욅lܖ-[e`'7WOgZNφyyE_nNrH௖TNXC?PtrMxj:ލߧ5Dk9nakk|D(,9- b 1W^y0@'7VmN5%54O*6hzWl~^' pX}+Wh:B#' )T}\Cn*bkaFX $0G(J L~SGfij)SmFu+1~ޮ_= v6g7,u3>4)ƺ6u]@h 0J 14`=$(Vee!T:/z?m4dM4HJQk!(SV\*~8{..{WbeFdh#8L#â9oFU#+2B?oM?^ Km/8:ɧT!(W(W/۹6r^gpT=j2ba[GLO@[5|_a *d^Hiɘ񕦁~yAo?g~#~_cދ}դ(,HA\l"Ek~1%w)@# ayO!Zh>E06>OTV&~VT ]!ppBkutgX?E>.i{ pDB\[KKZF@(fsf)a@Ŏ?THojn[E?׼4B{Qx~) ~-W.0j~'// OZcQsמ.lc0aM﷡0ڄ+TH$%c2F):zZ-b(+z|+)Z%{kA G/^`Z3" `\c@Pue oŸ%I,#G& 0O/(4'Z*O8Ŧ ŕ~n)oC0b}ߗ_{mp6xh\;saM kO>,lf|f^9u5OV8GcKiӰ_c%/ےm D8`;_N!gݣ~sXLdl°RnV C#^?5\u0k q_O_ T%9gΜL&Y}JOukpGPs s&z"b|fZ2ͅ@!bwX6ݧ2w?x;9/qK=lMg`耳gϲƄ+f{ ![BRD(b,SMP֒n=Nx3SiǁvF3(-ҪutP[Q ;I:[{Gh8yy_~+4)迗jVn/']QI'6"F_y j"FGD;ct;Ɗk'P_=.2qhĕq{Me*zhu>w֬ hyZa <7AvIͺuuu|_j/SH4m4!nM A"C 0@p.p >rJ:`KBQCH'#xWVV $.^H&"o} شu,a6v/Ϩ30oqK<繞c<(uNsR5MSo{{L'A/  C< 4)IH@̓0 u m1 e ʵ"*puTLVWfx D @T UVQUQU1'Ϟ;iUe/wDKg*w<,Ϗ">N#/Ig,ΜN5*T+_~9͚5Kh⨔rǤ ALB,_{rAIv4Ide5 _+gr  C_שʆъ+[;ฏ~DiEA?#̛_?@#8HtwqSzFmm4{lT;Ȩ I6E#WV_cE'F%Y|T \0M O'RKH z eI-T5zIh̙T^^.džGвQmmHP0Fz)";p7b-j^D;iaB?B8^3g@]x$[_$zMYYY 4|_TR @" Lkc`۩$\|U.Qf4#D$]%W-U-q1y7hSi?gn6g);'ziۨhַF@ET-Z'0*n`}rDP :*S$s >'v PoEo0h`9_cBs-Y)rƌCiE *p<='fY L` M´/d7gJH6ڳ԰L~݊Iya<=>nVMXE%~(Gk0V>D)hTYKBy2 ^ea`^8) r4be@"H@M^f? 5RR˼edT>g6:~?ῃo Ep`GDyީSۭߦ;ZU)?7_@&͛'(Ɓ@ Ų&A,S( +ѱο;TA":r , Ɣ468+lY6*-)u h3 ~dq z$śgG4;|MǿϳR )+i 4w\x7nW_}푭lu"sBnߋBEjaC@EIی(.`IoaX]nG׃.K$jL@0c:n@ڎר:8b kwd!7Ia ԿO'tW]q).MyBCC5@d]O= F!O*L@HqrGɯLnib!2 \ppG6ٖ᣿~A? sT`+ ÿh45-kDsAn 6&L lz@|h}`Jv\0*@YHIaSy,`S^ yQR-d@wsD |!O? p>\9HlAzCY($wt㧏ӝIu+{OwCH2]We8T)Ze=qbdAE9dOҋ^}+. mL%76dN|4p`nG8+))1 1@JO'Nd#rNPGs-Xr{lT8󂩍 4 QVzOFHu9wG[BEQ}}*G <_G+-ͮOBYrY$sZi p[i'`qR+w鱴 Cةy3i&/9 s{^$ԯg^~&u!Cb}$N,tB7u饽/ />4?Bz睯4Z   $OaN&+n3BD qU`k@ٰ_g<I%ej,iZ!!bA^?HG4dL$7"~,rh} S%rFfNe wJr,h4ڐh4ZwXS0YczG޽:p:{4JIB/E_O@/"}zzGV0=,[骛nqlj὾^0oGX)7ц twӚkhY2Y9jrkiHͨA8%wo^y6vo#O\]wo`xh4Z̀v@C;Q.cRGC P&:`NFy9TE:=~1p]Z{)Ք3J`d~{>M?=H7O=ͭ+2ఫR%(up!DQ4i:-t)-d157F9݊= N=fi}=BYD<\=WJ 1 ؂/0`% P^?Y3bXǙe:wWСOс3"@#;#DO… ih"Zv-u]! qaglX[;:/%ZȂJ^Ɏ}+yCV' GdT` M1-Ua?@bW{`X9\EvE۷ocǎ ׃Z4\ @(>*klcՇs(]=eHk}[rZxR4A?\l:[LnZR0OԉO:h! }HxRu #sf@}ŭsG]G_61 r* iff!B 0aBག\"X=y5M.,P7Іnt> Ɋ&eΗJ^QaN J7܋((X}r~ˤ\(GG^ a&SEtÀA/>i)ȴj#nwiyr$iAinhJCV'h4]TO<ɓ' 3Cι>pq<ê HW=߈0KK51~ z^|2TQ h߅^Z8#,IܣY,yTD)Z,dm/1&Ϡbg8Op [K VI<<\/BE7_Ӏ_nT#8D g^񮡖Cl Q&u\|}?x]=vr6b8@(Nj X,~')DiyIHg"u3/pDM> ݃B㛱>G1|omQ"P.upd>W)=!!Ns]S*yw:8I^U _@?p" %`f i)*b ڄYyOtsu)= s/sP/ >>7VU=΍H T!T€ڐ  !G!URe ڌY(g{-vDv gQNIVWB #=\zxB!V{=%gʑ#ڃW^~m4`!E4p#(d坷ZV=p< 嬚F "QBRqؗMNzC&VbY`>LԣaOfm2_* s>Y'CBF- - .ti7c.h|!{hZH@&W#sO4GF.OW+l888Tr @U "he2e A(_1%2YO}}6A>7F'gƨQ:(i9h!(G\'\-cUٻฮ*{ږd=e'N9!TMf<~|| `l'@Ɖc+)lĎ-K~ȒCݷ{:ۻnwXSuok>L3ݘAw=+]/`m   @\fU)@n Flo-\D7j!&va3zᡀ7h[t}#Y4{F;-g1w>4.VUH (S Pb 뢪))\q7ȓʵH ?&{p~2V?!Fdk\@匏|%/eRP0m=y5EJ5؊SE};AwݑA+hV{yOg;:ofᏖ).]7ٻ63tur "C=b~9rsG,F z ^ByxW~?漝985*f)5}}s/@7[Chʔ D>qb N̊Uc@f\f.`Wz_;V~=N서=0[,ly<XFrpM*˶Z ^Ov@R4rT{7-o,$K/+(NJVNPpx;v ެCV+9T`@@BqZg)xGTQz,}X`z!N{/X>hb;lz94xck= t:l9rJyh2 3p (N(x~|^dḼkKr;}#hq+nt3;u^ ~ؿAcfߵ}xύӏ![1ǹ+JU{OB硃B &%dDr+hQ저0FI}Dڱ?|N /7vnEj{F-3ڙ@ [窄\-cC*WڅmHe}I""_ٱGTvЅn7!?߫wB&wD;Aӌ?: 1@vk4'M !lwl"e=P' d`(9c_ZyM.C+?/4S@X>?>~]%CZwt=AṵqkBiRe6'GN Fe ?-%g_7/!:_0=<B^Hv?<+뵊ZAefܯޔ ( ;D5 3R[V.AofF?-EUf̚b(FoMsP>ID#xbs${F RdߞSܪ6Vȧٵ9z3~D~߱=1);,B QE%H4E$ONr#]2xDOgAMmcU,G(Ysk8bvotڝ1S~s_~]Xeúҥe^qE;|i?'UH a S,nBC^ZSr^lS)?/q?Wz1=|N:d(,U:;RXccDBM$`Qo3P@"!Pɽ <bF@[v,5sdF\,F<ә#"!FUPOH?+b[v *CJ]& O?бGFEpP, @XlrdCFǘmQ>^b( AcsY* ̈́xN5i_;6SO9Va8$ ?x,f:xl 3t27{Zy6@&b#1[>3!ծbu+GBwKe+@:hHQ[n5w]ZluYma?7-.] !i8Nnػͩy"kC??]tϫ뒬BW9S+>y JE"%He>KiC3GψC7j~H##];^*@~pnۼ7W~h,Hх_׭?twݡPTznP6{zoPECD $l#`,W_{nKA#xfLbm_޿ݪf{1aާϛy~/_CVzkW^ ?̸byБd,ա'KGA .(PoRIcRNrZ}iDB삸mݓˑe)(FN<}/jg_ZGO93k&ǚ+R$O6vAD׆nώĬzxx8D(ʒHؠ^fё;#orP=QP8Ή|Y[u.ü vnͤڷ 5hP|XkyAR8Gn&r t:T$pPrd dym4:z/7/';ksia/~7)N=yJlmo0-CZRB?L@+) p;ZX_;)\*~ qnc_b@^/0[Nl2ҍSwS.7S{&yzs9xk5ܰ.l+2K7_n"t?O@NAZ$'#@zoJvBj05;DoX֤PEG84x!.Ͳ~+jrF@ [qwSl{y7^gz%oZl l1a2f_A(&t; H@j\h$EqF ѱsHTMR[qvcJa8\/v̏;BNys#Y뛍;z~Fa 2Rʟ*T;c$Iġ# 'UMB -6lM2#P  X+Dm!!I q}#LM7܃^P3WψgVߣr1^ h4&wZMX:a W7ۄ+cBT}( ᠏U[^^欄 Iy(-L O^%Nx믉vod/tgOj9X.@'V >\p :{8ʨU m;Ȍx/( ԏyj;eF1J}NSdJ<$>ﺡ^&m7.Yk볤D}~== m.XbJc4 G #No9Қ]F:CKŧ_oy[$ x(!"vn^CŔ_:>϶6ݛws|Irwy}X\IVgupDGA_̣ǿSB@H%@WхѩD5'7;e((b鎍%.|?WUm0xhYG<4n޶gQ;-So>hGgw/~<==nsZ"g٨lYHa' 6|?q[q?͍,U- Ёn@z|!lLu93`"+eDOBWO*j bz2}A<8`UkxgX/x}jܰ!>'ʯߋZQqSr1Rkvu<8op,nH ƨ>֡C/P̔vT;}( 2I?x;"Nz2簹Gƀdl)4O8v3 |7Zakk )@Bbj! X`|@|MNVu^#;x&2X֌FBMDsEqo?'.k2W)D7c9z$"߮l;G#~?gr'qVc\HAO$qw,v3(z7p@|Y4ſw<10Gc>&~,֛S,B8't g?dv_jeˤԶ ېn&AV*5' O*.1d*UZO'ήgw('Bnv?Myzs-簞G4{Ə{xwaҕϫ;v>S5~w[BvIWȡ=ݠpZ\\Df ObF`ixmg3 &.ɪl1+{=w[>F '="Jܧ)hGפAOlR] \8dˍ% a0p4z/x]^L ZF1'2(霐vͭb\|D=5iFmGj`tT{8K}gM7τg{P#ώghOlϔҞg A&I6! #O5Sr)@ooo ؈S\iSDT;e([77[\pʤ)515ޟnRX$ < xuӥptD8TX}=yO3#霵frJyH2y Ikث?v+R+%@wUj˽u3:P $q;"xs&4`N ugG}&'nߍ|ͼn~}(Rw达tvLM OX*sf H/ .[ߴYs+"$T*d J ï,_ A%гsAdEXVeU!}/ڲuu?W~|N]=tUXڊe)_A~"!2ףo#ڴlnniVKɒYj<c1d2YLJU_O>UJ{h=vCZzcc/*~H5"YPgΟ>zo3?;^>WqunmP EK|v5{|_Ug9U:1y?ê1/}~$\B2G6 )=ITLU^W'MMMz{/,Ni2eدOVM3Rqa k lAo1TF,m(RǾPW:Ͼ:GԱ_S/<:';9u//?ݱ_SGɟT+|W6-lr_az 'dX!We){hY;qCɠȆ)CUN>AJ -Q6]ӆe$g2\!xPV !nP  ` _3ſ/T4"i QoWs[x-jߵj^f%$1E}|J;Ro!":ni?R|}Jrbh 8"ֺ{h7O/*J,I%iU. !k ~V%ŚKl?+ C{ÝSl3@+q@iȖ~`*^Zpu'jV=0;rSiHK;UҲ%Bvql}N5 E`C('2?[-Y#Æ5s_ Hd!r žNŒ~P!Tk]nֹTu3x~0q}bodcժmR'#LW*+VJYVĐ5% ]uN֡U!T}6)?$Y]%yd =rN PzO<ua0Zb-7h%3|8 B^$B#j 7Ͱ܀ ׄeiTL%p5l%FU8 'p4tRwLe{+U#`#O2R"I7%oݐjU(S MV˄ W\i%o ާ|K`cAx4|od.EMߧ)<(?ރhvDG ST=*ʚA}lؗM!a~.h`q%ySE.r(AnBb4O9P~񢀟e' U J Auv 2uS9ӽ} / >56>PV߬aCuwIl4凌PAjU.Ak%M4SO_r* n' |4s޶ d+FB^9Z_ [P8}?ChXv$yȧ [Ww,#(koK)6#sKsjk s_,FIZone0]A%6 S$ A1AE`AY| ET!9a)zd2gـ^%JL3*y.m ] HV|aHrb2G9O˽C%ۚx',@&d3O5S= 6φ6RQ@%-(i5.ЫF",|fZ?܎|P{)))tAs,V?W d NnP2[/<}HNRtp]<\bkMѦiUJ)>YEֻN~Y/a g@)6$z;ckKLgM_LWwt6(n+Vr^O۪TJOs9z srJU>uA@=k(*mPDU?ZwXxu˚TMJ U8te߲5^j8EEiw{_ؿ9\şX'龱gU-E[@A!T*D'kAu?O5c{fיAaSPP4ƿ#?Oc~H-1g[o-JY[|抁VQnAgD@`Uh; $TCn_Z>ѽV˻A5FJ( e _ *a0f טC˦dg[%,a1koX|~[ñ"PA$l& P"h^j]s\>x39ސh4JpK0$]QVQ2JoIfefǀ7YKiL06iNz{϶F[1X"Kc;1X^j5?TV| /6 !7H@WG@I=і+S3پz=8O2;CՋq* †RHBRD(,-ANe}SA峎`}}zL%JrIiB*X\㶮 68b/̯}Z3\MԌgxVz7&_Kx B1f A|)ƖveUe 'q](ސSR&ۧ{_v\|ɵ#w-і*g0)aCĒ3/x 0KZ# cmA_'Jʹ>v3xihiHZ+,o6=IpWyxv.%~c1#b,ڛUedE0]ay|XO(F@1p#_`@܀WTp/) v,[.koCC'E-v\YCI6D]6Yf)# /-n# 8Yw;_^>OԷs#)2 _1إn>Kˬ)Z*c SO=xA ̠c(.fbBC(YÄ}u5u-axݡS_Z:Aȥ8:~{FM\ t| x {3GY{>{;]N0ZU{K;Gg_&^.g3a1NoUU" @:!B@@} * Ep:h~2g!j*Ml>J cf̾ ʤ%D۵x()j߶k=CIcg$!xv&wn‚L7x.gƳ?yz/*jvD3 0r ," P ~ X]S Pz.bX8%@Ս^2 S(<3iNeK.XtY벂O;@}ӀdzxVOYz |;ȚX%%6k)PCSd#jALyKjMXf Z&k6>K :@|lfwC\y[*{(PÇ'G 8`]e~BQE%ɚB7^{z#(pk@@# }c:>cނ*{=b/_]駟a)& qPoXd  ͆P.,{X!SũEI筅 ^)v%S)K;~߭e6io|J<*v/X3`- pNp|ÜfvDEI䝲ӰPQ9VlЖ7/*1k PM&>:ovA1wI$%-ͅUp)mUeA^YX2,e[rX)ߒI ,,̤*T5zh|w(8zwrQ2455Agg'@__Qk@xW8l^{5 ]X.P7/ZVK.w_^v~pZpFdExWK.Aoo/\~v; А"0(?]fs%(CŚ#ۧO#-E HTgupgq伫 l6xxxR~G &bPW@qd́>l+CJ.R؄Jޛ GFFn݂ z$;R 78Y1;CD*0'jq1>OTiN`a?,Μ>vx< fkh ⁰psc Z6D/_,OXDž JTμyJљSmmPTs^`\!)o$~]~RɎ_K' W~B[V6 '(.Vr.;()v A@7;X:Bp{bc߯`Td٨ n%<eM)?GX3`Ʃ(f>DMO q"Hq,yn ط!lجX7Fyc}`"5 |?w \| dMv i AJ3ʍj>$ >ʑfMh4W]ϒA9[v644zqeٵϠ`xnyItv9f'/(|X.;P?y6bM}AI8߇tɆlHPbBLBŇP1V`gXX9w!ttHlː^IT,3L5-UH Y,(Ոf:'%b#w$e:Mavv!K)RdhkkVLc)d ֽV ,ٸ]g|*;^FD (w1>O>t\rEzјhm91 ɇXlD8 R+"?S^Y^49Z({S0v2$2E?{B `)H ]lݻN9 qS -ambNG#\|$ٸ&^v[;璼:_7VE,2 ^dXeHm|3A ^Z^"[Bc"6_«8FS^_f111>!!+tKkk4{M|_vk8~ҚtM+FǦj|/ey1*ߕ !C񩤱|pm)FxЅ}{")FvA#IENDB`gottcode-kapow-350ecea/icons/hicolor/48x48/000077500000000000000000000000001514263554100205075ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/48x48/apps/000077500000000000000000000000001514263554100214525ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/48x48/apps/kapow.png000066400000000000000000000074651514263554100233150ustar00rootroot00000000000000PNG  IHDR00WsRGB pHYs B(xtIME $":bKGDIDAThZ TU׵=p/_:"*Z{^ҧǡyMR͈Vc[(` MCQLƪAC_ID{:R0@0Ikp9{5k9"bҨ({dddО}s^?Kru3lpu*0ÑXgϳm;_#Qk+q rJ 08yUjUQ'T2y0c1m /l uఇ _韫ê4H=c1 -<3,B޹Uuݮof74N N7wW!UZ A581ޅYuˬ1Z%z అoIu@^ '!ǭ,/ĊxsN[DS~NƄ'm~'pwym]rnj&c P)B㨪6673@AAǬ=ok5W筗]vɁwޑ-Gxc'CŶ֨C @r(%öa'l ؄66cF`3lpc>y7O~6grˋz 1VC W K SI\dR|X`AeA;uE~Hڜx>M5SXr3%}Js%`I^,#%`T$,#^!|D=a!<0ٻ^MN ڢ'3tU=DE=Q/ W$鎒MnPm8 ᮳T 6Lld) g:s nڠܼ\qfb#F,SQRUC 1ډ{k`Ve#΄@+DmUj>I\^^V"K@emVi1QC%tM@e{蒡;7j}y6\9bɀd@D%aɖZ0QxoN_6>С._=zTd-jKX<`HMxtH4ɤ"I9ć >G7@k19KEԝ/du°H]SUMXdؽ>]~ABLL,Jx\:AWg#%p,z|Le8n813Hͫ~ 'Ç nU1F`˶5-k~:Pk19KE30EZ ~FLw}[ vy!U3ZJ!)Prk q rc:[%neszF겖_z:b /*@s-R5W㗎/جy{ñÄȅ[:NIZ؋Wqrt :f_F]*c(F46X>)eeܹSanm"±ùԁrhAma6lUi{v^$z7ʲJ"$2Gml+m11O ̆[y{*_+ 112zhI&d$HD}>&} ,Uh0s8Wh6I]q|$󶞓l?}bq0: fBA{ޞħDLnjT|t9ypcc&תBN:ĄtOLӰAOCk^ q^%_7ݚk&U~Q#'7ߪJX`Řfo-v5$wPx4Xg>~o;j]2IENDB`gottcode-kapow-350ecea/icons/hicolor/512x512/000077500000000000000000000000001514263554100206375ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/512x512/apps/000077500000000000000000000000001514263554100216025ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/512x512/apps/kapow.png000066400000000000000000002344041514263554100234400ustar00rootroot00000000000000PNG  IHDRxsBIT|d pHYsѲtEXtSoftwarewww.inkscape.org<tEXtTitleKapow icon>tEXtAuthorGraeme GotttEXtCreation Time2011-10-17B8#IDATx}iՕjIb6BȲdAl@l$6c0 `6clVl6^f&fs"޼gb"{ z߷w='OݬZQ\Uu-Y7''':tСcnQQQQQQQs@EEEEEE %*******JTTTTTTT(PQQQQQQQ@EEEEEEE %*******JTTTTTTT(PQ;D q |3'i훎K%&ƍWN_bE"j,[,9Qi؇/w>P( QQQ2މK&1:, SIUGoo]7DŽs#)H(T"J TT@_x9s`@NחMf21ͦH;r)mL&TWWW' D!) B%r@EE i,z ,r Y>k {I$i II(Pc@EE ʉj`,Г[O AhA1CN`pX0bxãNm"KRvaߟGC<G_CEN@lgΓpLHd%** ^V=Y0<Ɂ@݁yңb}<c};>{ \~؇|')D$8aDANn'c IJ>)!PQQr?.-{nshfdɓ@-mvW vh?жc}m=`,a,pUclmk!1c H#'Qc$!M9Ι$\pd5/%*sMKl''Kּ@|K,qTb#_zuXMOv;:︧幖}-/l`vv[}+/'g߲do# k qōIG:/%$._!)Hf!CT!+,|ɲ =,VR,[E# Y(r`,v }g]ݷMOw?maϛhuoݡ?6_vzwGx` =[.9| #Fxd腣׎^0zM0s|blm>l۶!tGv:rOcj={Xqoﺫ;W;IߎD pވA HODo@*JTTf_Y•= a>,pI>p3W\uk׆⮖Z77@?ɡ?Gzb/9rƱ%c_2Q;qdjr^{&nLݮ= džcıq O?$Zݷt_;j2{N"9nh`^1(<0$Id!6PY1# @\d[*|n#{a@ݷuoxnfao>,}/]&L=C_]}ӯ>8#PN߆l}Yc+'ӓ}E A'Ra<xbېMI28F9Ĺ9Ź->P|A=ⶡeC_6R׊@p- 5re{\K0%*JTTN~Q{ϭ|]<| nͶ?}W,>iMk- ɺ٣IFZ1fI)Fc97\Ƴ]I}߾2-H`K]2ᰀܟܯMY1qE3M${\\\#\+\5ĵ$2GЈ( 2U*aN%**nK9ֺ\Rǵyc[wQ];Pfwm ݝcg}fDZ @4.œ${m عkea;tϛ#sH"<4dB)O\Ex pZq\Hם60S͉TUO gBC*JTTfZkߕ%8SL( |)k% jƓ{v\]xp?8M&Ɲ"cL }.x]Zq7J'>c<DŽ J}K<':oޞ|pMG.q˛-5ǵs`愛 n *yh#ZsW@E e_G=乥mliAw~߻v)o^8Mf'L+ژpl~c O\Ey dO6H K\\~Rf; ֹs'aIps Z"C+q  *JT愵O}SۧFiU9>͡p#KFo{{Vm{̂*;S%1(dm=O֓>u!xhh&w@!c&Pz Lk%BȆEaM nj(-!J4,  (PKx~xIњJ>s:g+;G>GׅUK0ȘpV7訜@ w{xC#_2a,bvay?[;ǜq%"shc%*%X'nQʦzZ-ˍ/ӱ-/jCN& m/dmcz*g.!"K73z8, D2 DU(PQr?uC#e}J2twMz\Z^n9n}]^^Yz)O;puyyu"5qXƕ A;kJ yrbdΈ"99m pJcQ`bY #D@C*JTN=ן{aPb}^K]\R_ m  cׂ,/D]"xL74GbNcncccΛek(PQr? ?J$C-콡wm-/>u~vd˕op l)p⍢dbiT]s \=aWpؿU,}D "G DT{(PBO/ck )ou`cv:Zз~`-jr<FD0L:M{7={ {.s@xY>k2)ρ@Pnoln}.|2}{M|K#˥bP<){Gv^BTBHDɂ DdhX@E 1܈}uH?9*_DĒHЧlY3:*'0ʖ1}9` {{ 4MD MRHJTLQw ||%o_4~d9`/ژ%%eʔܟΪz:t|fdAceWp{CCD FUTAKR^d'j%DY%{Cyn=8Q7qnb>}QM R[煮ɞ"[|RUM{( V#@U=h'Qw(PV?#u&K| kcۑ3*iB(CR*a񫨜DjYHV!ևԒeDztuuedWAʃ P2ǁ7 yf?`XK ~ɚֻ)<%[U5Oe6+R/O #y Q0* y4,`?Ӱ>(rÅhH7A2ܺhⳠMo4PxlfqЗ TRL i/\8iGqkyyPh9 RC9wڥ(?@*Ju:`%wKk۾kC(kWgW^Ax p K,P؏{H#|AhX@E ܴO Emݚ=ˡKc]R(qo+6UT:?[0/ގ{G(8^axdX.]hH/ayv?ehE swֵ_ *yeJ|M***!W Oⱕ^_BϘR>c*Y54[~]Öc,5߂1܇Pol?wVގl9eW/B hccLIn`uQǽس ɲ_)9 ظq%s?%6G"+A_ mi lYN. ~ےo!wL08P99{F[{(90,tVK- ^8% W(((doa?k.o}Ƕ^_TNS!qkNav .ޏ0+QXyG Z0w8p.}wgZhb+#D7}p(#*p"05_T.*T3LP P`v?_y׳dTEe0ᕼ8smCC ԛ͔(:/=,Aa3 0ĶO9}(c0A;'E-VBpړ_ ^T%̎ 5 Ѕ /u?.7psoٴN&'sk\ǩsNF~с[rsW!><el2f23[[d΍k._dǗĕf]rِ`s|wύlk^l^m#|ߣ&@$y fĀfFtzܹ1OH&@2468t ΃.<$'@ ~Ɵ?}ُp͙I ЁUY'#ɽn}̊'';5KbKW_5͎swn/o{|`AnWcnT{^lb6Xϭ3r̊`9^{ >mbH#q 8mI|Y-msDĨ632B=Bép@ )unk}tt#p p3yw? 5oۃm27c!rr?f} ȝpqf,a-/2˒̚-6>f0{jlk֛9fAfM;]lD^iTՐncpl8F+Ǿ---˂߆X Nq>{g}yG(8$ ņ\L6[&xt'k% 8ԥl?hX]WYzr+|KԁT[)&>gdףwâs!@$_2`ttO@-Dx`%JNw7o'zwo(r##{ga^v4wis Bs*aBn8F{]SޡPdp@Ҕg@<kp!2 ,H i?!O/(PȗF֗|)J()o3Lt/8 [ +NX1soͽfsn4{Kוn*]z|L,J9Wi>GH| \B9ޛk>jvv"s׬qM9*QIGٱT/CB'B7* PpM:+)Y=otMUH YhH :kL1>*9s~]*ܝ;HdCٯyy|MP0Ҩ@@?ʥIF(O?Wk?W7e/3[[k**F%rGIa7u{ƔW2ЉЍБJTp_/uX'؄g[?N.TG.T]>%2 A};ylm JBm*tWe}WP>j_jy }y2ٰR!kk??VfԔg'sR"Gܜ(Ej@GBW:$"j[aXQNo!(8%?;?+[n}hBmR=]&\O ]wqb==gߑaeL"sWGx$9N ;֨FGvkQsc pp=\Ëc״4 ~8'Nkf t RVj(8ֿL@rcU:'MYO9>?eSR&2Bs6sjy$5wY]ijR5]|nox L'^ܥ_m}}*%*J勾T"Hk35%wKpM7%6=J j@jVZ$M@mb$?_WS:ΤAP9 Vऀ;YxPW\XeL8e}5y샲)ˁɽkB5 kט2mmft(w|T|^[Kï䝘Έ($%>@AG_d5F}>we 5k̂Sk A a"F/ [{δNgD$hAz@Pā?GOcbs]w߱kkqWvܺM =.]47{2{A#n)GŭfV5N6+YiJ쑞xVU{u|嶥'lHL?܋ZϮ77w6++ PȈe!FTf~r(Os;oum,ȸ]U@Q$@ Lߖ_ƺqOq{;B]4*J?)l(>SZZ652bl`լR6 K'wx~Dk'|D(~|U`<&X0n0'PE9ܯTNX4SyIjudIjI\ }1ss+υ_)?E<|Yz"$)^I| d_>?0wZQrK0GrJK>WO.'Zg[o]*\N<ie.-[6 hg&ҷ'M8ە\\*P^̀۞n>`\i) _DY2>N P|D<}40}13|( ;GZ0VJ&Vɟҹ`.ݟ?[c;&PM'JfF|YS4VXkχΥP 1kg\FAJ/SyTo? j{f"7(4 >jLO(O.W՞c盛7fefeаwJ}%Qқ/^N8S'\)DI|ێ?F_@zJJC3("N͊ 77kMw^7B&ހV ̌My@FcksiA@t =V(87՛brі7KYlaR4X9O\Ң<_jN6ӻ%KʚTL7*/_fbʏ}ԣ,clW=S%B/@^k5|!m;3w;ws0&4?`z\w|I *{*TT&O 5h߲wt誩oŸ `v,=-[̅ +ૹ%rTiK}S>@x:Wy%tB!99Yyiv}|x[0=|:ڳ/wP)L A_0/PrèdLWRGFY9 =LAȋ溆(eH3]ʻZ۹(u D>tV(g#gr?=%J6bX(۝ -KgN_$LVJ|J|IzQ{>/Z>77o5=GggY>$}z׀'$żz{ߑ?~ٵG$ DP/ssstylԒT:X0Sy,bC$sַoOu렓2*()P+LKI܏21lߥ@p&Ԙ(s\ [勵4k%UkVwN>*K?ʅ/APZ_)ۿhm1{Ǽ^1CCSU߰3,Nw?ՎG |Bn_jٟo֧כgSϚKN {K#* d/_RCjhujX5ft _.>z@'3K=$ Nn߸qc@DxIg\?\LGm;=elK_`zZ8a=s(] ?wZwڟኽ0Q פiH0cL..)1>=b2@=h$t: б \cߟ.?af?Ǐ~W:AQQJ CL S,P.wYwfIh_nru4dמ* +% x|{߷7GSաx_| $rRJ-oCS~RƗCg2gB,$mn~nzgP8s2s0~WWVmH[@ 6;2X@j$y`LlOfXY.X# :5pp$+w|gZ_`8O`w&]>l~nH juTZmv;ڳ׍FdW:pu_xNkǪI\ҽ>[^Y~ wwe}f!N( K]_3gy{f^\^eCI0ݩ!UIX1" PI@'&:?_6>{n&O= ˫߁N{ 2>w5kmOERwiSQrnv?^RUR/ P?~ wi_S  @=tT}m1IcG.nU{TT QhF5\vZ;aAzݭ6V~վ\җ~r_lOΪ$@HW|,|fvJBK?k|" sR%MTA#oBxా~'<1u %r@ZzSsR|W\Wcg AWI ׾? PAʕ{wNSR4gAkp6VVdmryqSQ*=~U&=|t}~A}7|Ah~URB@p1uB=l''W8bT; &$xเs\ZQN6C0f1vө^ZܱIсy+EcΜ6se+fZQ }ylי~bߋ美W7žX/ H%?S A߳+>fտv3xb- N/_F755#P67 R3ʒ xO:"g1&n÷po?9:T  ѥCɆ?gӧ_<~WͫEEޅx k-2u%l\fۭ:Lʖ<ݜTվN70 Xs`)im~̈qTx f3R2.|\f}0n&:a]@ gvs}-q(wxP;ɳ'OVe_- tj+ j{?nHbOrc܏OL/ ND*t+/ی`ڭZUn}m U A^mPYT3hBw?d`]o|f6qT}d@Xg"sbwtj^.;O>jN؁:n7o'zU*ܧ[[V~,}:,~ rH1n??87v"CP4}*M* P<+jvY HWcL@.9˙.6 ̛7bm$#?3x3q| Nӕ2aA)S5x1tw}Rn|]O_#X,ӂmgo`۲Xam;ƁD`]SؖY=m+鄂*PW˟t/l3K$@l|{% gKKb%"cz*#Xꗩ?-||X6C u)KE>Xl+FP$aV{1SkR&+%euֻnc|¡ύ9Q4? A{ K)h ccUˠneo=|m,N]/oCx.9b$Zɖ{old~AXoUp'qOPo;Kc+TO4PUp-Rkk66X^RQm*_TF0Fh}]Fs͕sB1v@AaoY߂isZEjDP5 ݛˍs ϵv'rЩmj6C[.&c@@.%0,`< o̿?%%w:fLTl+/$Wa坰\I |hPu۾zn/~>Ʒo6w}g~}AϠ ?l)\>pmZc_hHX#s 5(`/U&)zUq>]/fzڒ`gzvoh_{om 7ˍ^Nl75&B*wc-9BvsS$邡T`Ƙ!6ThH  }+A*ߦWOήYCU WQYPzPb]Y~*v{r D$IT/b$Ar0ყ~r7`= i כ!%vk&&8dr,RϿx.,sVx3Tĭpag[O歀>U+@eM]PbR ǿvӨYe,FUyi9J5rK'+èݪ{v>% TfL)ŖAyR@XHDm avb<'I4I:).Ycex7BH $"H۠fp줱OQ?>^^~VʫM˴3:*[/i/+u" _O ?L;07>'# @@ðI,m -u4ivYUZo'R@C:z bd@#aoue/zgjN5KN\8q㞔&XsPצQ6DL*WKQWe~Jˀ:wÉF禟 xd~ 4w##vL on`=lO>7cMl24~. h18ɭi+ 1,@':zct7{:zk)Sw8TA&32?/-] .Uen5*^~2Y}'T+W`<<V@mW7L/-p,@ 1]?3Q?;N(m+Q/"9Ъ_G}@7RG{S`>Z< UU?g''׭?\^>E$c$@4 bQ W2#DIfOo铧OLW/,-7Wȳ1#t+|Qn;Uk#W`{"*Yf@or f{m4RG]#=e@/@}6SA< f`4 @~ L::HTN,@1v6?} bΪ V)PUsKsagqNTL5i~/BX ߊ0a,zziw? OrP+߼f}͎YnI^n۩qγ1`.E0N $]%$#׎좛X !!#ݎ,@[$r/L\N\0:wb| GAtʪ<q~|ȱ&`"hRW{Y(dQbd"ƅIc9sTڍB og9SMeDUh@$tO1,Y0l)#Z8F B,jWsvb*TJG2?1gmH%~'E_o }#؍xU_% (~Qh^[aQƝ|W^pkExmLsA((9W1y*/cƄ 5A HqL,@/~[ bQOt?2ꟽs?m‚Š7?qۖNњ/U%_o+H0Y([Qa_.w# AI(ݘnGbL QX+ )[/Y@eGKl lG]/s'MlWoj[K$'/_[X gh@e]@Y/-0Yu/h_q[x8K=wwMTɀPW #I8g{)6ILe<r;b !!&13:,cԫ1 c8o^3z39([#OT}\8Rޢ *+ WbcqMPPUq?n_~iNgm*?Q3&$/^r$*@y@@3*mE'$@n!ƌ^=ZaP,@evXz,M7yYх?)EPIZR OG(oۉ18zDI˩W|( T+u5X1#^"PX-uig Ev/@Or_clgQy\QBWه?X[ljhZoy~m54gO+~G0W+[UAC*1<({C!5c[ &Vbu5BT_fVق62%я @(Y0?  {Gg럗~iǟEC084ޔq3u_}luL< hxm\Y?Az;QUAMNrru75*@"01c Ƙ=TB[e L>66ç`9#ZXf&1aoeg[Mٳ egtLOEphЏEXffZ(. @ySc;>~gO[sġPT@fw[0TA%Ko P/.M]lzS3gn' cW9ـd }就ѓOPF?:h6hzvܻD ,6 h8M _HR}uC|y@]P `*0зY.ѣ{ʼnV9aeOvO3Kϭ $QO,Th۹5U ~O]T0X4S ࣨMFf 6WRwQe=)Tcm\歀,TuHI #M/^ʓ>;kUHfJXc$̨Ff/QycyXiOcosn3OͯTc=2Z$ROG~0F9a| |ګUU~U?9_W}F?* /S~YVzogQU>ݑaUu}~U,=++g'6`?uQ|gn3# ̜qv0zҜҢJ(/>tT?]NåKT W-Q%_@ZM6^ 7 /зwQn˟DɀR/_R9Pi̐]&8]JWe)8(PSa1YT 16O6I\3y0?GPkDe9 uɏL~>hb !82}zCN+xzUkEDoǢ1C|Bc!x0#q"3'ΘXΌV8>)Pe$Z$'T61]Y+FWԛ%H Zā b\Qe_.TA=$킿d} )ef!P`y$@$QSgM-' @M @ >~A(MpZ_=/3zӑ?E/XԢF];qMO<ao x'ܛF 6"3˝Nh)',. 4(@ B- 1fD(`/UG)gsg>0s#0Cl0Tמ?WNN{NuVQZ96w$lg @TjSqqkuhtb@$MQ+ h OQ*,."1|Cs #N[[[_4a5zU`R0,? xe*_78d~,@C & #@À5mXE99,6a18UA`bt)'!V!f1Ld1`:!U[z*;>ܩڬ+Q}&A}ۛr`@II_ȟDIAAXR@{i|O _?Np˗_4\~&ij3N$iq4CgiY 8>>6@KJ R#\g1/p=3'_̇MS7cHRf)WdZX\}ezέԿWV?,Wpo ~?_ 6@~2}gi -EyQ$)VS-DSĬɹTb@ꎅ @]Dc KSu%OAu4TWl㲙 cf%C;eտn?l@"'Û7[;@DIw[_oo\dǎU!ZS<511d+86= ?P?|Q?̎eiD5)HD2BVVh-;?nގ-YDVGT3[5 êCHrkb,6ŀI~ cV%͐ }v3w/jٰYK 9-҉B2,)Mc8f"dTmRmGT$^m$^Lӟ(5~4&x5*<~\)m= x4I]$i[j$p5y|&Ā @ Ъ2{zzL"Pia),--kKO^2aa'aQ-J-f]ӌe?~~> Hy -4 J)¤o B$IjG\X_wSU_^ gmGa+F0z3.eҲkM?X1>TI2N6EO`lu) 5B(P/?)Կ8D_V~fO)j66 ?,@X?0p F85W_MMGA!iX12$Z4 *: @cH Z t<$?Mu K4s=8/wv=FTc~V' qits-d1Q._9`|1`ASojZ;UvֳbUX7> 6@3Rf$ʇR*F-GQ躙uk*ʽX@Bu^XV&}p:d{ق\ns9vl0@&Uz5ܦO h)ėO(ϨyB FrE,s.ސ[^{aTLH{Od4#qP8S>J@M(alW PP|^Z`nlCcD ĆVE*2+*%k4$ko`_3j5:zMUAA $],n;[XWFLazu؛٫Et.q*yI` smc$g3t7@WGP?6_AcT&NQ6sHE%}|9۱.N;/hubTQ~U_n4)#W3~ya$V͠PG`"P!;&FUʪ_1UxP~7yJd8K6@"A/X3} l_S8>t")-ʃcaq!_<^kCͶQ_X,A}.7`"?|OP e?QQ GRG)멚# P"1a̫g;~M6Fބ1᠁XnV6"Aq/?>*C/TӪUJjvSUA`VP.K{oEt?a+&aV|qo[#>''`Զ(uSK"1؇1R(lļa,8-1 @$ Y qGDV?J$ {Bsgkj=z~V' {+W!FCD޲}vG߈qˑcTwK0Vߢ#S&!({Fvhp! l-@t2b_4_-ɝQ%iE.ҩ4^8];'je?D@7.yիap믿#GޗIUiU{CJt6KCQ\bTEw!d8:13'I&:qc$nqk% ;PA?{sO{ުEE|Ս5׮U}i׾]e4[ϧY3 R 4swߛ)@Y--z%`2Y<ÃcHBBTQVx`Dht@Wݬ\7 #%,Tjl+_T9ֈLLitֿdCs&Ff I4qD:x GQ[6wT{1WCiQm]붥e&nTS$I1i>?RG, vH)yDm|8)3P1V#1 {-Z4}DQ3)tR+NmLG?ˋi„ Tx@:RMw_|7 m^8n)zm/{, _OpH# eH5W혩 yepr@};?|* 6 @Oz7MneWEhHhHBlo a@=FE8p &z뭷-w|ڻp?h ?,mۛ۽= t (@:(֒]\{`Y)`$vh#NgZ @W7xz >|QCj M8:%+ouN @>&߽^E>m6O*+:)!"!6x8OIRz椸ﮋTFMI ᇗ Ҁ[f՜mVA 6V7n\+"scP͝4t\~> ~j"dNeN:l :")ݾ||p׆辧+~v zg;tRItki^< Og}F{*P5 RaCM:7 .p{.Qx"7?{/ZOx T섺C9|2y\Fѣy0FgnMg;\ԵsNZr~tz=v̡'~''voO~6nH>\ kyƞd{n.o>ퟶsT0<au`āF) `7Pg9^G{@H ^_r?bڃ3utu'z!pPSSo4i B pB* iL.En[D;(zyn܍M7p*Wa>& ;^cq#;VA;]0zbEߥ灓߾};mڴz˜\|hP{i{𴈛xfB`%8P䭀 ͣ> ՓoPFՈ?P]h) @Q,sl3UҌF2Lzs8 Q@0yduѐ!tRN8;|F^8ŶAڰwCj?@@nA rO'X6v\ɎGv`DZ (UPMveڵ߇KsO}_hE[/l{=iЩ ?Y'm> s㭹fa oPVCMZ\8q!@쟀fdGֱvndnt QA9E>|OUʹtRҎg5\4A %D  / 98 %&@ O+{ ;k//|E %_џ5'-鴛N/ezo{E`˺D&nTv~>6S;7&vbPc y&sde4y]׫Gm @fڰamܸ;}sq}8dtNʶ62d*$C[ " Bԭ=XbƇ,3(]xI@FkiKp:9_ܯ|:eB psjooAMui5-::~/k_ZK]u^с#u#AzjS)L߉ @&SlbcY<]kP'V9;f1el+Khí?eQۇm/f?:ў,_j@9a#PTICK(qv@y]d p ?ؚp VQQg'_mRknF (. 6l BBy]Ѥ>5l\s=}yTuw Ȥ/츁5oK_ P٥e4rHZT{N;m|u#ʅ>=Jn>n:pRHpDBIN7'. " GPlc ;8Ð;buXطl OmUɂiDU.t޹=B+ L1 :v)XOi檙w|D&ɩ"n<ַ;v#;n!e6fQmtvtiG˩6yl2z'8~mپcwRN [La)(0:eC  D@7G1HF \͔pdHJ+Tmv?2Tot-njà !;t.64VnK|04%p$[ֺwML3zw`(֢w/`}Ӕmh?^J6O+?F1}t1{= :l0{L^ۢ0uvO}@ cC5Ropk2߅hbo\& {pw[Bd$GzyQ4ڿ0\$[V  xQ hąTUZa ` 1&@ZX q&R0&;~mjg$y4e:'r]Rs?CaNG@#A4lldNDBkO+s~sP@z{`Qw(RԊVm/k8Q/rmm_'FV.0v z]h%V@[M-j+j{0I_Y>yڏ:;/ -n|ymXOO,ϲ#J[m~*RNc'3Ϥ˾}>C EE?ꨣ8>n(P3~ $3?JQ"e@@foVHhQjj'_L-}ZzO]u@ďB8}8@v@M^t;MR9U^x649 :K;] Q*"7% tv@ WV &ԉ.œ{hW?sO >Y:< r?fǿ F0 *cbsZ:[hyi%[q.uF;$XC@plq{1X٣vʺqqY<a_n1$ );JX@U))XTQjeZu>SGCΖw{!P'>r:4y|Zϻim i长M:YAV͎)6PYXolnX;Xd%bc•<F׋ كć>}2o'v<9q9QͨjJ:.q>R&"p.wHn&BRXf*&l?`u9N7}/fV -LȂ@t3I_xr:]Ӯ}oS3n` Cx32}pF@Qj:(Zyp`t}+ xbm-Q ` 'l(N `S %Cd [r_Tn$_zFV`P5Aa'Щڑh[{o'?zo{e烦(lvb==Dgi/1]/Ofsܱ|?x.2ď|8DžF{=U4Qpvj۪#[==  w t'@nް 'F=)PHM?_KzQkF?}@dO0XZ?tK~O|J} _:|ɼ>m^Y?e ^\bzQG;e`iHqJWϧy`*JV@ӦMCq.#v69t u@B|&#68xh<(3Xg9o^ x]ȧ1 i*k9z37_\?w uPY0s˅`Pgc']8B,5.N3~}7M57Sd8EDA:P{Ҁ{24)0Nw ]3pЅ4|Kq!C |E^ P,A3ݱ>F'I+ v3%s9 ROpQ ? :Ro!` %uj֯ Sb A@mmm<o0 W/yx꟬ͩ|0tLfStIS@*%V#yyP з_=z6]3Z>|9Ma|ӗ!~O>6jr?VD@;@)p!L:T' j1N'9qP WNaɛ6k;zM&̗D]) WNP~{0* O!AՍtRjnutۃѨ G/˼Mp??>W,}wQl*.!]tQѕc s_?eh`}@P?=[_uRˢ5 DzwybKTF  QɭN,PaHx1P-ֵĪ@(KȮVB+.t kmd+-szmk7Mo_*Y;=GE)39/@i ES3ΤZy'} ?dyQ?2~ n6O2M " |@eV@u-d¥R GG-?ݹv۝g6/Rw;cr֗iP{Us ⯯53fKdp@qطvdf+KeiTH+ˌ PN)Hh4d2@ ?(Hjf%ki|SB0d_`Er:,9hs$k?j 9g&w"Cf+ޢFRӧ~44&Z>n9Mh:U&Z#?.ѥ/{9U~jtBhVT: !j| ! Quȧ'gR"iHTWD Ѱ.mn,' ^ rDo520dFD' ?_wjۿh ԫOe7OH'w QlavJh|x|tin\S g>/!+ |޻:E@ߎ(k^~= jWpR @7jVܵO,"y6Zc:!pf Bf`\lN7M'^w"}G?r?H9\jcrţ#A1RK vH&lTWYgG{3g.qNA}^ۇ:_&@ۡ:T0 hac=T;iWJ9RȡyGJ/QΟ#BKGT l|["^޿2Ep$,ɓ'ۢM| _N?L;L_tcϳ[upSaq2M1+Vq[' e" >Y )1 WD '3F6{!!Jm6Xk[㲃|6sxp:- :B+O3]"j;{[78NXH7̼N~r穘CvB:k,~bS:? סv@R9˜C6p|%'Rsc,c$@'i?Rҝsj&7=#E6 _E?Z2y kwoXOSM[A|IFϵoos"@}+#BϺ{ ?tNw i#q (8O Hs"`YF ̀(AF,Ā|j+cH^YTS Nj$fK# s Ƚy#hၼ,\E9 @8q{k{y]‘{ȷM>ۤw"aù?N|#PvϪ*>.v bt=G>=q q_uctп3u K"%J$Z>w@-b@Dѷg0]DO!Dn"5Sjia[mT[=/@`РAD2nou3H U sRb>!ˋ9{Gu< Y ͗GHb@r783j^YuNN~~ S724*Z@gPk{jǩt° Э7?zt͗[ϦM;7}=q Xo= ˫O ]u}mר{RQG>={n| $t.;ԙ)|&by}\ฯd>s m 2@V5<'d ^;ḭ,Zfi`XyJ$j/  kN:s̙,ë_;cEʴ_/I9Iu4 ٣h<::B7&Y8~oyjS ,vC9M{eFy>Ti,/:⇳ӇG~BEzVIN [ZP_M/T%h>丢BP'6㸏@ȟ'z8jm'jdab >p( -w ε{ټk3s踫 n0O@6` ;^$F֗1Oq2];Z:wܹ4a%ď<9Nhhy Me2kuaGrWtH]u;R@_"<Z>lTZ7la.]L%W ʑ " : hBK'/?4ɴ_WўB!zk8}r |rZ9u%4KM #@C|8}.(3mpbTPč•a!d59(fpm @\Z\fojaEEdc'd\ i餥4fP~nXA_i˧[cjCzwobd#Gr"ߵ3S:Ndh pMp]@[t{5v瑊x'@Q%@U(jbj$!)(b*TE.tzs>G̿\O۽ N3M..FՏ{scLMUͣE]=jΫ@+?PSo [ۡ)59=A{$אvfuBp $Rs<|iiGV(>aEdJVt꽧1&5W}p7-X D1XpnAJ+!N7Տԅ;=q]8Bjʊq#&A8З^2h42uk ؠS~x IVY}*M}Df!p ]Sůc>奙j"`91>|-Ûԟ_ּ&2#u!G9Dɼg=Z4e-=f1ԯ??:+ЦpD( j``t6#-MsAcJT ?aTFu?LRxR?ڠf>b ' A \h"S [.#BGH(Cڇ> ~d2ďB>ŕ|&v֞(v6 )EJĀ|V2R9|q'pb$"v[ /.wt:Ԝ$ΰQAđ%E NF@qTV@kV Ϟ/U[QK 9q-& q#@_@( jnn4ğ[=IM,X:Y`k9T ~Drܗx@ސm@D ^ p/_% JtD~sWsтC}81J8h ;0! tWz/)! 6 ~StR\_D7D+MQ2zdfh7': tux JBR'Si Տ_5g$UIєze+)ŕaLih5 B0g#Fx1ihPdD@ 4x ~tP ((gX467Eq{WM>%I&}1bR*ߐ2@D3-t#9#:O65%2wuuӛ;LܬMͺUG6-.QOԵaxF8`g>KMy =h|r#H~m#Ap?"#Q6 Φ6 *>/XM!3:\\  vtm((#olþ֧+^;R2]@d3GouMo\8޶wKCD[1>?ďl 8aS``n$@<y*`3d= o5:G+*.%ێ,3PWXmִr@gwͅ{d_>m4^?*\x' z ɴ LQa9Xz=Oj21- 0i 5u*ѢAXh "6]/E8}y^?36V.| To0_8CxCW>6 [wz= 5AaB508ݽct//)qYג*6kL}JWWѩ;^u+B ߟy 8Djn<%X.}G=Nzb}/ﷸ )])쀍^tW9dOz<`?  5Nw7kf4z0}jQzo{tgӬfso>7Ss>f?K{v1 B0uԸ>0X__{Xp-rR6űf:tdFaD#>Me.@TSϧ@ysFl԰2h M2h tڷV*x,=C}380-pq|Fq/?Io{T,>AC =2yŕjO$eUTn_wy}x]j_ $xb:zѩmV[}+aWnK#[ᅰܟ7" -| /cyGKRÀs{`& QT llf%K인GUur4lC(d]^ϗ@$ a9hHdhuNѰx+wҘ1_ݠ_Df,r+){#ԵV|oس#.%R DWKHǝ/cfm5/eaڼ3[i@\qyk&6lF2[ Oy@z9$_8^8GKd;ޘ぀h//bTVnt._Kf"oK\ 1 Pљn 494w?6>*Õ?Γ}O؁h;cw3,o* B]/#?Ѳ.+9װ q[ۤL޿FJ2 ($Y"q<_`0΍#M|.ь5d_iOA N^h9ozjzx4~xG@u:_捙W`-g9,:;ifL:h:S6 G3ٿttYIZ6Ŝ B,/} vBa`%hEg==,R8$k{ ۋ?G g66H'BR}`JzyyLIj26n 21 P  } PwBk^m|_o+DSAO_4mu#'UQ:{wҥz)gnR?Rjj:N~3Z1u4&a l2دI'q#1pUU^|1Vk>`s܀D* aV{^s=p/|9a+`3`;`C`K`S`[`c`k`s`{R #l%n C'7x7i@ fIIu'$SSL=l6]qtǙlN_Hc[f_D }X N{L~ki4uT:qĉ\B!մj*ZеN8fͤ1 ch@Z8FU=éaB\:tsiاef?ZA, r?d ^@z -Mm4V&`TPhr3> z3X9upꂺxSz{(1G}8}~WGԧ?iO~ۇJ|pG|DzG}/\£V@rRШ4<8Iy[mS%:9 DBt„ӛ؞OQ=0X2͸f*EXŹEN8^yu9sϩӧOZ9~l8y|Ex򺘜u=.C>vq|U'./ox}ӛ-7x9x]S{s{R3={YK>&˖Pd \iV…*~;G[ 66@ަ]Qו+WϪ7,!g;wWдA e;66i: XN2~TK̍P6;!##Qpkk֚w3O{QQPQѶv]jK @ ls7X`.uߘ8ahkXs9}QQ; /`k~r J *(TKo|?|I}^9o,rFt9~zx +>\&s+#~@;ÀɭPv䊆:&`Fir~C WzP ssBƮ7rt(?jay4Cve|9 lڦ ݝ$F'@M- 8Z+!i""kWz7$ `{^{\48ePoT:@A`?={ԗ?eumww5hUvU0A|e%ѝD'&yx&G]]$l;P" 9 MpOi5^:~wT-DBFOɓjmm͛Ž?҄Ƞ+^Pavݢ RO[UΛ d8VWWrT6jʗo,}vi9U4A/W@]QX&&䙗ZtP5!t(*28${3\]E IQ5}? X];N*X:H++Ҙ utDLP5*XA%N+KYK0?PF`IB`扸 `ݣo8σ8d#MGƷ2P5@axɴ֠g ʀm[!ǘ I6UԄDDpL9 >HąxNدfS@GĶM$0ψAF`Q*ȫD(Q~ {lxT߿K}2`D 1n ?o\ bۑ{`d%f@lFK;C Y K@Q&Js^U5qU,xsޡv"@I"͚ȥZS[S+o;`ɤNe_ @uI^^x/kTxJ Q($pK?G6'V}CP@ v CkZk+!G"ǓD{g7E=(LbAʕj?j#!X忑qj}jsHS D ̛2Z^^ա@#􁶔T<@z$` ]e"9-T9ݷHU MMrxQ+9ѷ8Ѫ mq$bM^j2l*+A5q<˷?se]o/ȇ)zi̟Nf P1ЙnLvb b @GD4򐱗h@JǞ?ݫ;xχmKbmRؚne,QF]@b+QޜiDĢ|tFs"pwaB KAA }/Wgre$+ )#B~ڜ soMM4@I kWhH"mYo~ P,Ym#AA6-H?DUf8TA}k.yܩ܂J:sɖ @-s"@: 2_[|?~뚏$(Q@)voU54nS[w!`h1|٤pwwD NO93q=p"`ǡÇ..^\-o4l/׸dD qQRc?h.|hjM|7- vNk(ȵOTk!0 1KCpY;$$^_{5ߴ9|[-7Nr]VN8,k78OF-3&َH3y+F dM,*@ ߁@҉M#6~dP#ԝ  SWM |jCR &X`!33"\YmqGa`FQ@48pe0P"8Q7v˦/e6}_Qxu'Nz7?8wV@=@-&@W `UV7[* Py„ KBlQ1wG՗\e P@ _z AX_HK1@M`>%;BD8O1Wիesر#xx,|b<`B kP+  Tt@^]VwR`TOm^Xe0P.W~{'m;FTS3|5R@&1o|#P_iӛQ]ۿ0.?0\%vP n0{=V9OO2y^{0;>|>!6K/xo-(JɀC$' 147i>V7@ڎt@ e^9JFxg/I (7|!"cTjriQM'#2@cY?]T"3np,)e$Eve0P4~ҁ@^q$+<*sJlcߕ?oM|g^p&=!Ã:&7'7&&G\]WWFcEIe)f@qKD\WN$:zڵkm ϊrW#)N0lEvvv:QA@C\~|<Cni Ϊ 0 YU˕@ 4.@_lj66QqtXKh|Q% N~'3h"4p3k32.NC7_8u)l7*Ȼ$ \:,` $IԬ]Al!lbцmON !"`!J2 ~ekg.wԎ:tHM5KB$"ܲ/req (k 9` a&TT?m># #DkRPL;PE@;FǵM#% @u%FIۦnE@reP_zIG{bjSX? t^`7JJ?77br13- Fg86FEUp91DD?j"R/"3 KGM>-q;| -&!6Tiw0?rS h`#nCx3\"ЛZ_dCLhK8#rk{@~,%$ZDnW@BIE_\߆k 7 3M;)JI#2mo$@ . Tn>"&٦ `wǟ"PJ^:yss>}l˳H@Y0%xeQ1۪zW(fk:褈5 \i9~^?I? 4yƐ;W"l3x>RӬxx}<볧Ĩ%(:W'tHY:a`$2(WZ? 5I*GO4l_Vi gn̜64hwR2XՔ6TsT" 9- 7Õ+j}z]F W7 ()]JzIN_AKJy}{Lt"YY'x\''q:ȕUa(5Z ̧Q}}gRN JVu 0L`<0j#Q%2<ߥE_G;x?%u !3!)HqsBZI8-âiӂe tiWJr5 JhdQ@ؼrkRar:9,S&5xb@\A>wUhl*w ܚ7 nZ)EF矖-r FgQIJy0ll^ k)75I,| IV@`Ї -\^xҬ({Rׄ"|'P"Ҁ!Μ ͰFt9,\[O^K 11H%+Q _rOb]]gFHY'3==ݦ<s>^iWjz4A (^'TSVi ^(@}Rc tI7YI>f-2g% l+G^ ߟr89<&j~_KM(GWt"Pe tIxuSÁN."]BkHVG:9>%0 +O?;`|i *_a8F`M8غn IsbHm ^/Di+Q:/<d@# l--/t*lӥڐ%yΗNu'6l`E0I`i~3rgq/e$%JV?Ggٸ/o |م&7(3EGP0e@л VH:TsFX$ `LK6R`H://5H%eO16ظmo;d9|TcApҀ/4-; $ Lu{sIN(G"DV?~Q?IIЍDq1Y)+ߎ;@ K29?f4ضDhWZ΋Y0ݞ)?A[xPD\8¡ۛS/UkvR`ڎ?KO_GgǹTI%I 6moroI߅eΥUiK疐@Y" 88SS p)!Ѣ9v1멧-)lBp7lP{}~@R?mٿFv&24oXq55k}& dX3[o #>n`*@?=9.nl(TËBK , ' H,h6q}[_zÖh3G7@TD@ @ xnfP؈v:=GU mQ7GZl(@Z<.A@1 &Ivfae^OWt h?F; _o* IM`szczY,$ L>^PMl[$QKϕh@a><I @{L - ع%ޖD6 f^g72ȑ#ґPe/J1w<) `#&}χZk$I`;xUhevdI8A3r/O>}&/ ٿM臗!MOsw1nk3Q.-,M a3L uYgJu%-0>iuO*/рf BfѶ?jxokIʤvjl:kYl?:dhHn8e PkӧDA@GyR܊i"z$ UL+u0e O^KBol߷4Q 5 k{ w(P `K/%r"A\>|Y]\h 7<I2W@ ]ǟ$ Dп$۫&cY] ~o|[GGTLI jd#pKBvD$3|mK^Ɨ!@ @ =?H֟=uP0螔^A'QmMrÕ\&]ON LkߢXF{v5S}]Cɪj@C9HpjKgH})L k r-F`-|sKq6PGaw?5uH:?ȘlU Y+75\:?jw,Y:;n>NAhHOF3P|} t)bF?68KDRM N@}]\Q<9!gGZ/\0usjyjs嗵q3G $ elZxNR2&Xीzzϩ (a @!AI_o3Y~t P~A(@J-zr :4~\36FX1)o48n s>Ьj#; 6. +SmiyxQ Щ;U b5&7?aQΨqFвf ?5 8TXω}cƾhe9&ب.R[WatSC> l2x?Hvo޼zokG @5*ˁl)7[|GNC|Ag|Duu_=߃dIqz:a "88u>Zy͌䠺. Or% >8Shn"(d@ MS):Xh8P^0[~zd+wWly6O 'umyB<3@ڣB6m^B my6̸Mk Z]?j>U>?6\{zuݳE{?lrKY;|YO}[H3B(KjȀ F %BdC hrDQB~Q \jtK@!]&ehC??I$ (@VA8AKRm?-"jS8ɷs:/O[] : ]j]}!= xk h $Ó%p~L|Q,e{9{.k#sI66'9*aֿ`ҿ!iDDl.ΐQdݥ Bj FPS\cY=ws]iK@6A*(blF$'A<0O* {}Y;^\C+uq_K oii߫Qv?N^{_ٖ@ϡWK?|A/&G|m K P P/`ßםX@h⿅cK&7 L |i]/~GS"FK0Qy5{ 0LG@%8y*IP?/Ҡ`K`SvqRV=?n&O>+ 8 `Ȁh0WXo/L4 @#jdJ &R?x?^ e"lt$]礝~%KL4KQ?sPd?llI r@>fo3I_F! @P k_j>`G_֝K q[Ю"ܬ6wn3K$d CTTw05OAe3 (PT*u.[/%[ᙿrܶ6Hp|NG;,3O^j/@kݟ ](0?я6\eEP]]\U?|#!cCad#`\ynlH¡i \?}gƿ~$oX]X={j<fQuCZ׾>;dHT}_K% V[q~ёX$~{GND RC"uP#kIA(qQ'7lV@3OV?ϵ.b^7wࢣ ,뎀Fc>ARQC2 .ث?{ EFZHR/I s3 0()pXo~4?hN6]qTp9WAc)_'M_ @(ť 8ECtfU']'^-o2h396cE5dô)qQ|#@l/]Xz*@3FWܸ/‹;^۰ BRUzF%O3OkG@Z(@}+ 쑞m~<76")U]^׾_kn[EtG@0(%|-&tv%,~?Kx"@F N0EOځ'@$5'(1 h0`s޶}~6a?Uu1@O[YS0ߌ/j h-K۷?RQQ1~UnU[,ȥAmR9@  2dYS܏$ e/[om?߷4 J .)#vf,Q>lB#Ѳ"!t鐠 gfg^ Rrjnh\#WMojmj** ,5H;W`x8$4 QeH$%7qqROD]\llB3[L'o%WgVk4[S} CC?t* ֱ9,Z?=oʖH$,%l=aӀ3ܓiBK|[shCtV`˟G]!/2qD   QD09ueQ^AtЏ"aqA B:zQH hM+6J8/@KI H;1PRrO?Yz?Ed#ZF$_rfbocwmoCd %3ɻ$s%/\QD^>CrcϦ΅UP!p]uP#A|RWl l c{M=mЀd!ӛpR=Q6`uLq&`FJ}z9|ŞځFĿf >elϥ {H2D^C:`ݨ&!q4Ro~`H="{=.(@;x3ra׸h YaҨ@Qi0 ip/J2GҤ.=HI˷,{{ˁ]AFd\2ڣThq[ןM9Y_S(y?|v?Ǐo.`(7s->WLF"Ņk 8.{c%zT{:YTE{e s| "i~\؇R[L=~{_87~Qh|W矙٘"w? D iD` ""C] bS@ۈҡ9sƩorº~#D1%9a*7*Ϛ$4WI wVu-IĽ!=I(ߠ_҈mqlV?}Tcq\O 7SH r?#>u L7AnW;՛L]埿w6fRǏ>&(@>]L@81*Agg!\ oH.=sۆs?{{1T8:;Y]?g 1 D]Bss?3`D8vH æ :|=}>).!6ALKQ8qDeEBy~ЁAâq~ _KhG[)vޞuow 7ٿ! ?.]vTа sstE|A %A[3j(i09͂l%N꯶-g5(B~Oj~)?9`QO9N~`Ϥ0AzWooedӶ?]v.l۟SD4mBw hN ׶&A QF۶o=RFڂp^ %IZT6esEe8 `{be?;>϶$?bo}翩dq+s֔ _0QMz@~uٿ+q_ @f1@6'`]:3ݿ@I_&3qޓ[Vw /p8 bZTYdI89q[`+Ǒ2iH5s`/bO~ 7T?N6g|/Ŀ-A?>Ņ?RH &3oҮb,-5^| /,YVƉF 6A|)kkUB8orYO% Dy"dKPquƞd{>w@U?WW뿽;=sxͰOQ{#dTV/W#i++km_9kB|7xyɭk9՛q;H( `PDt#H~zzkz9[ +a!X[\󂀫sWl:~cx=SцN:qP" u̍333W/>Eԕ+ށkaply-*R{yF/8\T?OOg uBI6zwj U*KkQ'A1.zKlnܡs!؟6dP%4g`qH@_D`~|/ǿquu^Ǚ NP,DZeɎĒ,/q{xfNMej*!R|T~@d;ER),R;EKJQ,QDؗ9ϋ/^@EQ]\O_8p㱫v_cX|jgGR?}gXK;mv}{WtR˵/ꟑd?A?|CHH!Щ6#Nor ~r}OنgSsE*”ga U;KuSfmA_RYiNI.".tE?s{ٌcI)i|"ڳK=UV{OBwK?j=ѝDw1O)ןzǵEBnODWgw455r\k AX6` "@,zQ$4EA),T Bn@``%}Ol)AF~: >/T pGpWpg6DLd;gvoyHP,]61@tH67k8o[yXE73:?K!JOG@:> , V_l}p郠#OCq;zebJ}}O M*fBnQkC @ T m;$;'7 \2Nt0۾͜9*zG@Bb1@@(@ |@ D-.W+ צߣ(ۍ-׮ΜhPNg Q ui\?}]݈GsO{$Zlwņwx? Z/; eI h||#giUo=ܺuQV{N"% jrf;͛_|ӛ EYMʃY@zJWʺ[:xPϙ,9WXnr`WJu?RXqprEJ{RPY|2~aۺ?E/l@fǨGy,\YY9[Ĩ\ǭ{+g+L9YP6h ]{N`^=frثz˝Bi> Ē9bֿWJko/TΟxx. :nwb@5k7:%\x%R r$/C$/J>ǟUEǓYǙ?qzʞp`y,yd%:ѰVL'A ZTf @޵kk?}-EwO :[?w1%0`5^*9ͣ}Ԝj8ʩ lY@# 4l:MH_ ρZ{|)@/D}>g/e?+0|}w}QTӿe]o| 2l$}=d_}q6퓶'y7UA?S?6lWO* @rBYFt_sW[8pn 3~T]  0{k:S5H=|ӆOi_l (d7Cb!0HK,ՙkUEy>lt?ۏ|/cN;j$dtY~KDB>R[Tqf#Y~^oRS5?l1l2l3lyr˚BNPWG׌\sL!,$ ަ^iN4}fj0~@HO}>q/ }@/Ku6mkXh c=Fw8|szв=~_ G+}/:8gESWȦ)T śNXܝYdk I>$( KwmGjzkw׿p\jgY.1$H ׯ=_ *?w,@2RVVH@ )nގ:́{_V:9~|1xlL{{-|?" M ߗ CgggĖ.AwY?¢6 U`b~3{ P( Dy#K;il7=\BW1OZ`-Rp#{t5v-Z=~ bA5C%u%PK-_2/̞Ǽ7hs| )_\bN()Y>'' |9,(E833D3M."wR_^d)O-_W_=, V4t( ȷv>atç ꎧ&j8@Xd;T;dܾu9Sw&S-rdceK<9_AUz F{L3rcS$  o^bpܶ':CuC1 {`s[N<Sf#/_@QK(>@hm_DuO劣Wn\DO$fwvFR4})* o 0|tA3R7-RRjY:6=ՇonUGY|PD 폙 &l[P '=dfYGu]tP@"H$]8UV V2B,;KO AihF%Ia\h`~{oD~J|N؋t-}Y()َky|yb2RYz0}}jAԵPǿ4?iSH"!?ݰRPZ*ATeeBRO7iZlԠ -oi~gl b o~_g$2VF|OLLM΂ߥmȯAk mV.^BCrB;;2HG -}POVRy838;8C/|3\;xG&ſ9 K;I~ggm)kksvjsM F|E6 7i )gu5^l|6bYRkʴyM-c"_/lH PO3}- !PoK'*)ĬPN_jp;YN? eQ1gΌ=;8C^ 8R oFg;Ѳ9~bLZF4IRTbZ#EVkoUW . tդQ=eht0;QM@z^IUN1&`JAÎxzQs_oͅMYc2.)eINjݔ2%f v|-zYNhp o> H?2&OSzOIT- [WkCߨ _LwU?+A%TPg< r9_y{yv, /1l=ʂ9v1ßUuY4du # u1hsY~WC C'Y?w~_5A͇_0:1HZfrjR#qslv6m|z]?655ͪҟd/`\lD @q@ r奚wRWʂ@R=șE-g!*ڍ~fx~88Orβ0kxQH(fX((t_$haX#G/mv|gG^vk{;- Lr`ϬgIƄ&U4n>H]VEeXM&.+ vWWW=:FI#E-'[4 .;L14u]FrLdR%sͯ~+m:>}EOŪCp\|>BX%u]XfHi|n_ wP`}=_)-8x_ =`{=?t({W6g̤yȊüG}A= .; cwJ bv c WW u+ `QnLnL1GMSյ,۬aMCޱa }?@GYC_0r:|逅-Ծsc^Mt2- ;Ü9T4s0_0歯e|gmco$9̝mjavBŊ7닀[׽;&(;|k;RФ|Y,{pѤ9xӻsYs<]i=q?JB?\I `r`fD vI3v>+| @f30/NrBr\1!Z.\2{͇̞;~|>d W_2G;3gL"WFE4~w [޺0'tM$E}ѓ2 '6ʌt- 6Y=i׾yO?aW?ǿvO~1 nvݾu9pObқ֣c{x<ύ ~uiM2?(}ZutP&ݺ94qض`a<*%J o+j@Vt.Tv]ws* өKFr1{tͥo/3<]@3q0˜^W0+]Q1kjLsb sy77l^:<m||/υss DQv ptIiB#w=ٟ %8246X7GՏ?le Vu *&i0@Cõ﷝jY9[O<, @וCJPZ'yMAP:$ÜaNzD}oVr4Ċ"QGX*;zx=\+1cj3{^}s yV?W`̀)Kyq@@G7sGTu/P +@^2tדB=(~(dialfoA^_`'WP{k'} -s?r'oB? ~@:DL*^0ߑ؆ 'r%KLQ:JQ PmAp9y3!ELcHGcLS< `\pRa:>x 6T9L'aWA@B,GGGpP.D&hAՖYձێ>0s&&ŁW'S 9?eҹ _Dc`$~ p#|w^P[躲Wc7QnVYx\% /Q?Ÿ:k Q EupXh?.Pg{_J\5  !]k SlKVaBץoZBaڤ6Q"Za H_WP. 01uuuyŅp `ҵtpZgتړ8 N%UINt]~ [I6?K9Ir|`|#}+(Q( )ZFm @m$A ގO;v ԽȔA]te-YGQ?WK==,pp-ó:uT?!  0JDm( th!aښ.65ڊۉg5)1K.]9~^<&CrY{"]P屝MvSSl[[[СCFu]]]s 5Ƶ\ aclͱMN9)b]u.b:!~`cnm·=AJ`0ԇQ?C!:D̞ q)8^MzjvöBlj661u~ra~+_K)A[{~; xhZ@+oUߘIxpaoMmOTG+е sGlnkz7Ll8# Kו M+<~COë!$?TWk@@^ou @@A~qc xr&9X(4aP.]a`@Z2^w>w~-~q;`S8k] 6O s=qJ͕_7Txk sR;@g }Gzdn;pp;2wq('_ t} |]@$$؀dl@O[wWTy )g@ ҥkuל`Fgx[l_4ͻ=J|ǯ]WM>US vA|15k>rjõCoV*iIҴ.]tMZש\3.ww~6~ ~[ncB_]H p @EQc|  8~}Za#D)H]t-=Y-nڞdrY~N@ ;lC\G>+uE>6 $F lD 〭>cwZCj6b WDGֽ?ٜmmnz wvS>.ן\8E(COZ@Ubp: 4ZPͻמWRJ )amP#~f+Vxkp7qGkk#oz" ~@ 1OFZ@UXڮ(j_V 18?7?j·Vhq]K^^O?"ywww<<΃5Wk .Hlu "b,6 J ؏%|4cw;tlB?-jȤ jNt×T?eݳwp[˥gq'%OѿG+U&la)@0lШ)  X!3HKmMIҰq 7CIfMzYrƈIOM;~ܵ ۻw3^v$(gPE$ר_nfAAp N8@{[l9 LdNM_jB7]klU[ȧQl$+=[[cVwHsΒ?P" Zl@EN+.DZ:`!2@}Ou ,熏wҵ? @,[}o3?`X&sD.x>l x@9upC<몾pX7t9!%+{h~o{GKd @ A*$ ߓt*L[F@EK_漽rIn/9XB w6+3?;4_g?ns9R#%?/&q9ݯQ.2)-`OC;E㑜06 +Lo[מ 8#-P2/&Jו*<?wޅ dUXe;{p=tR+;-pX;"r%Xca$8ĊqXc\7/EreA FD  >m&]VtuĖ[wrIy~IwCk.l@L"rh!P0G`@@ߎ>mVK`e>e| ʂҠLp3 tӗ-|4oԝ͜I_Gf;L6 ~r&Gò~~5ץ@R@[X3I(tQ 1e06piV/|nF7}`̤XI @:{@jl~6>xs8888gג~pyMȶR3aR&hp@ ρ4 7Z[uuۙ) |rþ>j^'ϙH^pqq[{Zƙ#KzGpee?Vccu)еl!H@FH abB, XUnhzV??\J]И:PO,ֺteP1߸+>qq3m68yB>ph5򽬟?&h<.V#P Ya#j1vXDruG߲|cޯe\,o'|IҲK (~:K6*,泛w|G c$Q]__??tu)е@@u0zٰAAp4=p[?7'f`ZDm^'5*|S, ~fq6qFqVqfrQ~A ]~pmpV#R0n$-LBƩ6_Vb-ʜT c&l ,ڢGp6qFYe;[Gi9 Cߥf/ץ@Uk@GØ0NT(S0h#UUg[[ @KoS$梧Rs,“"Cy;qUqDįpʂvjfABIcX/TO}JRk-9UKqN: 0A}JuT# c[]hqc tPK6 ̥{,":Q|=T:|VQ_!\ ,LlqvjWY"hI4Ѽ w:?_]W;1#)(\3QZ(=VaTN"/bonq8x`A[u6& L |$Sƅ#e:1{4,x@\D۳3czY"(To~8xp7pG:UZS@ %(DT'@0cF!Ä8@2w}>Wn mFs/ZFw^'3ϜìYT29]z% t^?meG35SF, {Foh=38;fAZRaم{BE@O.> a%@7OZXS>b(j zv[Zyz?Q>@0l=shYkh|规i;>Ϯ՘{ggg>gsIa>hSE:~] t3H XuY IZ4EVq\9+0 #n 1[m+yAKqbcr1I]x^Tȅ`Ƹ̛+xx5>/ Jc +2Þ{xy8[xY`@Ec*Tg0s84!(O>8'~[bRk u8=Hț 6s$00 9pF@uGuzn}=׾~zT wp ML 1ǀ` @9=#Ί}7w35^Sl9ׁ 7n9Sa[OoIxbξ"}-S>('>kK.]٬w`~-"zR($ y]b 46q_8_X'{uFGmؿU"CJIЪJ@iڪа޵56v33{gm Uzt̝;eU(-/6Q+8?Or( T vd.2݌U d]]xfȫ*tAff^CJ/LjߎgxVZB${5I=5Hҧ}Z߮41qW`^wl0?6E 讄lAܓ z*<8scpyieҽkWOOޞޝ^=j%L%A5mU8vfiofڜpL 2F)QZq~k>p6x&3³RNN}O-}H O>X+++M6UJoXƳyrAz4Lqz=1I;hΩSG7+{K\Q'~-{Mcs r ',^MS>O= ,X/$Ѡﷳk.4BiqB^kkkƚϯ_gc{&FSz}-D>돸㻦=/?w#f<ޒװ02h* 8 ]RVj[@A"fNoeW+ ONmybp/AV`'x 4 9ǫ_va5"xqauDk^= kkn$]Xtkks-ko,|}fU$x~6ܩ BcO=Isϲ7,  v`Ya#V~AWuݲ7&4;V 4}k.{J3];{Ŀ\~\NF/_t{9ɯ:迉o_~0HV5ӟlf0 ?#3|cp,~s\8'΍kZf\7#7cnb?ss=Ľ|ɕٯJņ#ۺs+{Q5Og7, kȫ `ӦC׀ Fla<%H1f hJ Y\WIzJ$Uaw!NO!XA7f7f?+=f9ם܄H{?߽ZQv==>1q>G+ pp(+*z_Byy&-{}O‡K(%~>LI|%+ڋŽo7, $hnL`@  @Ȁcz 2Q{ :Br\!Px`"\m=i^;J9wtXbR6׼ja AiM֖d5j‡'~p&|Zkߓ{/P}}ro5v5M^ziݗ,|yWw4a=3[b&|ð0rGUDAm)0@CɅ= rPƿp8bA 9gҹx-;̼3rĚj3Qk}uo7 @=(Po0ȽAC x   Փķ #&xq_o9KNRO1G^Y~{BW7˾պ7a/mGeP$D! *\ $1}/ǍzJ|Db@/xZF&{ð0AA*IHȅ,h-EC.JDM. B5p=Z9z1pG }aX. Jࠅ$DŽBJ@R~xfawh#yaXA&Z![8yi%u!nO0, xBb0~Ba`aaaaaXaa`aaaaaXaa`aaaaaXa+ :qxIENDB`gottcode-kapow-350ecea/icons/hicolor/64x64/000077500000000000000000000000001514263554100205035ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/64x64/apps/000077500000000000000000000000001514263554100214465ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/64x64/apps/kapow.png000066400000000000000000000133471514263554100233050ustar00rootroot00000000000000PNG  IHDR@@iqsRGB pHYsttfxtIME $ bKGDgIDATx[ XUe?/lWE$ *>k&Ѧ,EsA6EEp7p})R1W\Ssm1T{ D5}s=}{ aM&G+@ ֵkW{˖-֬E;ڴi׽yw5s3~[n%,ŀ'R=z~(:e/ֹcwII RFC VcNiŚS۩KsBeD=?c0sэZj600v u\!^^sVeH!W}Zve8pR}=_lff-V;̌RBA(QKEb`Z%Q-4UtwiX͢cRZV;uAԵ+U3-ii+cHDv* ?m 3k8(KmwJ vH 3eRQE7}B3U ڣp-QAyͳ}\07UM5(*%`sL5|-y­Nm6i}&8@'i˲鸇g,#4sDm4X!R,n(}c}Jfn+2[-P\˘4C#812(v|,OԬT=IBڤ4JLؔX׋'GCצ3BڥpT)ox MT͚5{MT1F>cجX1S_*tXBGGSFV}ᇴpBZr%_>3ڲeƵUVgrssibD96bT:(B(5iCӖ ( $'HA.c#Slb,͜9,YB7n;v޽{ta:z(Ύ߸{%{KhɆOX4:@ V(O=y Cp7YR!!rmgj-lR.?_CӦM˗Sqq1۷9Bǎ'Nӧ髯ś&qԩS2YnF1bh+$.ML[,lP5<CR[ܳh˙&Ma"hwjs4 F TPP ]zW 7з~KgΜp1wۼ>b}awqݼVNHaqavDŽ"i<{dz|fV FN>&yݩjid'Ȑڹs8U!8ٳӹs$?^:|uphnCwϖ4@ӨN}x[ b h2gM~0.m{N|ҵ1U^Q"GFҤIhմgiutkO} $ifH>RN吁=MjN05W+Xg/ 66%CHpǏaqŋO?ѥKW}p#oU~e㳿%qY233 <9'S|~}VkC;vvX`X\jy$,k)<67r RYYY{o#iՊ 0p@Zb%K dR+- %ΐgMy}.k#Z` #\AHJyaqSpX^^NTYYIN*!F W]e*o(M3ϟOc b1+ -VB"*GWK˖-5 1*<%"`x ՖɢBCdIB>prJ!SR UYH16[#Fl֭Qp{S}>]w1h-V[aoQ9a`4k,oQHHsz * nV,}kvR|@3P6:'Oև##!KG-d_Ɨ(-ˡ.tRW6y-/[jO!~1 ~4FW$ "\j=#3Cf[GƒWg)R饟U@|4ϕ\*'lTա/HYBcǍ%GCܻZgȉgf}4=݌#zMg/.qb:9jTBe3W?QS]iYR`(<t^c+г. ypU @Rfbwp@2xpG(}A2,\^Ha,+BJ+7dj"0eOS$̮4A< '䦄~F˷2=Dh'tNJJ}}iYiƚ 0K_]5S&RG@ۗmFZ?<[QxTP[Rц dAL_͛OSdC['ysUulMf@wXBf=l(*eO31eu- m^x˞MAA:[L)GK(=>y^v,f<9P* ;'P|yjUl4$~tqSoy9`i=g?%&q䩄4pRUjf*]w]1GѫJzܝxjԵ5S3:sLʫ+³*r-rS8OYU ^ǛE:DLVY̖mdLblM1tm| /P!=vnШ- WˊbʁM&'^` ubl=TXt~`U$s ph&h[ x`61UɐcdY *U^D(!S,=!K׷jp7hh6x/ -ZD=zg`ټ_^g Z\E4ZVBCqn `a/É*'>L˻T=93k+(^ڿx24+46QA2GCOHVdj}-Hh3ɑɓt#dgYXKp E \Rh#y: *xװ]ۺ:6sA}u}Ì}Ac:/<N Ɖ+]'ڠw+ޫќ) ҥ"p ]t_ Rf3cj}?xBMzko(`8r]fY콜5k ƔTkCWKȾ ]53xc08j!&!UJiu_CѺs]ݿFWBvvId/,('ObF6Fpc08cADE$qcPxe@Ҫ]n8S1.-O9jhXmB.Rxk,=LnTb!FpϘc,paHvz&9dp<"HMĵ`oj;FZ`$2tJDٴv*OQܳ npwII4#Gu7J$ Wl9_aZDZn_#kZa%)%=wxϚ#v%MٟQ56;ֵqpǟ=d"!21nޗq"ӆe 2)!3#$`0c08艳D4!2 ˃vM<3~H-~_kѦE7{OP "C S&㯣SDY@VetDUhX&5c AV3åR1hp`JHMԌTʙC9s(-3'{={uLგY2iA.񦴼CMs3CIQa ྀ{A_ 8ـwdU;1aם`г8tO6e+(m~.X i~ZۋnMk߆2~S $O&wCo&9*8N { 󮂺pYw6龜fG\a-x֋!V.CfP [hƛc^ȴ=q84,yns~EИoy0MT7,cܬˠ~~1ëM}eFmXO;:;usEq犣y *FZ˰蟁1_X\w{c! Gо%)9 uX>=mug{KSW\DU=*jOBO<B; 8UV/"5B 6l ϧggȂқY)`C\TpI^{xF>cϰП4>v'h4;7Iw$%g<эh. bknnSx8~3xc+7eiֽ{wk6}_WALIENDB`gottcode-kapow-350ecea/icons/hicolor/scalable/000077500000000000000000000000001514263554100214565ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/scalable/apps/000077500000000000000000000000001514263554100224215ustar00rootroot00000000000000gottcode-kapow-350ecea/icons/hicolor/scalable/apps/kapow.svg000066400000000000000000000307731514263554100242750ustar00rootroot00000000000000 Kapow icon image/svg+xml Kapow icon Graeme Gott 2011-10-17 gottcode-kapow-350ecea/icons/icons.qrc000066400000000000000000000002011514263554100200640ustar00rootroot00000000000000 hicolor/256x256/apps/kapow.png gottcode-kapow-350ecea/icons/kapow.appdata.xml.in000066400000000000000000000141531514263554100221360ustar00rootroot00000000000000 kapow.desktop CC0-1.0 GPL-3.0+ Kapow Punch Clock

Keep track of time spent on projects

Kapow is a punch clock program designed to easily keep track of your hours, whether you're working on one project or many. Simply clock in and out with the Start/Stop button. If you make a mistake in your hours, you can go back and edit any of the entries by double-clicking on the session in question. Kapow also allows you to easily keep track of the hours since you last billed a client, by providing a helpful "Billed" check box--the totals will reflect your work after the last billed session.

https://gottcode.org/kapow/screenshots/kapow.png https://gottcode.org/kapow/screenshots/report1.png https://gottcode.org/kapow/screenshots/report2.png https://gottcode.org/kapow/screenshots/report3.png https://gottcode.org/kapow/ https://gottcode.org/kapow/bugs/ https://gottcode.org/tip/ https://app.transifex.com/gottcode/kapow/ Graeme Gott graeme@gottcode.org kapow kapow kapow.desktop HiDpiIcon ModernToolkit
  • FIXED: Did not save time data immediately when adding session
  • Added option and command-line flag to start minimized
  • Added starting and stopping sessions from system tray
  • Added moving sessions between projects
  • Added removing multiple sessions at once
  • Show total as hours in report
  • Show decimal totals as two digits
  • Replaced shadowed variable names
  • Switched to KDSingleApplication
  • Updated link to translations
  • Translation updates: Dutch, Estonian, French, Lithuanian
  • Improved code for building translations
  • Improved deployment
  • Translation updates: Estonian, Romanian
  • FIXED: Did not quit when close-to-tray was enabled
  • FIXED: System tray icon did not work in Windows
  • Only allow a single instance to run
  • Replaced deprecated code
  • Translation updates: Spanish, Turkish
  • Allow higher hourly rate
  • Improved Linux deployment
  • Replaced deprecated code
  • Translation updates: Italian, Portuguese
  • Added optional closing to tray
  • Added removing last report
  • Always allow creating report if there are unbilled sessions
  • Always use exact value for totals in reports
  • Only save when timers are active
  • Prevent adding or editing session after start of running timer
  • Prevent starting or ending timer inside of existing session
  • Refactored code
  • Switched to Qt 6
  • Translation updates: Czech, Dutch, French, Lithuanian, Romanian, Ukrainian
  • FIXED: Did not load locales with underscores
  • Improved Windows deployment
  • Translation updates: Italian
  • FIXED: Window icon didn't work in Wayland
  • Improved loading locales
  • Improved Windows deployment
  • Replaced deprecated code
  • Translation updates: Czech, French
  • FIXED: Automatic high DPI support
  • FIXED: Crash when adding projects
  • FIXED: Crash when removing projects with multiple subprojects
  • Extra warnings only shown in debug build
  • Improved Linux deployment
  • Improved macOS deployment
  • Improved Windows deployment
  • Translation updates: Danish, Portuguese
gottcode-kapow-350ecea/icons/kapow.desktop.in000066400000000000000000000003171514263554100213730ustar00rootroot00000000000000[Desktop Entry] Name=Kapow Punch Clock GenericName=Punch Clock Comment=Keep track of time spent on projects TryExec=kapow Exec=kapow Icon=kapow Terminal=false Type=Application Categories=Qt;Office;Calendar; gottcode-kapow-350ecea/icons/kapow.icns000066400000000000000000005322331514263554100202600ustar00rootroot00000000000000icnsic07=PNG  IHDR>asRGB pHYs  =IDATx} \Gu}zz}h-%YƶdKI $/f  q0 `-xllkf,=3=Ӫ$jnUZԩ뺲٬R߷=ww]4?ɷtR7a#m~}ۧ0^mrM7ogtt }D םJ~xhM\aq:^p :a}?u_pvc ݀1gl0{U\ib.]n48x+z=UV}A555۷o?#C¬3*sؐ?l (4͙^ȕz3%}P?(߭^ݿb?h]]]Ν;*|Sfk˺>?1_oD}=Buu6y'`Z] 5\x}_g:rzi#?lfg`&F Qu KɜÓ])haK|7uvz_F'ޗ@l2Ζr8+ J{0cXHȥ=J.=ϬN$}- ٰ\! vQ's$d(;dG0ox·Ԕ+ d2.zAh~joo8(7e1c|adt}3]3Ⓧ!a2C/uUVzVʪ*%ˬ @{J|Խ6` _hclp!{2{`AɮF^ A# ^]9yL=:0GUXӯϴd.H׭Pe1*᝴4̃=~ܷ@6{6KkՀNC~N @Vg'j2WW22]@2]Z\J`=ll+g>4SEL?+ME`(䖧|}҂o?غMc9ub"p+V6D6Hu>{>Ex\]z`,}ʵ+C(M>~TޑzFjʛoo[pAGcZ 1ր)ҧCv ^گa:!q*0 {͚5ΆK7zY8E.M&C%|93,7foKZe8o ]g Sgs`t D,î3+P/ؖږYzI^$V* Gn $u:>BڊkeI?؅@n!'' %)i 3ڡًg?PB۸F0%)0% I 1^۱`6Qwby2n#kWq Bʨݲ[sJo͔קWƁreY3I\PzW]=6C}}r`ڞS8U=,ta7 zy4U.X ޱ],:CŨMa$(OFdeJykP 8Gcj\WK(w=wm ^AHK{/ >SdZy3sޛ7˺ufX@Y@{M,^Qbf朗?iq)+аy=W 1?("ܸ~㒍C.Oѯ"~1 Pzo(Ng(}S`ULq~#-P(mf)S0,KƠ[/F?x:pCtE{xT+Kbc4˻9],G374·'oy\\sSJu :ZUQP05Vg3$wG6Lƶԭ7ٴݜ$-ʥӱL0IG17c*Ɣmʖ 3ךiT-lG}zC*|heb.3*~Jb)hlxiFLO7W7n${Gv>"r!أ'#A@y?8o࿪VaZ x)&4e3r`]wug2'uS4Ows\V 84L7!4̓@QpK&cfv}.Z3.ٱ=.`?lm&F{q a>]ٴfz0thy 7J2AIK0D K5<{3 e.0ۜl6RW9:AgiaN1j$ N=yP ?gt!#lNm643y2x48` .{15d$ JVvhԏ ?4ZD.+i߂*<-]' KOx6=./x PkoF.+_PEa(XQB/pJ\?|q(sbz1gYa2swuL'prmm?YXt/:̫'賺n3qdž6JWr~w"?JI\́D02EAcA!Odh9*M' Gl)vM*mIPGZ\$~r\^y!Ww >-qƳvzǠŏ\TRq $ݲij1v34@7U 3Glƚ\1 yHh4 :yH-=efqgV`U3 j8;fA0sǟroo|~z͢,y`M :t-K1;,En,YDp )O` eCN1^ !u+!<\p4:\Df=L0SmRhekM|tWmpf?_Ag}.ɍ7(|WߓWB޵]}YkW8N#e; 7l)#;0G`vXeٜeryr܋ Y"4 ASk:S`yG&nb%&bDzyzL'*@Zx|RevYO86C询_.!^|mYն<IcEW2[X6x.¸niinM]b477γGtǬ2Cҷ,Xwԛ^}vms2f .*[MA޳y?.\ "ܵ.Iɧrn[>vq-r!W2x~79>ðjkdM4,\Јx3u$ N.;ZҲ2S)4EQ?lİs |Zͮ*Ŀ\#fh p*\6BAT`՜4^ ~͛7&TDgoω|Ÿ?syp>%p0lO<{?.jx޲; Y\XZp\O؃WMNϤJPIS镃S\lm!4$f>4IɰdjBPl4]6P}G]uba4rJ@o{69>Hs&JʗK_|O,d3h n'`9M#p \,WνR_cDe˄ #S{3gZ%M 8;deLPy98P~4)09_h8 ;uCś9b~ӚdU˪Bcvd|r,e1YtwRUWeZ6]87$7j휵~zi*zj&4aJϟ߹NtqF8ӒhCI0@n8xZTpwseWPQ*Lȃ:aL~HN?m eyC­O*ߺ[rڛHAmmbz8L7,Ɣ2>OV5+]!-7"~ʕ|9 ǟ画gJH7j[4r BQ7{nLZs4,{6./d2wp[؈?[H7xTbGnǎ<6aQꅲ~zp`OW?Fic(L+zXz)tT-nѺd]&?|3ة˒ u짫Bd YF^]+zTKo+Ww\2Y`,\Јxw"_:Ō_.8O^v`uYWڕ0:2%VbXa/*6ep: ʛ9hْ;OrӘ3b5ө)y;+{e&X \[ǛhSØ) 3qXӸ/|[1@R8Tr;XЀ^ȾG(.S:*7fg=R]Q-ןoܪ@Jogꖡ.P(#Go|ϔڤb/j+vZٴdfZp))Ø bǍcm"ʡLrk:_ǣ6Z^۸Tq_, ٖmaYaz̊J!Op 7HGw%ۏotn;Yhʷ]D Y'0^N7~Њ\d-G ra & gS[l+ǑE%VR{ N{XGp+;Yy5FN,<~]:3J!UmC⠄ fudY{O`y{NcI?rOI,4?F ,|iÈ10S34NAsյRmxm I#vҌ,vg4› `7J!E H -te()TÎ y,;+WXPx?ޞDEi\ȗ0JGۢ?WgT.Όs%\JS?&K,k!0Gfs<.3Jb.ʵ6CpWϞKG>1'm='|`>!b\S.!%j).LTGJ~x{>`.AP`-,>3c8-Lh:_am83 3L!C}*v׊ m,,g38s)\xم=jpO Ј,4HHgfn̵SXL\|tę;܅Z0 CHbXDTq,h0u +~tLxtm E?{>5} G\zЅ T_My9t}`s:lbo\o3!eZZZFАPGhoBQ)H n{]i']](!{n1DVt]϶U_s)4Zw:泍dz&.ip<#P`s69\`MLǃpK-"SFRLcIJۡX߳}C!.0΅;e#mͬ$ lFLe)a6ubò3ТOT9;`•W}s4qv]̬"|JiK' U?.mqpѰbFZ[ا^c:>ۜ݇|߮D~63[K,{YcQ64J˗:\uOF wcevJaroR>n9#z;s%DC ]H)6lN?ɤt :Lc >>nXb*Con;P:tEm&\2! GG~6\;|Y܋šՃeOBdweeHWK?r}$&tД* Ht[3gZ] {\΀@DҥasFJ'ror{sc^bTqZ.{?E?t(Lv~@0)Ë&|0N׵_taN'Ń0*pͼEnz&k>hǦgHpuX AkN f[ҥi~ui)ucGy;ϿSǡz9j';H[5|3~ ׆u4=. ə/| j3IxHt2\uŠNSAϠ8o4m е-mLw[gVBV떾3?-+Wa#0\߮`9~DI<][#O|I~;!D2 !fhx[eCyɛ AkTM{oјqm\y!0{Qi4{ jU 0Jnn\dD)P.o"j- _]ug=ʇjG(~('kJ?J7pʾ-u ߌ9OLXB&HpV~"XF{viLCRȂGdFYӾ|bh(pH% .W6O^DkYF@iOpױ vzVZ/"C4E{6܋=ݤ5.ދ:%&lS@Pn p5wܜ&J R櫩6ȢgAm7ˊĊ׵J^ f}F6.pu x2 |ş--~H:S1Wti@[ǚ4'ЦCXG&>rPJ-ƅdN,?wh(\;$J.?s7%.`pjղ0 x d2=cPbjL~mOt|}Dm6ٲt}ӻjd=_$<;9+~ӝ60CӅ{Y-INEu`K2th'Вh)>'~%{ȁݏU^VOg/T8qu&kLd܌xXJ.KFv.LJTM4 qhzd\Y޹\V:9W)@59NWA'{=n:&^(PXOr# #>Ə7~?ɳs>P3c -u0 \ӵtYT e}]2 :q4!FdY2imTDQם)+Х!*U+"=({JG%~݀N .dq`-`HŸ_lMBf+xh"?Zz.ˆ:v|/3L@tD~JMF#34<-J  I(H0@o[[ !˜q`,WZӾEJTbvPZXvm ̠ҁmbʅ1u;[{4A"xsȗFpTC/{<о}s3M1s,0Lဟ]&.^x$\PD!LS[b3Q:0.:#{3iX2% *+? L?NdMk?^ugEh`bv]΁kA&4E\ Vr(u0wѮUUz\5t Y3fShC5]5޹]e @pfd[)eM}lq{ܯ0@)/"̬J% A,NyRkzZz \n#bxz< Q1ߠ? hӍ4<# F)1Dy;z?j$Tq6٦fx1.O3XSu_/st<gK+Y3dc&#pCdՀa`hUk"TUK~03ҌtCgk:k/Bo"U7x{L{iw?cS 'C} }7V.0!Wt@igtub4Co~p岮{g :$^^bHbG ] _ v}9< K%Ut&`؟ygT!BCG0;ׇU=gף̂9k 5K.!~%Db. A<_[ӓg|-.p17w_T UF~YhaĴĮ*hj}{=-Z<#pه90j58 ĢM#i/EN^ φ=]!<{4T(u.fI=MzqxŞp9wq'Q̏p %s*#pI$ "@jRԤ]9ÕeXSBS50?,D N+ .Wsttg~@7>bGE|Z8Y}zy/T?`ub|N*;tslrY)/> ~Jh RBCJR$ HBBN<[eYu=GGґ,z֞=k{n\=<6=z`N\=0'k\ 9c1v5 ܱt.8dZ,-/d:NWSO=e(- } Y8.e57bW\ȅB!`$Y[ L̛7χ㶰*s`73JF{zzF3L$, ev90 # UfАz.Kvtt$5{+ 'RD) g׃_fu/', blx%_gappS{p瞋 `G2)y ]6922lkkKxwZNʟSWJ~+3 #>-pETl)(/˷ۊG[H \HfvffUUN o W}/[ MQD(H[(L B:\`0f 2m5' 5-ФLF(<#e2o2tq5q-ьK)d2rBb(u97OJwdlnyDƀBNuAͭz҈| [,k%PK/洃 ğﳺޫz8]gߤg+vç[!/̯,tVh.I{p2QCmC7~3nDčbr 7y #?B'|_4=hNyH$Fa &h`j,+9ٜ{=0'&q+h`Au|r`` Z5sZ^[7@AÉc٭ٟr_>(/D ̜>,0!@ P sf=0'Ё(5ff kx@ˠo˟>./͟Zl*o&AMe24۞>[yKŒl^ヲɽf<öKP?P? aGX2O =rS9a@N IXS)T|6Ĩ?l[5ws|贡KrKs 0 B)bl&' W%~:S>P0 sG3ѫ0K  :.Trt̜@ElϚlɍz"}Km^s^[;Wk(ⷕajz|F 0 3jue@fN{7ھ3L8AiT,F:afNcQ೩5jFӬ(gBX_ M C]mw'$X0И g iJ^˃9A>Uz zbUb_{ e޴Y83= =v,Û_,@@\2ԳMO5p|/=aq,aNs l_X.>zrks+eOr\Ǔz @ac  ah&NjM7ݲk n }W75VQ"O~۾ s  fO|űl/w kƑ#GtaYr不*hΔ{~2n'g>}.*ϟ?;9: =~Ivm5q+c^MZf* zQCp6+眩l4f˹W@@#(k3n翶)~4-:(KN * ̎Ms X-={d~?K͟6%?Ծo=s*:--}kZJ(19;6y!44-a3KE/uAp XJStѭ=yfใ'wf,%t4LTӿ&h'@j$xzގ-xA mR0@WcZs |B ʬ۷o_fVW܂B{av]y`M=,NsWg̠1A5akjWu;]_ w*f4~%T*[S L޽{𹃿p_r`Ӂw/mx3g=gf- nK7tBz%4c~Yp))1AV3~Ukv/>s޷;<UK6جcTQs #0=Uf[ίu]CMOhiN xEyDe7W=sC~3k|T}!@Ƅ4\N FnK]LR* DMBx Ͻ}K=,Cp߫ʁWxڀsrT3!@CA. ;no‚,/Bבᐴ‘cE)ÿqΝ;kn0~h=FV3 bysn *˂]]^i*_NT~_摚!^4 ofv%0̜NxCW,AyůMDOW+ۯ,r{/%J௨:kAװwJw\ ` fܬNxP-mֻ[i?.=Ցp&E# KghO0 j{|@*9ڛS'C&\WiIp/Ljojx'\x;eIe'tvlu \ fx ; n GO^XEd/%_p bѨ u ?{obO@k =oB >LZ8My 0j#v),xZ:ɛf!@@&Yg-v+f̓GJ7mڔԽmذY8.{#yY>0 yT75 ̘@۱*AY0Э!U70 eNKf99A2AX9%牑x?d[v6E`c>_5/ﻢ.?aN`L)70( oK,^ fy&z!_FV*e ӗ;/X{kL y w oit*߫rDŽGo|K{6<`6rz38-[fw,^i^[XEEnarkOd&yIWU.cG`q(p{ {^Sq==?}1s #-n"HL+82 LM0&q,7W|xh^N*nw7*<cvF33[\4={e?/>Oe[ZEE+R&䭘RH0PߨGV}kqnOn { {V}t˧o;eɢN* T7! 0?js\1ymov[ [3B9cE,3+l̚0ڄ4ˮ&h.B 1F֋8lmNL{}b6>p/GdgMj{6vyH6Q\;1u[^VgV&`7 ',tƒ(YPX4 ݖtiD 7V#j,ʒʹ9&c_r˯h'|ۥG+0t4Y)|R:E զuB1㲝{`g1sV%RwrP\ڭKsOwֹt* Tm` 1 7ͥL荚 z&4 z7awO ?~{zio*/;RY4jޱD&Poe,!W_>8OfP:Ifz\$ww}K$~cfom"1oR rt;-};9{kʹ:efC? ]GFUan , 7!7C4&M#nI ɢgYGfӘ:~alY!B=E_Zev GfUkf_Z,i{:e/WE jkaa>꾶ىٳ݂rf{6!`q> i5p 1-܀RF ` N/=8{pA7X,k`6 4MV:Mv S(|Ncb#gf_J}@gciT}f|6gG7&7M3C]ͪ`xs54J7?n؄Ǎ550@`@FRAȯe49gxgsoy:7/YC}wB`h(?oꭾD⾗zG%f|f<1[[exy|wn\y0u.񛵙0X0,~*Sǿo'@07n8o~FC{&G.S4i} BmO|"ΏG B@/ylvhB9sg9mڸ={$<Ҧ{/ȢNLݝ:ߝtk4;fz@o3nQQ@oGMȗ)fրiE χL{e:dm7&x/6w>`}˝}JqP'Z#]G^q W$/_1ŒuCg~(;:#`#9Qu?/+!ʸ .pf?& B6Fqc6{f`7Gnӗ.;27?ky@^UhԆB5 (<7G vhd=|x5KTeVʲaHum$/$`hr/-H/vL'x1EpܗsQ];>Szw?bg GrM`C#+p}q,{[Դ_>  Xln_<7K0,NC7}9Gl=}UpNdYUh9d㕅W'V 0!?0O. *u$y¦1|+w@j[g 'ƒH^mm  93)*;)eG˨1}u#.M^Nl:уۀof· dDo5c(%mW}U.3ڔ.My;cݘ_C׫s hJz]UʽJ &vqCM+0W4&PO ?~P۟KIJAЦ# eM 5{O/Bɬ88bz;bE ^󦞷_كϚfxGj c .sO ܹsK_---`ม!ЙXz8EfUZEǍ8h_GHg/5_ԶӻNwέVLz 0Xѽ/>K2thWp]EB4P  tw M ͪ<džke95`Iw)嚲U]= k82l0FiݔMkϫmꘅ7܃o"I}$oSvT%%Wnp@n|nNwOR@na*uL~-};#;~[*F%ͮvٞ3c'_x'; !C/S^62ԻY*~1JF3?{,/unڶ*,#1YX//!O7=~BU^ZشiS򗆕rj%j_X\P\}MjATi~$:@Fk#o'ҦK]kS# af,|@J-ᘸRL)zbhLI'KJ]zzZݝ;[됯bypgNwgNwaBFv`~~cO hAX%Qj|F'%h;$u#+G֤Xt:+3\3caQ*K=ݹn]wKIgf"baV钨S꺒;_-̞Xxhp5$Y{}wnN gluCp:wn~c?KQs0.G 3@-b_YmW,8A+zS#OJ9gP.[]df66TC4>Bf'`RP,Z̄nҘ ݄EY8 u?,-/+T7q'?5qԯ3HwzJC`BjI0w% n%db;kuHnDLq۶m<1\?cbXܟ"KFFL3PXƜIC )3뿠 L+ W3 7z3>~cFfm]*/S#-(>zWKڕYm>O)Ӟ5JQSq,f6F#JTk׸>2OiC-N|U@0`_QfpS0՟$$Tr<\Ah`3#@L̰W4@m+O+{}0#7՟.P9jHy̸WO 7Лoʏ@WCnQ00qq7sc/m3q;\nIbiOowpK5W Bw,gE&J` }rIķ]E˕jY613[G{ۙ\o?oo{Oq)gd?`W}/]vW-A'$*A28oQ_`{4͛WQm7o(>FwC 7L=3qZX#h5q7 pbIPKS٫Gv#7/7o6B Cݷ7ؤ ex03eh% \w~/;xd+zPKRUibdoIo8jMtmT.Ǡ̤tvɫ[du>^-+g7ˌfCʯ* G8Dž30]\|0㿓w<W\'+] [ J/qa,RLGӔbR`'/1xF Ъ5w;|VzjnRp`arwmzq`LLCc1C3F.r=Ls 4C`<DBka}| 5A6K `MVPyb~«I'[0p ^GSĺ!,soڼ̘!>G?ŅVjKjyXC (,k0?toʾmmÄƎp1W7+O|30 O?::!:uOR/2`n fTyL(WjӪ͛vE~41~C~:)1ߕroHuv>E`$T~1[8#1q 3^-,7=C=QZϳH1 /4lNovwe F Xؾ>z0` %  aCE )ߗѰM6PjZ__Ci\v`SniL/L_@0lpϚݽa nA˂ m6S~f|o| *e -}H-Mhx0FbzόsP;qG16 ioLѵg<<<1Se<4&_4N ̦MH9m5c5p# j]?Ql-v]v_ c?RԮ?e.[}QB"M6CK]故w őcDq~̄YX-*=?3 Xu݃O>?uF1ivv}mknppLdm6D F^Gx j YaM%%yӪ7k6:f}gP0UQ1 eyu6جo3?W{<@@oXJ\Z0<.,ݵ ǹK m%6Z%zcFw]:wLBl 2a &m# iuGG!6nb40)M hSѬZmb۷/+1pɃ' ^陃 nfU` >]4M]Fgp !(*K'.M\X0 hxyo?0tQt>x1FiKU!ƚ:K h&/l=0sm"4z&ò.>x#~P][%uC&Iu2?rѹ}o[Y䛾t2-]9r;!{Bec g~f|ʭ2`3¢Q\-7υVڸp{{1uHm|ðɺlFȽMgwۛhswbӉ^_"Bg (4! +oSHnR9Ui)˝dR޽{y7% kvs:=/lLυ1Wtad;3sgn`o3>c~ܥ揥qaqi0.W #|&'pہ!cjT²n!?.aԊGW,vp_3L[i+ @ :&?fدeڵk≆4Z`(*f.дYnHEnkGݥKNf|fPr5\=!g8toة4򪇆qMu plm6Dw^sA-)C[ZT_[ /c5k?`Z U.OHR$2x>N+U\Iʙ_O5 e꺥GwɽzծUڬR&X6[|Ƃ>MIW+M#yz612! l֋ק?0b8 gs_SN(L/}=bܡ֋[bDb&T*looOҜ[}~p㏚2`6t,~fr|iҪ1m쯧1j౱{6|>W #|"6=^:q*-(hX?L;0O&t-71fy %%c9ẍ́]i_ke,5=@IGhP"TIι$K^=|AE12nF0p\OGvN|65w%_-a^f*T{p_T\|;0$qɾE~ƚ7A.fx!0FyrF_ X쏬 % շ' '8Te| _ގFiV̯M%Kܥ:f|[PzB?n 3a>Qw?̣Qnm_p(4"G^s_>TA~0^--)蚸W$i*e}{B 5FLYeEm-έZ;R~TU#Z*6tR)+{mt07zDORW\DhO䙸ɧ3|* jSp&'..,L9YHJXR/l{u.ƭ1KF;|TXZ}6%AV,VYLLYM-+ڱ}U5de~\6rD㲦e5 8n0DC7a'vyT[^aZh\8'G{?j~ o2ZRϚVBo@fz)ʚnC a - +,]-{lGGG!x/ouIw7I.j?B՟;ŕI{ˌo#`z 7c_ٳ>w=y=U@- N5JUˣVD |8aכ魜-lrw! VF#HM/% S͔2IRjͶR_whfeFԄco^d"uAemU~[T\4x8 ?gǣqφaany?ępC-,J{ x10K(rag? 8N:1ߞ_g`i1ԄGBkH_V2666CQMOJM,8OM.,^j|BjyDz=`džbWo-MLN?3pMe@e3pӦMS柾ڪCtkT E1ttʢui=cA&š"&qqYQ{ި%<]úXؓ 7+7 Daq3rgMV94xna{/EkÊaZ1t^2T%\+>@;!JL!D!nbB_ڵkR36Gk8=GͻbDzV|ZyőW|2IH'hYx ނ<1Qxo: P&r;x֟=0X^8P&+ٿ~/v&G[G;t7 #;ϥ̡\emG(0KSŅχQ⏤{z941OPsGiGz&f7=o+?uй%-s& 7;bB ,}Q3 !QrҬﻰh>01 7Ԃpٿ56nHp<@f{4#aᛘ?|v2n+/v$-n)xzѨG6S6n Sc{mh3 12ׄb;M97 #_.W::`FXFxFגi:po'Ѝxza tw6@642.ר0+Lk#ﳥw 80Z hT LA)P?x췀,&#OeЪo/9)Tji`Sncqce@1`tV3Ѱô㹣a_1kth\aD?7p-59/lB1\&{O ny@bs] /w7ef&JbR~J;ps|-Oe=bh?{lךj!M K8p-MSr[9dPd|7ô7gAO7}Roc*~Z{ɉ"\PA3<{ "'TMz`ku 1ri柁ܤ36;1  m´QN}z#z׻=;c6c#7703JMW'7 yynк҄[K~@B)-\&0{f̔m;멌_XC٢` YA46+=qǁ/ fjO9}=zo{|87w6}f4QZZ|\=Gk h{M߫hQMKH ز8 TH3rOJR5R?ڄ7)(gC …Qe~t?3 :2ju #.. p 3.In͚5s=w‡םnGkף񟩡qѾh~L\x{ʱgCWNqk_ h:ЭaЖts6׿}umk7o+ T̤U%ޱ8 R#LK;3\`;x񸍮۹sVK=?8 O_-oF -*^^@IDAT_ߖ\gOH04Ϳd1VW{ ؍"L0j f nguO~e9}z/m_qpo۽вz)3z@b%m,}eE sax\ahe죲_y+Ow%s+V{,N;4?PT~ݸsk׸G>&Z/ mXR]ҪcRBP=EtM+(_Bdme~ l R\*Dޒ[5zo7-j4a)Ԋ#MT{ZxyM6y!_r=|%i@M_t8Jt:S>f殷`K淼eGC Q͈giijwanAiK/,ZVm= jt_ocē|NL&x!\rTlIZ/սXj{%1"6 Fx-FI83 A6C[XH-Z=y/#]nI:BBϑX ,ʧ?g[9"uMv,~q`_-߸Vͤ.ȯ1^3nz&w߶d|r-okoP70 e\s{d<*sLy_<ߝy8HtH{N&eKN;, ỳoU#֢ˆ:O_BkzɷZRҪ?ӗܽ{w*q @ HbH!Uh)tY\\RC}6(6PTap ,l\4,W;s{M5|87>wrOk.4S ww|!3nKfqR3S|N\qFd۳nݢu® Rի… FՀOFx,{]ҜhʳX?UJ?~'7o6鳼ChPNyk T'>_+]!Z4dZ*$"C߀-查|N%/'+_uv'c+nmm6?>Ϲ'u 0nqMflrqM>MOQ埓}Vvl4̤RnŢu-\*YZwuu9T;2c #Kc~I '+OZ9=ԗUC+ZjyRBMz%Pjz@bʕm۶W3ËK' t J9ѤM"30(fJ3hyq~h?}}gbt[e_ĝ뮺wx⸬yK?P֗!=~<d7no"J&LE ݆ .(iУ/[̫I3򃍿Q\BdyvmLZ\MMO4eTVI\F`MS$!d_/ t t2aBK'mQ=:ʇդV%/T㭜jmyMG?o˵kݿ/ niKNs+)Ur У][#fp˫Gk ›辢 l44LwlrW @K!+]ڜJc2u\BF Glp`VԊg,OGi=g&.R/%*wzex~}w?^q+V n׀0ջ',M-&4K1[vhm&͸6亚8r+q 1ۘGAm%]a%f 6 ]uQՃOVHU16E|VRhPP/2:i*馣+BKGep3CZ!Mz>WF޴)+ Ch/xm~]׾WeLoY,^0aT:Z\^e'TƘ:@ϙ=B>0#sW28Hg M]f5 >.>c}0H.-N٪O [$Mh نYnEMP:yE G;m+tJ3^]9>k{9mnF݁?x\7y^n~ߞ05Svl:z6.2 Gvٞ =vYˀq^ԓg-e~< £ >) [lR=Ӫ `þ3 ~@ԟ&Ȑ! S脣[e˚Hx,`A3҆eTKWO>՞Zlw}g}?PJ8dž?wt -:ztCU7=L4Kt-h֏LЙ׭[)0QfcP n4pi 7(lzlg 4d"ih t~N}o=М%bT1-W7Θ*F:1 4 Lh0h\7]TݴO@@|A{|ñ!'߸w_nguv}M;v챨i7 6-v񹑇̾^qo֬YȄn6!zlKG0O)g'zz y8k1}dYj8mah;tnԭ\/Y/DDlsSN8 E讀&ȡgs7>uV (\eࡓTdp1'{x?f~ڵ~'MP-z!ڻ՝T5ńnKXn$#YTKjs,[qlcJW yRk a1#i9Ja o{Hi0ߑp v*U˜J>y\rwJ1C1^ד_=t+yĽꋯr_~׽ژC͒^(_`Þn|^C;7-.>TJ[/!:0;ãOO܁C7}jZ=!V c:*wiW(5)+5t3(TN_p:z4kٞMfn}= 4}kIV(/ zP-QRSO3`A/V>]'XKb ?5#(-BP-r9MCC ?qѯ)f~ZxN|y\\fA+w9_~|ϧ/3KpV?sRF*~x-w*R#cnH$(8(*0Jj!өaGG瑶6W}VTi-z[ osz Rq[XH KQ(E XL%a%"e1@;?Nn͛]Rw:~uP|5I[o {:MS-i]V6tqE}@)~$M\znz/#wa>?<#2'- ?Aށ8CqkN(2hD41F+LZQu-;* (҃@6 jL5 ]N 3n[ݮ]cFe^xuv݁hzӨg򮐒Z鞏}c'7K1M+(f{aW)GݲA 0C p%S+ 3.KP'oPk«!S͸@2/&џ(]8傣R RBJh徴mnQ|I[ozM4,_Ȼ~zg~3wW;w3GCw;v700NHw{=!WZna.<x]}=tc Y{. mz dD}մ,&M3aŃIʤ2FDAyxhVzJ'֟ lc{ h/3^ Sv {GܓO<pnq gc:. (GıO[ qN"ǹW{d#I>=F^׺{p[O SnT3`l,jUo:/?ˋ3+/ O٠/ZLMzC<#@RX#F&1{|bD_ /%[T^5ΔJ ?>04"՘Gu>ٍ7L j;.r4'x ~Mfr}^[4ٶw>VPf0q{iei|Ws^{ݷ>L`/_or:T5Oj / ֓&Lʀoa=M:G_a28 Fr$sIK74zi~ `1p @wXJ}^wov+ Y:?t`jj2[2XV>{܊t[GKB9]\7կg|Y^P3|ٽ-{KjI涇EɷA0Zx[O1u }jMY-`j_="(iIe :z`,أ7`dcIKZi=(Շ=3xǝ~"ݻם=]}ծӍGqLƹV6F㥉Kga!ϚPƁ7/[yY/Ͷ0*(+!WrźuIl-\hA6p8hjꉯq4Q6@m"+Ŕ'< ܞVloi7tR_!|Lp\ʝjs(x?Z9?S,46IJ4Жr6D$::?cNj󵞫}ĴVZ_*T9l=o1P@o~xOV Tg)X#_?׋ ͻ~9Չez{U@Mjx@L^A98daZZUgyylO?Xx<ܪceh;6^M+Kc\X}=@[G'ڳU-¡ n[d(kg?l@n}L29LEUr]$*0Ǵ#WHw# Ͱn2t:c7J Vf6g¸x3[>sa&G{40=⌿A 7+lL{遴T1%L@_@7+kJqHKSy۝N9+@ Ԍ?J->|&LcaGj)L4Y7qPxr|ݔWl$eRX5^. a}#B|g:My#ʻ盞$fppC lg=W-<.@/8S9Z~+9|on-}̧b20 @`aՏ?50n |&ʔeꌑ̶ʬoߢ tX)7g^3Idp 4h3GkDZzJ7+=. !/ x'*MLeaOx(F9TLW|fԧ;3#`UVeJ j^Fkf3o<-9aϖxüس&3z<9FXAnYaQlfQGu\ jo@#:wܣkC͠f1PXԜwY16oj UxʎDw Ņ[ fu±4g}HZτqQtht~" @lq@ c;;$,9uݸ0It#po#t:Mʟ A6о NhY@16^\3 hOC3>>K>q[qq!lon4o/jy-m4<,/Lxj|`۞.U`*BS;ۓ}J.DNL{{{:D m[<Je F62*'\P:cPDr=PH 3?L趰9a_U0 Xh ~&&(>8(sZDٟ2ZR!j0Gc(K;ˎgln"EȉbF$--8NCb0ooA> ؐdPdQ[ɐ j8}MeUT[?unTx!-٦+ 3 R]7QjLLrb=[hCc ׌KW߼z3e<}mb}qby(G\j[2m)|քC Wܺ@e71TOqPi^v%~99W l@=ވVOw+#=_-s}~a%y+߼bV㙏l{2A,cVCv?y AYU?FE6s-{tYun7/D!h9 @Rץd:;B xpYLbŧ,y6ˡ{ٹ/6j]4/6KbZlg,$:/f er*S)ͨs*n6997iٜ@3`%Zpy+@ANηe D@q4=tR8~1/g5^=c[ GȖOm?M8lC]&E}V|a#q^઒n @ f@GM2}C1Lr;7/ u+ J2 j56w=t}{=ˋXg)Gxd/Lx"o%M({I9a'Q7|ۭ[K `N}g'ꯆ#`[Im*Fdz0H?f0kaڇS*4(qcJ^qqtok\T X,[L,UɍY0;oB/s/7W R{r¦ĵ܆Q:&(jZ"? Pk} `yi99}&hd xܗKq7S5o&^ꚸ\'lYBl]F9 s\Pڱ= V:N. &e FWHunp!Kk!tp|Йh3H?Z Ti¾nv. Z_x<㲠#3ȋe j%08d.Lz.0_̗5XXqW*i}nC @FOCUg,s(~$?+T:l<@+rDdj2ab X)<;x1/TX F2B#!kzGLx캉uZ}7UlC _/Es!t*y  ]:%=n28Shk~ۚ강Ջq`n4_p|_[\&fS7?}z㱗9yo:M#[)qYT?SZsi7 xFmȀEAkc$yi='n@W\rAd鮜&π_8L7n&/phٰ׊y= y0rgܰ\Ot`r{9μf@O~ p"pJ64/*h,.\Q&Jx;l8˞:g8 Bl0^ڸqbaL})Jivn;|te# e3;Yay}g^ k#`NYu}G?6Θ:v@дLO `€ap?Àg e=Pd҂+_opq~Mnjн7|p:V& 8l!ccabݮ-?7kS +.Zv24A3dkz*x|¥xN(õzm4\j\x{2GF ~+d#"+ov(Pv-z'rJR6'RmJ4`y>S:S EPnٴRA U ɩ gPZ@cӗ*1803oe[0-v/bq96m$_u_([?G>* $VwM)h1|.{J4Aה$O$Wur*P}0Ue[Y/"|NS*\,=Bo+~em28V雡Ůy=?cJ>(|'L=#dgq<7gtlUaKPg>={,iT 6mp7uhHi"юO:~,ͥ*a9Q#[wUX ccKa@0bA`Y>qɣ'[mr1s'[Ŭ{V-Ue;/uMF,gJޱf:oAњk#g1lFQX#̒Z̑3G 0 A`p03j ,k V:eZ&քx#;Ov>LulTuf{Ie G_O>ք<Y܅4 !Zgkř^*odui^/.sZ1ZG=i jxGz(@1ƄŌlYRXcK,qF$X3j-[ H Y=@Y?te YwmrX="05k7?f5J|@(BFn(#./ݎR8XؼbפO OVk~<7=E0u%szz~|m;cÈgVfƏ0/E&j+ݲյA `cZKU ]{ԈBwR$ɩXrb `3/6o-_㰯!Z8kxqi^/6ϔ.EKOc{GT-(2l9afݿݾrǕU;/[szܾx'5ge@{X^V{TbXssml.+<(9~cǟ.`2(ji2p^XSע_,+]x)e8kbM~OgO #8[7ƽ {g羚~xbaW=;쿤v17L+@l1%+]~8'2˷Źyyד#3pՋ~J@\9jtz:_W*u[L˓qMæxNi:8'M~PL~ˀOZ> êvͰkņզ1'V +*'daHh':V8D'.70N6Y¢DlS&WjŒ@8 f' p>nO*/t\#lծ obecǐ15|W,$ Sܫrˤnd @#1'YY/ Z#[:-<f+6%ЌAC={~<9AD@Gv~DX,ޅ{|/ӿ7{_I5La};Ұ Kx51u޵xqz.vIùFKK8/;ywY3osͪwn$cGnmb {ffBߨ]2ZJoߍ%V ֚Wcp!lXڵjߌ>4ۅ#KW$Mw}w}/q?J"\c+eyH__[,h_1旊iRå(iNo 83? ?Jw:2E ?3?sl&+ i }ﯯj_mZٟmP91 ̩ ;:ޞ? EJ5C14yOtN$/N_o_\1~[+\,<=g|? ~,?c<,{ǟ#9,sT/-v}9&U;>cr;V%މ+BTXY步 31HPd. ~i',`k(Y}}_=Wo[ItOX8<(<z*ܠiw ]_M8B04Vs~,o- %/?m{o;O;L,[n0qzP̨-s[r5Z6!0ʔMfIi5rt8 <]~ig[7 (>y]ɷV3H3\ w[k|;ƋpTx3ה*v]W*9lJ퉻Q>o~S6X5?)v߳?' @{z#䇷i3`f`` *wSFmi[!#zX_~pەK^ue5SfPhoDKSX:$jK~K€=VV*{\W?&wr ZLVҼ80a(7>l7Z5d_?Nۊn*]?J$x|?VgO՞PÛ7o?a%+IDATr[xaCP[Mhw{t0x!Osp޳fw6|דˆ@-@  E`J:>T#--OH,9{l(O% y^*YgJJŝfJ91% M |(vk}I'ɫ5YX6>)3`q cٿqw$ $+#jSӺtLQPv @@{ & Vf _nX~mv+M=bG-X!X55ɯ|+S#O "@O2P+48\jaR4S4G[_Qg/Ӣe8l^_- )axo%ٟOd͇t'fL6i$2Esz?vXcU)j+Y훱q^~*w @ G%jlR!RVu)vͧ]6=a># 1I`- vyYeu ~(#?X?)NtP1._Vۧ@S7}?~og4k߉ho&( ܾ|?vZ GP-d( #܀><< 7 qS[M^@{K~;wa{0~p1̉393^8y RŰ[!}ͷ^^.Ӯ?bf~+8 ݎ!Y:tPiqSGl5.6\ye?XN ~{DkƠfkg$:PP(a4 0<[?qLZ(݀3?N{cvWm%kJ#u$qi/ǻ?3?:_x-ծ 3Fԃ(k헫O4.7) 2m[ƇK6 |P҉#t⾉_]!;5hg_@K@/]R\\' ei[[@2 "םpV4RЇ??$O>oXQ.;ǔ07lEp{gI΃r&߀j`%WdӎP{G; ͧj䀟ߑٟ~nGV$PG$ |l_e3E g W\sis F݈GaLGG/&L< cMAi@"=4p}`q\$_o_M%om͘$O~p n ;?Ԁ'lЛv;f2q!9dIv>1FU3y0p]+juY/_.1@e$4` 26 0]cIcpc}.[.̺(+wyQX((`ɋ_Lz{;OS+@R\"0bR G7?y38韒)?ڟ$/:kj.oΊ#s@yN{ zCnR]lY|bсT)M*?9fRA<WW]|Icǂ?' JǙ\i!C'& I/>b@?e8(=cLֱ~;Ljh2q;) gkԁkCC5q)}o jKi;V!/]WV RHa\RBRP̺oǺMxl6+Y/}1y餱&l `b R+4.IL9M5 z\,4|iO܀@~6N&v1y:s'gP̯MluBhj<>a͆evrݯ܎+j" JeS]ӫN;,T?,Wjl۔@h G PSAk5yɳ}&MչJ0wa{ފn3tǢ_/~/Pax8(cj ~lrI5|if}EXFpԅk=4yS)C`\ƣoI+5TIBNN__]0ֱIP2(,{R͋sKlZUM^ p,ʁV?[1Lv81 jL pޠ?`w:ɻjwGhjX>>n7]RRGk[>T4b`(mG&@wk)X'!mRuHb 8<ء_ [UE(TP"`E@]y3?|ҹ=ua+0<\r Mz&N:@O@[{< x3IZl|Un|wSnagkꋛAA:WUd'ݮQt2(6)}䏍/l۔]~X,X(ս*92t$yɣ+>gX u脡tækpڜ\Bj ;y:l~ܑsɍrVHu>`"*n?3?J@ll;Ϯ?Upڏ| w7l+ܮRLWP׮]k`W=6xbgf B tȣvƠ"\+CmUm$Ox"y`􁤮A0= 'N9 擖PB<#8OP{MZL.,.k!1 xgQHѕc8ń<޾+?_}2>٭7wIiuV}{{{K_G|փBK3`ڭJ 4Lz<9*`y'%ѼМ<|cch 6Mc@3(z$nESMr0ء(|vZҾKɅ:60/֮?(-7Ϲ$޿ ۖJu*mW*u- T J@?JS{@I -YPY {7;+²2 Oi{p`rlXr|xrt⨎A~D+sf7 n |rzrjrmߵ_xb=L j櫊+g~o-{>_xrrrn+꼎ȮU]BZP6% Aܯ##|u7'ʞ*6n\ !hi16i>:NfzB 8<qSC5g^Odm({=WlC!p+X,1鵶!?oD<O_j*A!-bu؁} &>,,E,hmMX!+a:iiO'IqQ*[g˗sAWt=dZkfɦdu8?::8`$W@ph 7::O~qNK6wAթ+ F%I1Nu>{<"ozF~= Q'e96Nvj>JDii q{fW݃<7Á"X´{_d ,P̲4̮lBͧ0x "dƅr=`Jvw{; pxVt`;qH8ډ[6}WUL٥,%sE:Wj ',ykt@V@4ptDj`od7uzfFD xs0- jvC,axe޸D ]u J2? *ӓ^=ش(+]-p@rX&򉡣C>K xFaƴs{8iq6Z(:wzwjM$cڌ Q_ړ Y p^h" _ҋD\3y%M`*ٞG|RzjmjV'K#zy~jźܞU.Eߨ@A4<9rdiIQX9ȣ5,f}S+.ݳϟW|{of$c}䉝~?Gmw i@ ^xjmi4@-RaIvPO LK桰K*>O.? &t'nv)pϰ?.s[@Tr-g%|<&dۯAI6u gk`wurÒ>`3uk@p:ox3c/?OvKv&1?nT??^"bsPk- :5, $xbp$!`AQrgYa%':gKN!yoiIJQ"fs}fYlu+ ƒCaIHLsW{^qwgϬX39FX{K¬T~Rߕ&ںݕ FJ kE[hoCJ[ / qSS_/>oϲ C WQ~ح=N3zGc_~cApXwߵ @f%@$cBf)6)5A,4.?z`N3{k +Łڣg\>f>> W~0pIc?(+u\|l]~+F߶X겭Vɴ5EШlhW:O zP x/kY V,:a]Q9scmmX*>ьldV?Ɩ?%?ynJTim+="̀֍5hò@A? ٗi<03\*OE.^t5~~OewqƖ5~0Eg^Z?{jpy%(@t뗛[$ , ?Ы<=_m}k"E*O ep>s4+t<˿ %=ֻu]cR>+7&YԬ~){R +pxhttTa-@DT@ݢnܓ)~$, l$||-ъX\fQ3~|^y໪Tv~05E½e/>iވ@@\˲@M&EҀOwٖ£Cf~<lb|C+n01+f|fx'\MMutnR~u:?~TQQ\jY@ڠ2 d{v`eI}>偕XXLv8>Rϟ}xr|tY. 3ۇ]}=4𛛛+zfWQqaMiج=6)v]ϑ [?>/-o[>J<v2;CH[QX[%'e㻭sycCsz\EKyEP׌fffKF#h"2o?>:L9 o/X<@!`!*v8+wm8 |z60:r5ٚ)}3Wŧ:G5 g^Is_WQیoҠ==1`i|,jQ׏۵~A:GLSz9zf?/(=c%e׺oHrfxoW]L|4t^}ʋ9|'^˩IYbg4g^f~׼G[U:z4Rv&@ $Ɂx tsmI<(J%2B HvBN/'|S<.xC[G7?mi92aͲ~7<xR};3[|xY]})OI+wl)RQz'R!"ՑzaRXlv}lk;1_?X 9%ac5v @iV:? zL{ LyT_`O S)f{fFVVF-s2Ƃ`ul7=,\_aWQDWYR2 aPI,˅d/P = gfd2B8*pH{lvҊaS[ó9OF9lj@_;eNPkyUO3ZMn@0G|6(_Fgm/jQfB*#6* `=.rPU<`2УzeB2mRP)X>吏77eoӹعXؑ_:ηL-wZC0XS*=P(2ulJ(0J:VzL=PQeJ =IENDB`ic09PNG  IHDRxsRGB pHYs  @IDATx \Wu{AY#` VmppC !y^w|ᆌt)@l  lccdccYRKRUOUdɖoZ{Z{=s z=.j j j j j j4P쮟m@@@@@@lQQQQQ]htaǟ55555 PJ?9j j j j j  D D D D D tЅr@@@@@4bB D +=䨁h655555Ѕ@VzQQQQQm j j j j j 5 .@@@@@@j ]X'G D D D D DD D {(;nhx/QQKkJ)+ ,;:}$ bYQNxtJ>4e˖diX71;;HqJo FGG[nEddä͓Ek1QGX8 w}}8= +JZ-jFM,b.0JOD)22/dφaV8aVh,4 @͛7*ς.nڴ4>{|6]-y`W/\#7d4( Q 2m&v,>Pf~FĚ };}Yo:Hec(_#ZeWYg @*;`/`|Kzs-XA0>!܌Ɛ^?a~|Ry-xx=@'lo#ް6 ̃~E/X!ɋJf6͟<\uSuSeuec}_G}'Bp0_o~0W_+/L,=Rzo{#ܑKxU4`qdYt^5YHC(0 oL ,a4EGQGP8ʍE?>0psSi Jxf-` rpɐ1 =ܩs_[Tn6ֆj W]~c)Iw0wVdqgo#Koa#z1PqP^F*UV 81:[IJ.-ħ4 fk֬)oj`B8{ G6wܚӧO.RP9HD[|[vuA%dJ!)#'t>89S^]Oa)@\HގVTp5|`ne jX=T 쭺J<[=Çf`T@ka ;҄' v~Es1ʏ) Dx^xZ|C|N߇= L37r}wx}>p7O\]U}-ُ{>$ Fa K sc9R<ʫ8]Oa]קۖ¤4^~ط}C'3VQPH hRbU : F+fu ɰJ`FcCĨc^8櫰~rAfz|xހ TkǓVN(rxy'\-&K{v| mx "*Beu*7y.cud5U ׵U CRѸ2ЩbQhuUo(  T. Z ll,]g ڸXo~XҷA<|]%Bз>mϬ>7f3 ;^>Q>Q'BKe#9J#Ji9Gt}~LSf'v`giw}}o;k` Va@UV1ʀR8*%h 6 |<3oP d;}Y3'ϱ}3Pn ?NW ,<\y}9Y)⠒ONe@Ix8c##!W~_<8SqFHϞLcw~sp۪~4X!F 2f]hVbcdXv u%[E QP 4 -Us9gyy|C Y@o>`WNz3gϘ}FSm~]9܃< /Y02ZFx@^2Q%'9UvL轫om`~a((3o$ԝUv友=^k D1 RlߖaÞa/зp8gv{m @ =j7%βe}fO{yNwh/mrVxqk'_@ i+i.\ !.#!Ձ;m`۪/Q5c`i oͪlm*f\ 2c /@^Dch<*2/H<~v_߾) c|-3}{ gܯ}>eB;w/Y?A1FuwzOxݹ),€6i;y&يz!IP q@|^*si;Pxn]/nceow_ؾ+]0{sUj@Iq g>*/Ъ j[n]܍]CNwU 褁|з1d'F@ =F姇u3/_^m3P~y3  Qn\LE.Wg%MtGV?_{t2 9Nyu3k__U_9kPVy CslU)4ңA8jaR2<&3᛺70 |/*Pl}s? _2&˓7_~ꉺC=g -D@O{ 6j= 8Mse3bY @tu{gEͽdD>ìhfv{qq}-ෙxYgoN7pܹs4Im!W=+iG. @dbXP{U^Q,}o޸Sno&nsfc- HX3}Pӧ z^<h}]^O<<^CxCoj?m*ԇ76~#7|i?~dŠV0 ̅[ck lpN:0 ]1m@%p|>?kJg{>`58K5OnQ>]y5W42t .j }ֲ>ּ1E{oꏯ{%+i .QF@jEMx3 DG:)rX2*@߷A})cX~5jKgϝ~W4YSⳃ:y!@tQ9N~}_ Ъ +2ZSw _ sp0l`UՀh4@4jWV~eg~[a  ,O}{IWM^9%6\9 Pf?04hkp66CҀ mI/#@mX軯c<;x=9X>Ti(#hB;?-.Y7mbSl9pexc,_2iG"}-}QSLFrHnQQßw-vƌmp`0W!挀̎@A9_C4J 60Sp[}@ a_+Նv%ӛ_Z]]==W*#/4ķ yEaՀ ?yG4P7W(hhg|l͗ⴉª[[  @8,@Psh(EQ8*/q(}k6(i?~@ʇw~ 5p8 ^t%?}(|tQjjch{@ƀSy6Z!`O TtXr Jpʎl@4bCH5A(ai(".jhvۦ (FY03mC`ßZ5>РV yp` |8 =]@4bCH&$/oK}9op 5ȌߖYÐ@]}='Wzc[xE _jr6~OqS3Ѷ"1“cD̓3Š{tu%JOW@V~v;?mYl KYෲ8z>u{.9pGj':2h_fPo 兑85 CT*+Z C4 mßZkak Xtk@[Wlwwnjs7Zy>ca#}mpa֯?o {a_=yys*}fx)c:DIi1>Z1 Cif<4_u_3Z0>5 y3`z`ZB .G^r?6p෼,#<{N^>z{kߓRu2h~9.?j`Ejk;C#@8yc pcťgΜ9 f5ECkzXuМ]gSo ~+Hm}&^5qm-NZz}f9!=XP2{/yP̯Y_*j5@|e _ Oj^YX0;G[ܰaCm֭\ 4n 4RG`֬~~7}/~~=3-3~[ {k#}ҝ ׬_ÊD55XV9IWvPѯ~t'W}byP0Cy˶m!Rh wPKgv¿|lǟ ==K}熒Ǡ#` =a_XfE D ,\  a˾m! Ohi/hEtuOP j j5^Mc|=(/>3j ߱hk`Ci  -GjA1!Tu-YD2LOkrryCy/_;w  9UzvƯ⣋xl4@1!]x#i_]1>l XٸҺEoY?{6ﳙ?~^Ì??o꒩XH%Z2f԰~Y9 ZF_ p0[;گ 6mVl@MZ <)jG =bS+? Зxߌ[oXY'_;K\t~-c jk@ x-j7L5^WxAؙ%yR@%ST@Ǟ1Vg_oc֯h~~j~;M^6y>^dRuG55phy ".j"C:`C8GO;cTF'>;Sl߿N;qMol<-:<௥~?' QQV5y7oggw?￯6&%B->aU+́`_ά0{~7VT82GK155kF!85z_5 &d%{"yB 5iAa|qp=Zh5Ӽ/HԵxOKƳkM^c,:{OY"EAQF 9>Y}: uX7}{vEiK` [BP[n]^M _4֚~f)[ž&\ '1o 6?Ow~@_ȢXP_׊ fhtqؿG1|W |hÁx3|]ж+kqKk.8J́l?fv 2px[wf欙*QR @Rۊ8H Я~0{WOj9  b"Avli5 Wr>GO]wa||doe-@sɟgzWcS nr?GntQQ+K{m `I kK@iLT,m_uk{m\ ꐠ3`#@[dV` =\4 q]]#~ןj_xuy՞Lmzc>=ϯe]@׀:j l7QfGڿ[{+2-SD#ԣDhMV) ӷWKA?vaIs5?}Z !e% ??]%<Xa{B,hpԊa.k8[|’Y,?y]o_kOJJZOF&j j+5؀%! @Dn mؚÀ3 7Ƣ9–O-`>`ZZ\ 0=.w,~bK.[g q%fj93_WJE55Нb`h;΀}c{gG;xyPxRiK \QRZZ4LV<χ|lϲ aҗ0~״7,b4G55`\4ӬPSCw{˃,.<.(#=Н h1+@8(K$~ofa[vmG|T5:7]@@cu@Mn ia5+_p.xg@c=~?7c`ȬNi'a/rt^-ch g =QQ5 Z pA?u{4 sE3ھ4(N H\ƀ\]+qҟ~Afp/+>gf_i_P-(D D ,TZ nL/ άܪ6N\]:h2 6ԶnJ)KTᎎh:?oa?ߊKPfM~SL]hǓY?YQ w? i;@Fzey'(mJT<|8Š,$VgΜym -9>\!04xg/ ;́*I28)6GJrkL_˗I"#~ڝǗr ?UZ1 3<*J Zf)Ԗ:Q OOųm'm=)%I = hCZ -RMp6?9гG6r. |^ٶ@D#@Z{i4Ηd}]ަS 3xhtG4P \l YzeU2Ʀd܏_}Z qPP? R2qt]ޥg׬_K U~,ꂁzx¢P< ƒGY8Ou /Sd3A oVh2z`(')O# ScT\`i[C 0gK``hCl+kE qsF8 xVMRO{ƭ~ڰ8;iB}f/ZgƏ3ɧ(G866p0Ɉ+ e8qryY'\<SzO\ϽWl`b4zP C sf?j@g24&ît-@T?iӟnK3'ykTȜ zBZ薯h,_W-)m|ۙ5c;߹W8QZ(%5i_3#0thb 25L甍jMym`R!Y_XA_|3N)}SpCm'VMHVlIf +/}8Wd60N@a䊃va*^rZ%|3 Ad{m{8\ 1-m` b@_#]4M | 7dD7WhO{7Y\ku#/c@I_?_Ϟ~避?3GsAHKp_1`}]̯C}, 1ؐM!RzJrv= 8Cȼܮxx()t QiI.^Te(\2Q8y)< +iwTw$Y[5ZEi-E CJc;l ҧdh%`i&xϦ?9ԕk+v+hDڀ臆0hχ} yo3?G5SFbs>g, - (@IXjv@Y>*Чx^qȳq ӊ2P8<<8)*/y^@]ir<+^4EGaJ<`V51Q!@1!W3o8vnz?g9xXm۶m*!b\iVvt5 iPC 4{紿9*w|SˁPf}~(aI0;''gN=#='@`i")ˈydCr$WQBʼnOaeGy %SXDe(>S\u.QG~R+4+v?F&S}Q&,#x_Z~?A68X.[42:6 မ=_3{o=7`̟G޶z{| (Z׌E6U!1.x|y>p|?\NOs8<% K.lwG< l8@GYێ8*\@M~Jp& Jo3Ŵl~6|=l31Vo薭t7:شT="!}w5_J,ܲ}LS–&Rf Q j0emI/G 2`lh\OZQ/;yY_SZ5`)0ç燉4Ⳕ=Y9adQ>x+ q+J/N1@xQ#v5#Q(+ZFw@ޫ?7q2[{JX ջロE G]e5 F\f3L!:[nl_;~Sl  }p׏l K 3K{]-s~2VK C19drx/Y+y֓F2#S4N|^.mV˫LJPVxV@N>JK^rQʆ+>ݾھ]rFe"V4R(eh@h%ׅ"#|d߮&#ֶWۖePF U/94 6hГK_߶lg?`+5{s瓾 e00c#`!-uc01Z'̏R? i=t^̞g{r "'=a+xg)y+lw8 4YYlƋ*ucoGU.,T8xiSx<_cfx N[QcM>gw 05,c4%,1P3~x- M4lKg>#( 3n\L<4 =ryɈ,Z }cl hSd>ˆ%?OdaE* r[4&m @\qA=/x(Pܜ}ɶ6)*g}9x 5`JX~#>N$1g?ٱ?׭ֶX XxW;ađ6(_4ZBְ#pi- "">>u//>ڤrɠ≗a8#tP|rWɄGЏ{znXXDtm5і~N_oB0o{#hjXG#ED DYQkxcO֝6X[$7Y_& %53+3׏ݏAonCaCҳ3{LzJ {^C㸟 LO#SGul~)4yT2WY;O@X^^q+އzAL4!27]fq@>6<+׈blt4}\hzW)owIlY^v@0;LgppJAS]>dz PޯW‹~ihm|cS]q LKoI4@35׌90X81iR`= ġ3ȫxq pH()e#J\k'Ke>+u GiVa>^a}^2(`x~6+ %UnK~j!@?k̳=A~0%,фQm3J> DxD}ixi4zH'4x=Nj~ Pooox˟e+ ~|\TffΏg-pߪCg,׬D߅=&'O\pO-e> O+^MH2C/ǧU:I!t$k |sŷUoK_p  ` n -HZqpY>a+ wY|FYcm0&8_9~0 ACd0Z#`dd$|7 @ST4PH=WSڿEA~5W-ni!6e9w:9x3{6ޛ\P L5ԫa/:gzOxC(֜Z}#<.+oQtfχ=|T'Y3yQEɅ zOjFe@fad~xdJ#7QHV&?ө~&L!8<.avC`$ǸHS؟Y S֧d@; X]n]5~=0h/ JvЖC[4Nۀ1l*<3m@h䦣~?jc ё"ٛ$NY= =?m+Py<\ %wdL|;JM՛=*glЫ1Բubvm32M%]ucxQVf9 <餓[nM[w@;uπC-w}ՆjCVG'V}W7t\^ny~,Kke@r ؉|#OA8>,^r(yΎ7WA)l^2/],hUJѐH=kYEoɐI\ ]*n6loq M[n-[^\ٰPy)i>sd[m[rkօ kжF1bv2k8]yܟy9x3g0[[S6@iAá?~?a~N?#U#*G7%q;~fO'7SKJ ġxT<@/`G#a9Na+TE%#x(ȑq)yi|'v Cӿ&T$̆;ɔV7oJ~wkj$T/IJ#y2r RFO^_σdu2ZٚR`Mqy@ְA.6lB\{^dM˓CͩF#Y褍RW6j C͛%g3𸟵AC6O_ rY}[4']خuVXp'̒ҭ?O.fdPJOP4jE%f}(JK|>COy񒵣>7fssI`ʥz@F/zj~JmˉZhŴ^i)Sdr6i$#,/~IK:{ <P` kehzo~~gMuf?bá}[]ʽnᳵk毁Uv?:~de~YY<#g@*@ oi=-OݑG\6އ=q3k$W/Ojv\d/',/pȋ")<_OUVrkd4d+`yV71BGףi8[f5^G7Z .Ҝ̕{ _YhpBܠ)sOl)S: I]ׄ췷s^#gɟK{I%ɨgyx4rvg␩~ Nx9dr?X/? m6E1h ,r>.wK|}s; wO.]\[6yrɩ!s\T2-1 H)i2Cٕg'gJPBR &6 `4QTV&. -"cuߏ~jjmj<D`l: `9gɟIljK'ARA`WXԃdP f@(xőF$%^(29/rmyF ߢe:cTvֶ6lR%tKrf 7$WԮHJs?+@v#۞j~mR *$O=!ld: ϥ+𬖭1ϖ-F[e}/UW2f?GmYX]TΪP lW]cPǡ?go "~AƏN|Ⓓ^ODk~PUK. -dti2TJARoz:{/cA/CS#%( p!)M4YOIl/C5[I};)4)sȚuyyғnVBO߿$[HuP K~ɟ4y]u+kLF#-Թ U 2hW7G&Ik˯MTRBUVVOdsFl2b17\3{{71X hRnhWhJV~(K!Em/ym}мgd_ - ~PjIEt@Ӓ?~omKaK3`H{/'+^a(i SՒO(,1+0K&)Χ߉kvJ㵾]a-8͚ eqv.\6}dnVTw]d َdGG?Jn(ݐ7&cűE ծؕV2 y-&?[ڝ֤bNҷ018Q F-uל`m!M>xLĺJFÙl+hv*7Ӫ@ V{XZoml7׋&WC#7OBS1͎L~?wKeŗ%Jz[~oPZ_@ T;r/Q:(r9WNq|_N]O>5)m,ԧsPfyݹ,)//\{SU,W|ˤ&doH/\ '@h3= ymSJ-W9/9zBg=uPЖ  6G[k\nV#` {7;ۜvGl 0 ) FXZGBۻq[/]Ξ9R 7pD(9itdqn@g_!`Eg4 /L{`@݇={A3ikUJ%):⼼!io'W;wZU''%vvK[#HmT}Roԫ0äTsR|_W%OˑY&\j"^lcǒfm+̣UH}3V[+6xa }}|#xG\|O<8UO£)?`htntt0wg˳/sJ{{,S yJCXrxvrټv9ilROrٗ%ΧmTڵ/9^|RefrQF^>vܣ\V.ˤ=$*}(ykUBOw7mxdPЬU6ekOLn6 Ì'##0ۍJGͪ6'!19z6ӕVp0ΣvR@+~`ŮXSw_b_Ec;zk8?z&74 %2J31ս1,+KygTXF2䊃 |$I|l|8.;3'yޟF2"qg˳W_ /6 q) `Q>}l;0#KkX\_;ǿcʓ: Ib}:Qz뭀h`lRx#/P ҿ`E66T {3Y1N.3Kg,0/r¢~Aj #^ixɠr),JyxMp7$ P`A 8 yKNd^^~>Rq\LN-GM.2Ao/ܞ\U*pm+_ICJqTP߬frE}mCd+-?rV2\Nf}ccsiv̂+ک~ߨ`~Wlml1x4w4_$ ҭЕVu*,x0?[e?|Үo] s*oҀg[-j?KֱkՅG< ܳ@:?OAjTX#Tq¸FlHIk}9j;Ulz޷͟xsm oC6'7Il*/7C6ޝ0s}rd48% &])? c C@/gyTIl?fXqUǦ?0Q޻Oc^+ gEjSccceyV! ܡ38d';KʟuQlW/8_*u!Ewp4y:?-ߺښj[۳6֌_2ЕV@/ xS СxdC7d C?+a:M/?ޗ7#ۓmo 7Stz0̦]n_| wpl g.\#g&lr}@_/}~\ƀ*@2V&doo*``015`c YFL<|}rݿ;a2i~;gf׬YSi 0:uv++7Ʃs'ϝM;~^sщ,t$$Xա4+,y>g8v\HH,4P' Y xF`mF.8I=8 ?'d C+Sˉ;4Vy$sVLu^#{ZZ,фy[m) yj,Ā|} Ζo LUJlYXc#Ʊ"1]T0a(X^f7[۸2aC-O@ 9-1Vmh<<|ǀ:]!px+v_@Zv Xl2eKifR;%yehht^+ %xUFp^u.C7oH&ﭽ7<2odeO' /W%_}!pOb[njFPU]6ί\R$8`.<4 z=3!NjϣHS8ŋ楑̧_J.e'R%X~){/<+_YHF.8:#>rI0tuwPt]+ܿ+*W$>c;Lخq ҅au };={{0ʦ_[,/*+X1oX%Җ~0~hC;^UX: 1(m`-Mbe_/iS%K 秀/ +2jT!2yz0 +N 'd8ei#_qeÝҒPʫɣځ/7}dκsꃾ-GMVyq>+ }36xs=$'N gȆ~dJN{ {/ O|>A2ȴҝ:cl(X{^R[7U aU ї3V=֩Zg9\Kdb!6ea@ 3 ~.^N灿 5'-aqP5cXף~noG+kW&NmY={W<@S~y< AZyqhx}ZT¢y/ )ۧ?X{h7ި @Qe46/N=q_ܴ:wViM:@x EyΩ-kRq7n XɔBU2M`o 0_@[a+T,P5cod_ j-1J}CFǶi jt xɍ]NϞ?K?M}vt5ɩ^={'^2<^䊳;IOOiDɏˆdyiҵ-G5|,)^χ;Ӊ'Շ퓷yN2d#WVr}\/#ŏ$\)i oO%އspz6ᷲ@V ih,@6~Ń _Rit8`mƛTyԹ6J>U* B1^cgk*phSfΚ"Ԇ @!@8+c#^PϣUR5#M37Fc$]9]|#5ާ|U2)[}Eo0m]}S+Z)<'NL\6>}7z2[pM+;Y`@3WfyI[v>o4":JGҼN6–#딆r-Ӈ=Oz\^FL#.g+mҾt]GBP_ʫO/xEEY OMqzvO(_w1x2ݳrd޾dpCJ8Q.(*pEϮ:TtC'7LـXN]+&_8y؍c_XJsV ա!ǂN@uczVKddž; StDlRؾ}{?rzO}t©WAn_G?yNMo Ӳ?7Ar~?(@^3 z=a *(}^ty4/72Ҵ+)yWiD]5:{>yYvTw:OьQQ3 >al֋9^>,aYw׀kJ> ٖd! %P`Gɡ{Խ=ϩsNխ[眪ֻmk4>kl^ES^Ts\>/qՉ<*µ׆{ au~BQ"|w|o @}l!m&E.gKnZo=ca[_ 4_l.mM=+?ki _^[hÑ~/;6?8!5<@+N{YSs_/IC]1j{ma'jK(8kr<# ~b} ~=]N[:z召n/(Tʑ<0霌d<4(O3iZr(2|q*JPihSIWn[o [tu hȓavjUw޾&VM651ͶmL \ -\d?@7eg^qp>`&'-fwzO%y3?G-spȩeTCBG'EIKgG td8^4Һv.݌zٔ>y I\]D+[Ƿ;降JOVTdL僷v :o{sjWHw)p)OyH3]zZ~=o])?`@ BA;b@,0{ű}N_2Uk&f8䪳ٍ4x/38^P ZJqZ3/s}c++OtXؿqiM0(eXI0%#m'<)?!yriOJ /SFk^VNZROP*(ٙUu/SLŐNSTf:\^Vq_N# 8j3_'>h"\: N@J_80>6 1@ &,9 fJi Ň?y_ q=? 4Y`d\ sM->38bND,~}ZktSSWw8}/?3?NT<52 <@#=i9s9|.sV"PtHPL8fVd2ryhSnU\MUՁ iڤ"]+hJÃVNsiྜO|$71}<~8ߡ!Q9 lg ԧ2E,*V[ χ4mo· 0'w삏-aE >@XkտuvϜ>dSLD{.sȱ#mЭж?V>[? 'D|j[=E^#[;{Mct }. |OW:,ݬ<5Z5MrL>NC2  Wpav-dPTh G#v?yK6O9n {A< Áܾܢ7Z{x z_o]Jn,RX\e֖n9ck{F !!㇎J{O[4P|4UxUi2W|e#5/ z]E|*JK*UkH랖QƗ\΁wޱB99} )!w |lB<-pk;D=`vX]|FO,|@0gI9:ao/e ME;_c'}Nnn,H+%]`&>pXz‰='F#q(e$=p9 J+N:>݇)/MKyei/L6929dsAeO,宑=d?GS9մSe|z*/'rtxSMW~5; @Js:O+O;2ٔN5JR(zjQa 1-d@*Z*CZzdst xK- t0ΞhyMfv-q+j > Px/YE@7 @ϳ8٢}S1kMT;#J??gW|]e )bTBc2AOf+_!ӴkV+=UZY~OV(v WʛDڿk5qѫhO{2| #/\p4աS?w +:*M1[tDGa#Nug}/L?}wᾗ]xoWLZck\ f4y ca\I6WzyF %maE/*?F W$!!-m'Sp`C!%M%lV&}r|d{X_e=<=tS&w*yexݰG1_|9|&isB@t]z~':C>@TT{YxG8rv$.\99wV}?& Lɬ ^Ik_I:vFQnSWZC:}9XFFBu2z2ۡzzZ6<48LWQsה;oCZU4$tyY҄V蒕z\r@B+E_RGℝ{ޢs}9u7Zn2 pl$;E,0320QI9]2M֟]S\'.=G¤U#r]ԧ _Ky‰528uϡ({ytsq؏;~]44!`4|pB?J4k=o\dS]Z.œL*]v-oi 8>Hpi9Ee2i\:Mu*Z.o~-&Yo ~2<-h5`0yE}3ϱ3gcb71]w6ˊ'b?-M8H?շ6o0LKѽ(2orСͤk)[奲s2ӥ]4ooLM5d f!wM[:u[})iOY}Ttiԯf7{Xe/9`QiuUW F/?ソqW {/QW|I}5߳eocaN}0fLz4Za4o.ܳbŊ^>~֑g/EG `50iݜChQD&LlbYxK㸉ީ>P4J'/oG\QaP ')[S%tZߔti>Zn!e&չeJ߸0~3SLiHbZse/H= hU<oFb.}~Qï2,_Vk&}]Qb&S\=;_F R,7檟פËZу + 4g lp9^HWfyM]ϳ9y/N+) OH-)>ΟՆBUe/ySUp=iUNj2Uvtk ]ۿ&l;,ʔҩO{\S9Z}9|9~;4_|(Z L ~|I]GM&'F}ONbͷcjih N|͖.@&6!K~*o?3tkg&'U:U'z~{tz=sݤw40SOShrrSVAd=ҳ%ே~.-lP<_,KWk|&O߿|BӃ!vSOs GxO0sAw֑q`w^:`6-6 L*^&o*UM>)yzZF3|rƝkڠ\͞3Mtq==]uRB),;{ ۑɮqL|ES(R-ԫ+D&i"P|e{x?o7~͘NpX'f8=?[XHܽ/&*pL\iZCo^>zyX޷<:rRlATYih"x)x|66A{v\2ZySys2eR~ r t22^ ;2UUi4tR\:'如u h5|3d%y*p{q|>F]?e(;(`>̠?=^d@Oe@^lt|ݘR)LZT,Ƕ3$^Nq'{N߳9PKNnZOQ/PLP(MK/(> hWt#RwWy@.^?++?U:L2R^ ^.ָFzo{ThLU:Sp7|9~ S?UV+yl qo߷?o+{Pi ]V,ףl^>_(߃M7,̟ˀrjŹV\[e=+*GSs}>3 FL-Ç'eD1}Z4 @\Qx8iCpUntFs2eR>2erVP=<Ե{ڞ4PAsy}9Uϛ'͗WZ]GS(y`S˔<7&f@.!":08Z}QzEK*!-@<;蹖ˀCw6o@si@Uf0<12#?soM?ߡ0|IQ?rfa->EMY[8}b%<{Ge%rQW:f[8 v8kKeN92eމ;=Y=HV>/x*C<ePr2LJWG-]Im)6  Nnh|/=A *|E@ӇAo/p&j)/YUtg}`;/:AD͹tY?>ڤ9 mǗ/g9f=_ `vp򟜿\(LJ Jv,zo(4JZP|"Uo/ sOUk>ɕKe>dR2)tNVeShv2U7hB /+L>C𕁯DEDEPEPt/v%D|B}}sMlsˀu7&VSw&ŷTАM9 ]@W.MЮTQx`ucºuѹKрµWZ+edL xQdSZJoo6=]2~oliG΋@=5kdm%,ԥ#'+p%^4 iVݢ׌W >|eO{<嵚N ߏK陛 ,0#+dZyVqQE.OUg]: Jg3#\o/d_iDvM<^eãiaI@&w۬O9ˀ@[ Yōn޼9X'3Apv_dѳU3tAv ̒M?::qjJg^P\ɂ?rX nF|႔ގ7hd{D& Öƶin犕r]C~a˵; Nn_f>mَ8 >]v1@6Ng횛7On['ķ8;v^sS:-Y v 0`"%#C|rAI +xiQiy\|=pԧ)/nP>#]4 Us Xַ-.!-!=P(c6 [$+'Pxچv&\gٗmxw<p=mwgKfAuЁ?HgRS=_FwsT(9D^%e#-ÇqpS:i(vS:9/~8C^7ST*:|9~k*OjڗQZ^\Uu^;c[mlҒ-æŀc#{ǣHR?&61 }\. 0+34*6,eKr4x=kE5'ed q49x.-^rMy\rf| "ܵvi҈am*iU_\A t9畕i&<3 U6}xvF)NZvLie @u;"&W3ZƗ6| $czR/G5o_3cFT? E?m aF:8.L^`@O? 9y\xǛL\ܔ=ͧP7| ҔNǑ'|UxMz^(Ur Bd[ i4j9^n ea#珞&OkpѶE/$n} d_QwcF~.f ˡ@9h8;?~HZjhW>3` n-,L %S (:pWFkW>/V3Wy^G(q2b+ Tt˨--,2e%.TyeRr3o}#gcE tdQ zDQN_+xZoGu<=/ݳI7⢊J:'U>/pAS㩜/ͯϓ)oƗey>o ~[m恛ADvH6HPCb۰q$Yr"cn[,1P `G ס@3>.\kF[H`[dLImqt 5Zڥf%8~b}\<|qT,L‘:iQ<~6 4L,O;| RNeep$}h?dƵĦT>/8  Oa3^Yi9ei/׌/2+=A;"L]6GF4odg!$;~1b,/|\](ȡ@0eQt\kcp3}x?=Vehd E/`Y +JEZP8iTTY1McF/\rwD}ZGC{'z;v9Y}^ɖry)EKhE6鴯p]#M.(~pMth8l]cl" 3 }\aco t;pook` =.hP>jkHv{d5=KG6FAIq>RѵDh^Ʉ̭ 44tryied=,-ue{`db$ܸƚMeIiei/q '<*\}>S~A#%*̕ь6eׯEO9eR\v j~7FڄwJ[q{ۻ]z0>7O2I ޽(sq=˗/]hQw췇CM4Z3i3]m3P,_֎$iDR':0 )J *iZ;.]0s=K}$]gtOP{1*2 ^S9DH]0G.OX65+Reyy[zo }`>46duؼxX a:y9Zů_p|^|$rͱ&h;pF6}ѵ/T4vemXoYg#2I41MtQj?M},x%/ trJɕUG1Ҳ<]yZG`k=p =ZE#i)˥d}yK).z`:H }mB]LW z"KW #cFY3rb744 ?g233= s\6XiX_; ]ƍg/Z][Aqwff̽Zb7oWXOt5pОStw푁MVW}paD#)MVZ<dzv<?/'  <.f*[zkR>G9@Vply3%S%ZU:rx)IɦS i9sj7E'?`kdMsHxM`}.e@=" Dg91wlߺ?>Eq<`~HUk/V[֠^>up`݁JVk뚄n'>#& nU?[k#g#V"<\ذaCwH=B wyg_u_/c}? g6\&-/MG{oFmuSŤ/u+rSZZsr *o+3SExkIò<^Fd# {~6e 2FbwkL}ұ!;}G{] \͐v ^_=g`!DÉ#GNS1P[L3ہpie2p7\<-(]eOC4kUrGuT8sªUip=-[V*,Y$<5\˗YU0W#z uJi)FHiJx9SlinV7+KVxʟB[_BiUS@Nip&O=A\K^-cNZbvkFO>Ћ.r,} :3ٶ}P==cKNҰ0Mn6ӆO 吒34PϔN12*Z2*g?'.°p뭷|0p a5=<  >3| _]*]w FMحF|C=CKp]S }DLo}v  s\Zgj@y3k1n{9e .Q@b՟A|-@'vin ֈ% BAڦ& pkâEab,eQV%S:4MP< xI_8㌰vڸ#pqDZߟN<Ҟ{{ןrg` VCnJVᾬ'4)Ҵ0jڗY7+,4oNS2I h]6 ;BȻ:ۇ5Dۀ.@}4ҩ{7F Z!C8pҁӬq@vL8 `Vt >SY:*MTw h&1|F9ɗ) '>EI&DHm],O+SKh8/9ڠcmO{:-_ȮGʅ+QGE=md@.&*OR̳A8v#r} 0?̏D03 \OGW:j&j7[er>k0z{B ('4P82eAr9~)o7Zfp wX̓=^q+;oP^/ׅx^՟;tDuڤÕ2 J{œ,*Ɋ&M^ě-^?.TeZ)''SBۆzN pg<6!l{1!dĝ'&kT 4+!U[){Ӗo]#e g_I_d.@}1RS V<߶m[ʕ+{AGxg 5n*M&Um'5I@9R")mWc넼 mҥ@ظqc;⧂ל3~滟 #IQ| `y5?7퟉ @<Ȍ.G2[4Xi`mc M1tX7/na1qZD5|dҴ*YW/ ,A*Z2R9pj /r`u;k od~*<w~#_C_^~ܑbVshivU*e?> ]?-?B:l.r)|;4/$lC]?2UVKe;`D>y5Fx;v lڻ)\~a8A`폄;w}˭[.KQ| l+@dG>ldJnePv+>yxo5f/wl`ƹ$[ hجr-ǑcGohP(] A; `FlSk> Oe<\s[VN2n;Gy$aqx _ g5]ׄW3k~;@1BF'Fz!XҞqMrM\GANAͮN*O4Aiȳ|e -ah%W۩}{~KC mX'xb-Zċ?>r$k 2F޾61KZi_=ݻN|2 wؤ`^@ g@3a 8bt]TԭPDɆ3؏ z7 a)H{Iޑ T1}rc]2-ŋGvOioKlY8Ie]Cc\Hh8v9{E^vc/vz@@ΰL|h?pll8υ2zNv.<5?fxMX`v(@i=(lZ|q2)㋖BOiihvTt]4?<`QN\Vس1K {V8waEq['jٲKs}V)V>dL.>dpI_ 2`=cO$=U4xKeHc+ob ;u# DfģV-{oc$-DZ@MI@\1ҧ4|BjvDFH[ X=0?~K (P4bIQ rU#׆~afEE}{=/opx٥/k)_7 ee5s9Oy/Uɋ70wʮ-#:ArO ZYlV Y=;lػ!$Eq>nۣ-~Q`t㉛x_&~z{2=M6)uNN-Pܹ)Ÿ&jn'?a3KX?nH|tn`WuՑ U8Vlᡇ_ kHthHKȥt gsy?d@?Rxmȫ&|(HVi2:*^U~$/جSa'9+;/6aNXzBx7OoMѽzU֝Z.Gn_&cM锟z/Kx|MSTTdr7A{=7 /:=1vF8Nar|׷g˟V?%yMJ]QvCA:'@IDATdĠn?MKtgP4=zt>ٺ/؎K"-$BG&g_^`b ; 'vk`&O<~2HҴJ| ZP%SkV.UJ=%ðgpSO=W"owux|ַ[n' 3Apc7NL釛y\%+ˈeEy:Tn3W&eqW°CϲtО3xNп! w\V}Da{D}?;d3A96Q|f %bJtaxEE cǎ~ ]k[Yd#;9ͱapqZ<j_hR xԖ Th*<)x/➵^ܐ {Gb{ii9 O23nEz͜l3VX'Ogްf՚p}g/с\x聬U t.y|5;iѠH/l*Nz,U~t>dXyF9E@ם>ݩhBCEk,=t`]7 lc?A~-EGFܧEOte'^LrmS8AP>|/;K=?|mkqqe #)X+59TL3|Ȣ9)ޥa3 +G}pV=q/{6+|Vl\󩓇iii8&J_}}}ٿfJ%i*! i r;GR.c!:2 sZ_%I^UYC;cAH ^ +ze<+ۏ|" [%\~ oyXq\A$>^hF^^L'CZ~]+Qˊ&ʃq?= z¢٫-&7+Gh_b\3%@&4 z?zPbB 7[uLކ5#k2 (!OP:Ã,TɈ'+'*NR]1@^$rOyq\Mbڬd _/ʷn^f1B.!2!<RLu]ˮe#KbgOďAF3SW6-NOиFGp}Ҍq%`Sre<{УnIz:Jn rLbi #FV=:SQ:%'g6z ^~ұ6seSO 2ku}A]< + _Ӽ\{tLO`U.-Q~MQ4n~on; 'w|$◶_,kk:(CU*Rh)MyU)x)2½ a#>[֭Z.Y}I8m4{Z[˹b3XE3Nqq97ү2T#R[E\4}Z8eGxc&4t7NW/g/`O?@] Bk72uhwJj`2Djs#r|e j9Cс͢BJQF0]U<իJf<=]M ڳgO 8s\?6yXJ׼{•~eW+=zܩ1?WҰJ{^h⥐(T$B]a*/=TiCV\.9ps``sh7q8~?Dv*oe<6!J i4FPf] .҃z% i|!Ne߼s_tl@Wf4jOLNh8\uA[TTަc6R{lQ<рet/3] 5U^N0pVN gN 8iIY;gz}xϾ;/fX`q'1岘M:i(%-áC*$K|s27o?h!N#ש`*dْp+/ z4ˁ7zG]oo Hp\Yq"q&rHVNy#HoFⱕuǯs|Pj/:5M1Gsc } lJ8hSͭQl-_xv W=$hY|eA<\Oӕ_g . !uָpÛ6)fR]2/q|uY7=p+kQF&Hy u ,Ň,>bVC†7}~X>`SJrp?r p'(V$' ѥ1|_ﭿ%G/`-: 's[YdwbLl=^X0Q{Cp;+pT엱2܂9\*d>H:e'y«xTNCՆ L}xV"osMҏ>h?xMovS-᧱UOeEKT+^/-?M+GmX7`ݬ>1<{O>W*qLd7|9e#bPjp\m/aLӹl(m!MuY%#- l<}&aC < '"x=#FQQѺ) b:oGy;58@*ʱ7zl5^mQh ^3CнB@N@faȨzWr3I;㊳Xy~@ AϜ3orKGgnBn)u"pkBK \R*"NA|V<Ⴕ\{1z/ |>&|‡Lя`d: omGS9m xͨkW/§ٚ[L#_y;or4N@5X[y^Q<ð{GV4~c"ᓝ0vδN@ l.lPO #y=LznijLBbq]w%g\yڕ~p {vw}]_}6^<͋eRjN.y^y\SAbQ8}bdS 5g{~X^}r!ԁ+g\iI!͏>(Ͷ TkKg zhǕ/MZsO<.\ҏ<[=Ʃ bt,iM솩) pWXcf_pYM DB}P]$tPeWF4#}gdzڟ -'//uBw?|wx{^^WcO@"@,Xiz.y^\祲SMoßm}++N =tH`s1 [/NrRZ,MwوrmJS@oc5u[||qSI$Kr@ؼysx衇$@+hi s'IG&n'AOvh+Ғ:O׭*֬ شiS;b 8w͹񬀿o1>\ҷk{{{aPTN]lwvXC+Wy6APtx^U|/ x;z8^tpQz3}vVc-hik I41~U5c}S~#*`7YiH'H]UFWB z嗏֎:CB+HViA/SEo*0wNkVڹLȲjq ömYkZ޼w|:lݷ߲uK/gh }k观tz3< z)t\KgGgI}6u䵪SHi>MەaK]Eոn ߷8KNo,Nԉ @l98 ̍@m!jP^[xdi^: ~D* zU25۩lr8+#~}<lMo g#;|ozQxUo ?Mo}~?kC6[/īw;޾}^WҕdIŒ ^apL`"Cf2,c q<&0HB 6O'?1^eiKWWW%_Oﮮs}}Z_޻U>U{ש; nQt+!W-:LC9'>+M9%~]b^!Sw1iK< Ǘb ?b+􊆱P2>r``x-Omj|/1Y~rǾr+O&ANbP ^ᫎÛȷ%~^vt̵ 7ܰ[<C` ?vǏ>FZxm>[OO07cgN=A)Xd7\|&`qeO?dye6-|ٶ *.YO]}mCY=^!6dd[Us}GFI8}h),`,Ŗf( 7o5g҈BHS+ VzM 1en(" )@%HqрLsHr햚tkDƷVk&^ =?'|swO7yk5lkhPýdAG'Wx[ߎX1ݲ/9fkY2 <*}>jE|eʫ.U:M5} 瓀Om~ηy0.PVln~ڣYIu[/_qE#@SlNzhSV|_lMW7WQhup^,j NO& x&yqjvҫi;\ p _ +;=0;?KޏG'χ__|m>Q?9]89:ge>K_m};zo w\yGxWl aܱO5{/৞UzmQ?nϷ+ HCGfoآƖ^xpCt8czq=KA&Xxv"O޹Y,VzNڢ[s>=ÀҲ5 ^gB]|:\udz^&2oIa^LawĜ3 ;  ӳ ttm} e^q+}}[<{n88h"":u%m,y`U=&f͗*y+0B'B]3;l/@W[v 6qS7.e3'V>sZ5Х gx.-6ȶm5ݭoyϛE;Vp%7o|3Sg=Dz?.m[oֲn!c=š-}r$L}UaⷑR[-~?mm[8vnCö3\6^., Mc:<3~7'r}XvrˬPls3;7ؗQX(DdǠ 0a  <婮肩+{9v/+<A<W:~c3{w ?ڟ x\g\x??pKB|jN2ISE.[\ݓ[g| <҉5]$"۶96uU22G"56R_ S 01 (`4#VV)6f;V,g7'!|8~+-|Oʹc:] K|k,%7Š7g_A=aĘͶ˱{vܔk``r}RacҁV-8#W9`P34!7+kv2g 0I{ IԬkB,0O-7:p{s' =ׇ[e?#F0N7xc|=ma[;ß=g_1u>~w5{:Ҳ~O'Y^i϶=19&><ϫEcG ݜ;M)=}b8_zWC;FL] nQe/C@Z=Aq]cP'oa<,GթzIj{q:&) o~7vP46h~=>G|o7x*\}YP5c_V®]u/֢xPu 6m\|}>s?}?r=a/nJӏ~:?߮/LnW'8@x-wLG%xzДR<.W $:{xuRZ9؝%e3l7тxɳNFVPlM E('04q)]j.(:ЩC=hgh(˖@'[<=o'cs##lL/YW<4z(wV'Dᾔ%[/Awo|`oصk{h_Ho/}:Sb]쓟 z•;6_l2 '?EբĔ-bIW.wuײ]jfIQ@B4Ž8Ah2xq/;OR?YU>oC_u{SRn:"fIG}4&Djk6Gt Xk<9vmkw_{=ćP[,X\`V:(uc/??#IW'AH0UXɧ2ӏaN_:ʮknc#F8bކZ7 { HBIQ%Wo꽯_t I?p;{$Cl)~ ,ڜcg92>_P&>ooG{ߵHة/Z<\oh Xʘ mct&1s{LV-Camĸ0l z\P ޳MPUopeKg}6~0h'IƱoBH+/e>dhE(oOxq|HZ.Nx!qVJjG;k^dxү;~U?>} ڼK.>[۶m }$s@$"J9)sG6oZGG,W3Qk$(dkHHm`$?^b<`:K-kbhjKk/|eȫBjVstP~yv ؾԻ-R[|G[~g?[E\0\}>~Ƨ}|_fs -.3^<]E΀4m].u_DrRm2.Z.V{c,kPW:}ҤE'kE(,-(Ҋ6@ no<)+Ԓ1NY65w"xWעvo2ETT.E[k%nV v0 8|~gm;WپgIdGgqC})ns}%mR>j5Wr6|hpJ=fX3عZt[(K2FVil?ZԩJ^W~띅 Dʂa^}k{/5/\Ckdcʿ_1"F[~m#7Jy |A^Bg|}|@\xߐ_Ar9b<~,w&r~i-]iz;|(v S5\!B kM׽uKLD%lI(k :CQfX8Dѿ[g:pca \AW\?c=\QZ= (F|B—WOA&)FG-7o*}ѳ ^xp51srwڮj VM,k[Zc\M ~`#A0g$:eMd¾ׅ7\Fi Z艣=۟03U\? GOn}]tY[.(- >go_EO|Jcm>*@U.b&%`.bWl_vN+WOC ʾ~mӶ7G_<{l| Μ'Rb윷L]Qoؗ>p+W~-~g5mM|S87k_IW޿/~Qspy>xaO!3̼vMCF߭Eo~`rr$X8yhzGM ??YN>& Whi{quֈV7__Y>_>` n'扰i|SذyC<>ˮ,p xsQ7D'x՟~O㛔MSrWUR0V:`kn8?E5Sk ctX!Ƞ!6:`er.>nօ=}W  {tU[[o_oU?+㕗J?ee2 x*҆bD8anolpvb6??r㇋Tw- >P.|^cE$|SUzɧ# oHsO?-u 0oG2mZ]1:әX3wQ5OR];k 7۔tp$/y{w {gy뀟9؞{‡pZT풙 Md$;_zK; o{ck|{m6qreZ~sX߿bqlX|X-qCз6υ0e2¹s ~!_&0J@9DF|v1|П>IS $>WN0]E@@}+⊭lM[<P:sY+9Djɵ}يܯ j)%`7@~Lͷ9hyL蛥[n}Kx[. +K{]Z{DY' %u|kEæMOQ_8q!ώY͇=^8N\`%Odڰ]ȹM쥞Ň­~BY +uo}s𮏽+|O-)U{Ao~>6:4ႩOmr(|[ tX1YI{6KO-`}lĴcz s%3 Tut)WhW#@99OK}u>6QΆ?~ G>n▰iӜ2AmGY?4~|}ׂE[/>{\37^緝G SSSAcsЙCaf>_ χzbBc|6:A&y+o"e/~I|0R;Xd8W:~;䎫|_N}m/ ?;{Q~6̘my"8Zd(K%- d5ے>@; V d vq)r:zU_#f%k[ʷ^9L<ϓǿ>#a.]ش#Bwo.zqtON;,A~N/MbbV{ ]]oMrhrVuv<>U ^8#- ȇ^xWۮ-uL\&YA)+{UX.Uiؠڽclđk/{6ċ/8oJ+h10?69[ĝOp2ѡЃU,m&mf/mVm ao/no n4L O24Cc,\sM8vX?&'';/_e o o`AsS4@%գqoU-Hٶ휛<#vĉg Ν  ُ|}Y:֭[#':u*={6?>B=3/I@^6vY巆ч½ NP}g>~~0–? W/Jy^v/UmK_α=}0ooM@ ΏyJ:Sئly٩,:m믿OĎZɹchRr )hEZ$]8p[ b6ϻR N@.̼% * l[WV6Y&ْc@&+9iq+A2A\yey ?|l̳,@e9x͕gXFZ-f'^j7ܦӛn8Rs\۰Ը&VFӧ+ixפ d`/uK{Mdv߿yo~3HVb;L*hv>uU{Gn]:. X@Ak! ]}7~oxq1?Ƈ~תV^6S":ud˯q\ WYuuI1l F͟l~w&hG㮅fh+ 9耊rtWύcVT #c1 Z^Jh:s7!KmYi{vO=T\ww ?\< iЫN` v.v=͵cu{_3 {oL&? Pӡ*zH/vl#Վv{KMǥ* jiu\ʻE}GP(ܦcђ">X+-wPvN/\0ςd2=}hÅdOܯ~ʖc*^@=9~2\3{M9)02b^^&2G[jK4iEVu:t(VvME@42LCsPŘj/\ (.8ꢎ^g6Rq'Is'[ak QT_4T+C꘍%lؤ&2tI{Mdz9J^{1_yռ߶o.G7W]uU<'N_/ |h1]m1 }8>DX՟__ W_vuغcnL64󏄙E|ɯ}ߏ?{ϟu* ̙nL64Cv4:P(5- x@`귱Sv0 7k ' C&_'vt>#ryPtWˁMk">m 0yH-vo߾hWW'v,xGSOO~Sƫn o|׶C;l-5ֆӞrJ?SH'տDhX:F.~Z9^+u[Fk5(;d'1~ ]G&{%*:ڰA+M_WN? ɚR;K)z(cD[Y " 3gd@IDAT<+p饗ƅvX$0+kd}w{ӏSpեW+x4X42Nܗ=6U/-L>,e 7vzE%^z. ׼fOcVAbkc3ԜtlӋ1A2C|A8xΏ3rTBlm#p*D_9 0xHm=+pug p+Ǒm{M~pE}RAϪTSaQ߁½^ jd b22 PzwvƏ+-`GbVwKn; :sL:n> -/XQ)A:+Uآzv 8DHih [ kEF}^Ǔ dg] G}4~ ~{qvlnUO0'WǓjʤVW߀ >| 2*Nj]~`+m?sڥ&W_qJ1} foNٹy#'Ku,ʜ+pA|ES`x^|p7؃Ӕj{9fc#ϩLDB -+:jßd3H8qas(fǼ-w]vOee-#U{\mvㅍ'  Z4:T t3_,tܚ@}r8yxm&Sզx$_'/Omڳ{ .,.`!_3daa*S{M7Q{mB h>!x>yTb%ۢdnhf7cDq?J} p+hc`} SNȖ⶿=0,43;fV韀oHtũ0`8d+Y*2yM,y A=^'#'זL1x:} Ϯx @!ĘJ^]&2/:$h@h'uX.|?.?À|KB4_HFZKm-bPǀl|N)W&@|iMف6X?.( @M"@%IUaKZ̠bӁe78t\\ qAWw45o-tjΨEgr[(5~&ްp ÈatS9 'ѻ<\Q;S<@g-`Ŏى'ن} %cO**ykȎ#aT$41$'Ku<]T]wMɴɫk#+aԗA-:X7WMm^N-Uw*L|nx\Qx'摊XAlr,~`0K$Cq~3#@foi>dQ= :} {o1^"oC ? ϲWBD (8g~R' |rN?2u̵?^8#bA )ExL<֫W_Fpd@n,h xkm~]ewTTF(|7ؙIasF'ThMC|[,XXJ,1Cee `aERŸYܗiDI0=Ӻ^mڪۈ>JX 76s4e<]=ڤLy- "#(0Y٤9,񠪟>?lh`ZP'fm b * ";n&Od'8 In?._:s9p_lYtJ XES J^yVN# 1XGxs4&SU j:9Q)꥾2s#>{$I6X\eIyAL; s^wa20 @rnn6IDELOF~c/MˡmӱsTwI /?}h?U oH.8?t fxp}{}V zE"z!9U Ԋj؈ ¶+y?!4LE͹I'9*S[u:^6yY`Ԙݦ7'.:h,R(|m8}dl09:*Xh1H-@lݚ5Z[N7l7L ;QA85;5լLE/1~2h@#yS.Y<JVC>wLOx#X-zmM< /,C*F;}nEp"d{||._'(#ێ|c;p긴5t:uq6Nn~`| V! 6$M& $*'W9!WrMsr^c?<6ru{kS>m =sI䣄{ 8>1w:0K?`6ccgY.>lNܵmuPt.˪ˆ;.@|F7?SthںVHMYsr:M@!03 &"8D uӔI&kx6Fpd&6u /'\P2ijiuiO(p_N/#G_O}Ѕzky~)q]v[;z;A%}P*%Yػ$_.JJ U E΍ w.(N,&y\xqGM-PzI}]䩯 tT7 /%}@|apa%q=ȭmŵ"fq.?SNL QH? |ر! vG9^NVLCX(NAmV4y7Db>M..^8PzU)kJSMےNi[X|jP6U}aԅT| 0ތeo#?Q,Kt81-9?ĮE2U;>MGT@ΘeeREփ[_p FjPk0K)W~u'@$ B5fćh7GNu9s}腟U#8c R'w^iWΧxD}eѽ?2? 91r: Od" ?Ttapr24W:Zl?YS:O8_M!G  n+?pvEA< ZOhX ^FbO2h7Gnu|Ut@8j۪kVGh9\FW Ѕ#>qc|K'PArp.L## sP;?^`?pOPR?O+WzZ1vX1m/~-Mg7|<2z{@0(4H >zɣ$XeA&HHQ,ʂQrINe=FϵTW}:oYsಘѺi* z|E4OR=h!K>\nԝᇺqt%5ew %9:,ǫ `lj7թ800E'D4=Dn\ֹ `iDir!q?aᩜ ^U`WpjT94?_T'|t3mSf;v!_eށ.t 4a680 *Ð15X p0d C?}ྮ%׍ _Y_WuUc\W. 5M6r:2CIˢ&oE?~⎸"O6[fiq@lbGI@Zq%QLɭGmƀN\KĩE/E/;/\?&Snri1D')@'i\7Z?| ׵y_#|Zs[ei28o6t?| ewvm>PVܩ2ed n&{۷oM<,c|xjǾ |.3hP0dcsM] :Y * w[@v!3 $$7D7Vhc+{'vVL@Ϛ` 2 I@#i$2<.Ozj)/W6JcA]) Yꘒ_U6uQ 0|Q3/W\+@r5Z ݒܨcx];8<`~{E6ȴ* Ȗ[mS''(KjZ +.0pqb%I ΄4Sh@NԌӶiyˮ4^wWW#2\ԝ_=rw;f?|HoMyD&ua噫d4_. _N,IM}o>b,t6, oeŴ"0l@P F. M M #} IWN051$|dEBA_28eRN_ůMvu<L/[ჱ@sP<7K)lҦQ:e#bɏS?u)|XAo#8דWn&i-mÉu3gx@ܩ:+hrLr`G;ctYtkfχv?'JO0M:<Nt_f<ޔ^^dskR[6z)O#خ8zہM^4i3'ǦLb|/7.}p%k$‡ɟ w/D')4)Ȋqw\KyCdE+f[JXm p-'I0 Y+, .Ri"XWJ51FYQ<)g@F4OiY|w{Y/o ^KkZǕ.#< `Ԯ)*< Ur. xZz9Ycx._% O]"|W7 uCk u_ 1ͮa76>+p*, `Wz 0ٸZ܎0 '*en$ b}0q`QO'ʚӉiAJȐ B:MdUNxK}_/ŗSV|^0cJ맬z^+6=l҆ɦ|_ -Cn|0S_x#> U^,j_۶ۈa b߶m,cr  +Vc6lu> dJR"_mdiHKaF~Z)>5KiЕk{(Ord$K\o 8MUKeʾdRQ6KVE-ꈟ& zm}UmtL.'ɧȏʟxq2]J#Jl|6G#v: gonlXB~G 70H`4 0Ën`|RHZIjbK}+mu_PtAMRMhALrAS»sr4i޴*\Rٺ{*QZlv\??Fdߔ[*H@ WxeYqWB`ğǭ- D$%5)u|?UV<i7>uT|9D=vaS;#-ch$Ӥ1Ӌ&(OZ&i{2u @LPxJNSd#״*h,/Մ- zi}**^[tRY=s2.]0-|_ Ƨq$#cSL;yS;1u,+dZ^m `3HLf>}T 1:8y$1mWv^ diոLPk1 jk 4rGBO|Ɉ9?^*ʪT^ )tћR\Yɗ^\[tI{U L?~:NY>KsCz|)8mAWkqb}ⶶŵ)4bJcIZ 2` p^P|yjchNCѠҏJ:É$e И̂FrJ:(\,E{ឿxcTtUL)]6\Oݕ^U&'-تiI6dԆU}A2es( &: A/'߄*.d߰hcS@6ZP.CV|?s…__|ɓs% s.ܷϗq5: ] *CBpZ2g *'4>4e/ 9~ݱ{ᥲueTњv3 ]SzdSZ?e)WUZ-?0W|h1nv7bµBmda.!,f6xld暎WOfcW-ી56 NVLqav/nc o=@nXA|rϓa߮}qjRz'3A*QQ,դ^*26Qm!_$7UɤTӾǩ˫W(\:3E4)G?4yH$|SyeLWf1q)rn(YfrIus<_4vf2Ve' a0caڵD06 |=%B7|6LN-id j6cQ\MؽRY_NuT9'SEK龍/#S%J%ܱU<}{U:N6V ǡ$#xĽ?C3,(˟u$?`Bpt\h׎gv.XO}fbvIKV^YdU^E pĉ0Uu@q/lyqˁ3EshEQ\/P 4ʦ۱m={mj Cv4q™pq$9 hasNJ9mTʪn*9*m\p;F/J{۫yhU2iSy>Ǒ^&XNj_׭#?.rUF}sϊ}Z~E"GB-ϙT \Em|rOگ.pH+o6oX]c/6F`IK!N,:VORMb9 iY4-:jyNOmYU2M99߾Ǜɫ~N}9^ʯAN 6ڭrr^&WDU:e|WYC- ~#GHqd}b㉀/I b1:jRk&Y]Ķ4$qmj c0 F0/&@_TptI b01@ IN^&ĢQ'3"@t<2D[$AM*}Rٴ~nL6玙A= 6I(:Z\Y@Ju#(9Ak*W7p>y3Oy`]9b n_e?e2Mۈq  Wgv>}P?%o+c)^ =O:?d;VWfR꬝~QU0`ҘӇ- Dޛ$Mj7vŭN-8Ha.Z-QU"7u$kb),\TL[r$ȒK,!6&fYmB#AK颥t/]uHvP[xձ'z(x/WWzS]3G)3g{}%C[ SL%{=M7b4ql?fgTf;7XBCd9OZ;`?8zRb)+vn_念 3T6À+%20h\L7Gz?D'M2^,v|Mˀ%sMI $9=dxZtNb_I|^V/Fr:o)=xi]]%|6UU?9y/xW{z*;G>r N\Kۆ/s܆Ϝ4pyx<S^sOR`e?{SuTi9mϗ*:2>I6GrvzvR<זr}|_\ɉGff_+ܬO q< auY,.]}b0w~iU"dNj6e'[@x%x =M} w_uwC0͚\+#$ZB8ڑA  2A6w\dS/=OKGE{տf65&mpʤ s|-~= ` KM6ZhqrtLMZ,\L/pprrk25~ 9%r,r"8*8Y y%O&urrUɦ|}{9|eJ9<сMe|\ˡSF|X]>a.|O L &:|Q"@4RzZHuʦ|_Frii}n>؂WAɵ#zzSTKS>e|N_9?棂Ue[ᔽo?zgD߂>$(JuӸi1,,T\۹)Ɵ%k.kf`+L> t .v?>{~|H@0d@@j yrotĚWׂ9pq(x!Vc|s2|i)/G.w_w^ȷ[tKQWnGa .xQ1rduh*=[ʫa|osp}#bV`\X2{ƫ^cG{Ϟ=Z6pTk"J 0N s|hǁ_(bVNRSf/v40ѓE/۲z'W_N`?5 cY sL ؿ^KC}>Ix)_bm v9\d玕R~Ot//-O9ʴqh:@q5g震.D_O[х~g=XF {ϊ'*YY+ejnWϭWZ1{|H3~~w?kcl@5u_J'kpdEo+rLp]Qshdq,$ЁXtB<\㬒[ε J6Е)Wc/ʉ='ۄ[VT?r:_h+hILSE/IUWudtCGj!{hMf_ݫ3yYSZS 3RJ NԌ F>`e ߹%85erO[ c@5ƙ>ϝ/02NB|h=OJҞE@IDATY΅qK: ('"@(yd< G^*KYuzUzz6<4w8wc\ ='ۄSVru=O8Y*<+=3G\Ps2;!GR@2 ʷ39#1V WqŔ]?W֘4? wl!XUy :svF9Vsk*TU,vlDZ>Zdq,89tG^NK< ӫ:^xlU9/N/*ٔۆ#Cg>@su4[Wm5y9插pɪ#2RYsWsY||DZ[[Uuy}A?WZk9VWv.t<]*OMKwjhdA/.M74.=E? d,[<˳'o}h~B7p"J(8߆ʾ=#+zoSW JIҵSCxyxwS\~ii617zUF(!|xBzp#{#^`(c]STgsS{V>gs= vj|/_3WuzrX@A7q{pvD,Ar=&tւG[tX'3ʼn˝tSPeAs} QN&-)㔔S84_xOeʾ/N/*ٔN$pTҠQ̥*~7oKu*NU9O'_82tNTfцep Ys3y&H\||>#&*$ v&vH_;5\3.0Oqoϯ?lKkr`\3jѳʚA:͔X ϗ&I,Zh^l]Mm&&Kdg$RG '!ĩddNhrLXVN%P8|Pte6Ȧu}9rN NVA6`GumWժ&sU4^*ӤW9WW< |%sA<$ki8R4Qd5515E0{!||Fwe)jS1kwbrWf~n쯝Å[mtM.Q0Z,++uݟDUiL 1 ,V [ ࣻS`NAC' Mc $ex~VnOMG\UulNߍےlJ&SUNSgMc-;}yl΃))˲hImَ80CAO @>y^X)˔dQ&%˦AAf&{<&]uתU콪vWծwLҍJ3mkih~ow[=[;![ $w#O3ƉqDbEt/i/یtKR|M٫s`a䝑M:T7:/9[9y/>t|vthviPa`)n*'Anb=8x6#tGE~tY=uttڑn 'FZ)JY^rerW2*v o'1@N7ix>2"?ꐇޫ^McD,K^Emػ!g1D"a_?jF*UlV>MV|5K(|iQ f}pT h.cvM+'&olGCٍ7JXFȧBNO`ЂH޿WFnQL/˕Qm|ey+q_΃F'y4Z$tS=q?_1 ^19Ҍ!isE|b `H,+ig?EIN 뺿  7pnŃtb:31 CH3Q`Nk#I]f D;V]<Uv@ 08*I_E{66Ra'Btj<[Lh_,vjT=fXZֶe(Pk'r]uHI;?[u]C:tnQުvy|Tx9l15Ve.'Y2yQVLsE)WV2Ci?@Hkz yh`e}%{fƅkq.m̲{Ng8=\.u.;5 6:8AwKt%}$H VD;V:u_Ju48 M2s8wgߺ[W^J%61#n!i+>cpc,:I^CI#w(KgbybLL7oG>SnmI[s:/ֿxt[䕕)ʊi(+Ӊ1MYiҖq倿#5?#&3ge. g%NлC?гSj#FX GWeuT;::#gqd 0==HZ3{c.|joc_8C }]2ڈlʵdC+C}^ePMqZ3;~H;:' %8Y:wZe:eE9ivye[.nfzRv][LsEYi^;!Z XC^FF<hX7u/*+PPtt#'G~=6vc:q߫hv. s;s^ P;ޝԥ[Pt1 uhcY1:E]u,/u^G+_ﴣLRe9M[Z ؑ-zote3ˇ^Nv 1<'1o5Wֳ0EՂl5~%ٿj >ҒyU?( #Hmy;`ߣZ*@x ̿q;ur9΁E?i94uS"'8?%ixãCNW&/u7e-+q2ڪ|~3Y;լ,vo,L^&+;2d1߼i#mOȓC@<~z){|x5ε54 8g&`@ .tOl1Q켬Wޙ?Kޱq'UMtoX,k{E^顧d4N`'G bvy།PȾ~׳zGAME4O V .C1u;JV~LL('MH;Dˠ|E+NY-+b>!}Pڋ< ̀5ogQB`X`Ĺ?xj𩾙J(VJɾ+%/Q2]o[`\vL;4ob7X`.t+G:ƗԆ: ٿS./N8BYYƏ~a%V`Ƚ'Q :iJ4C; zS/;4o=Gn!';Oq韱t=?{j3,[' ?kᕿ+tG:[T隦1Pur t+@E;/tMxܝ~Wr!saX{ OwǢ`PMuʾ/=q*|1ZϺ8ֱ gЊNZvK :;G`lsQVLe2ۑXiԱϠ[E"w}}-C,.cY1e2Yżvqo;i(V7+*R4e1|Li xw2=2p}AC}gj8Pƶ ՠu[0&009cajy>5&%ĒN}O8ݜ5д 9緤c?gݶٽ9"1{)KB [f%I"<;?% "K>1:RE@`@uA=(;.g<zLVԍW,K&!i!/2y,߬T5~V׷+*R1mE<IGjGn ' %"7or|؇~Oot^g{i64K[M!,xA<֚W{&6IviZoŽwtY}C H@5}_ةN:/u,v^ ༹X#72I66@ r N{@4e3)dvХ KrM2Z4ʢ.|cb~Y2doդݞَ֥n+K+/He9:֣ ȷvEr@>2O>#[1eOdP,1Lh(XԎzƛv6I=[J;зX hxv.= Х~`@`Dؘt+oꦩ,*w`PAO e8 `dba"g+۷/̝@ ge<4M`%G4l=w e_rZ8667?3o?=3o^7>7<}Og]zV]赪Y^LhzQi(6F' xq z3c~NQ8}>_˦jN3 Jpfe֏3d[3~,}4dlJ5fN+/---iZ?Ԡ&V#WhC%ExC`‚ %ηG4Xر[[mux&jɭH{.d:)%x3Ë%=BqCz: #35H4 ivPB ηG@f9z%FdYv-EFu$yqܱgO<tn~gD?/-niTj#jC5l*RxыNC;rûdMy(PI{ȣgntc@Ek.B(MRh7{\wj4ȏ>^k jv @Жإ]z]p>'p ژ"j}kkןjWglW0x*gwGVDJ[ ~T m'`쵳v@`8x7DqFh}k+%ُ@^{;vsx; NCNcjʑf`&#V<?˜6\Y@,4*mW_Q_??֜8NSpih (g~?_Qk[V~fyq1 {S.p8#'hЏ3~L^;y7^cg?1b༽S?4R_}ZWJҿi]c]k9h5Gi M<,>$8iSd/5//ߕ Aq $|* iSltnd߸7Of/f%`H$m G92bG@3B@.@y+ /eL ez,4+nĂ۵.qǾ}/|raLekLnw28ǼX:P#hy[Xξe|4E=ӭuUe0]iݴyoS~,VԠ Vy,)Nw9Sb'mHVD\ 2vye 7KX `K%IQ.fegW3|3}y@NL I΃i_C,sڴX+:Lz egĸuڵ"̾~?7%~)nfyr P'Z'<";,z P-}ǹΎ- OSWHTtuǸMР2]c=_b6pa ́lQS>ie t"PH[u,K sE9.O~ 1,YQx|w-!rANk}CO]V([B',Lni'x662s߄Au>Fɏ<:r~<{qa "_ t5cU`eCO3cjGXysldy-aW:qR HN멀5V(rG`]YiPPr, %rrq[G[{[<*ui wJdEݘ: o[w>erܺPb>ye:ȋzf kzŊ}~Kaq5mˈRu}R8:ƋkvʴqidQn>ݶ7yS#C'YfAt|wҞ#+<}Mkmõ\Pͬ1kp?^>3wն龿hzƊt_i?o*vmص٫jv+@  >wf=_g<{zK`mE联sgsNzd?/?w4z@U3,'y =:@o'yk9yDy(9˭yP%ŠpzL/旕!/uNJ,9WP#A8si,o)yŦLO>gj}SGSh>=N_p w=wB]~/#uSޤ+#H|do\Q.ol-'߮u8A]v[;OnwN}k_Ora_J Jn wgw}/gCkC@YX^x' s<@Giu]rG&fwD`T^8+<2HD癢rNû mj##m :6oF̠nj7E':3}oeOǛgq h*M6rW.2f˦3-sn DnI~'' Ԩ,$@u-Jaw^NS *Nc^\blD_^ `AٍW>֧|6x{0Zf4*H/@NO@ D'XԺI)#e8gz:ǧ~2PNw: ͎?:G,m)z؃4mut; H%`"CidMѱ^Qfuc5{粧xgq%\-}h#5cub)_,kKjt_O#| MZO855խ?uKOKa]#J Ry ! Q\(މg 칮[Du_-Hg /~!q P^r;u K8 %8M1yʐ@b@Fe։ydE[~fFG$cP4FvOgGo|x1@MMI[U3уZty޲[w?`s'f?$n ; }o{\y_zϿƀ9ѿeOZZgVhX }Y -u-$, u >Ch\\VoQvKD]|)q)7"n3gv;Ͽl|m< i>dHÓ(XFwOyzkݦȬC4rB'/i&C7(*QpP:+*Q/Q('eZvqeP7iܔ&A)M:Rt{#ntПΞgGV3vr72`ɳ~p$ sydO86$3Ү]XxQ}#c'L>(^{jUGЗ [:ϟ?ߥ̀髁0髁,#J HwϿ@-d̿$ m `uvۣ74??v&W=cQN@/t tFӭFY>yj<7uy2b4x#G44F|̷rIdl=u㵍dō~ؿ [f؍ CSJz?v9tʟfk] 퉠ځpn}[OB h@Ɛ:Fqr'`ylsw]$P$İ8 mvV^}/ɛr#`@oGnj=72·GnӖA ˠN:bu#-:Xf{ٿz_e[N@֨STn\kF)(n%ˎ+Ԥ^#we2 =SNC>2'3H;ȏ;}NH-fg]2RB|&lVO/Yզui,OZUΩy߿]v!҅2_l7=TemjHe@0 U90X876S1F7V=" u/=n ̣# wyS˭P×QdDv.s~'Qy7;-niRÖcAϺPⲑzFeNg GX#3hQIgJ=[٬-~xJ[Db= =:l-m3Fgb)kYMmEWt~σ? ;033ө "i?" _hHd@yo?}_E4:8r+'@Fh`'?py 7~KoN ` PGC]ƠE2ʢkJiE^BoESf =Cw韼k>uշ>NkL)@J^ʢuȃ7iGMڤ3hCɋȣoDg}_gS LOdI&b7*٣n Gud/H3]Kiǿڍge[_wuᑿ{%@/S-'^ Pぬhoɀ[ ?_[x#ձ]tapn:uSeG Pcl&G .x癇m",ỹwuL]z1-ʝ.XfۑEj1H0@M K5'(ym`u9Y٧_tv[vYd~AtЋ<ˑ9"3urdEoJu$2]Qfjx1<@%DYQ:M QQfg R):6c =n:t'S~S eFqW~󾧏|ƿsJe͌Yۼ-vk `?BԭN9N@|I4'@RO5Z 67Z}H [Nkf.=d3OHiR 䖛"<] ȝoo{ ~Mzz{Tz!4X1E]S`:Yv;4(wj ad&vxk7Nn=GE)SdUhmGUU12rk+((=j}l`u (`CI92@}H>IDATOeCC w #;zt9m@|y'aȷyַ-D sy(yPG2桎w=N2C#ȓ>-t-d\-g+Bt#J{3UL0Cskx/rLsɉ2*e' 9Q4_;Odvxp X5?E}P&7:rSK[uˁ8]'X&47Ӏy(i;:/ؑEFyИ.|O~tӏڗ9 :`~~ìnZB\yEr+ 3#{I 3jsV}nAłJw%nզ`hb!u.`!AM УD' es7\Q F6 oZ`ʂ}qxrFNWTfbn";;OܙM,O #(o:RDt6mH'Pd @`4fKP!PU .c]d#3x[2Ȑ:+׽r+/SA}>:#8UmC熞w|?ů[j{_6SH MOhwiw;EAm*//L,l- R'Ut vK5[/ˈ^s9dNgO7rNib$"4]l'1z <˭kJ=sR#x գ&o{S <=xp"*r ^]zե^c~dž?fq%_~TrUZ$PH!J)O '}&}BX1Pܯ--~B|-PSP2Wb_l"6RF[71]٭n.%@6(s,`'jp3@OzocD7!zECtyy|PBL;:ih(c^Re\j"u@yePQi^^N8}1a:-txf^7_Ðr 9mR[ ?ڡG:.tL_ٿy}1g+"?|9&`f+8[YYHV4J[F~;5z%#/瀫2-] +=1oPف g >n?;t-et+ZH0o75;mj9DpO&;ٹsMB8ۏ?T%io^i)؜eC}3y_cV|ҧ}5֮߿zkj*q@4(y:`TYs6~<k+YV [ۀv&Y@/:!YLvhPvSk}} QݭzeG]-3"#Zu(NCc<|:.rr'Όi|%~Ơٿg.CU Wعl`f'N%?ZOiRjպm!Ў : $hhPo!7rkF@-:U-`gv2*@;!c9%ZN!sDi_Ӧ?ɖ*-kÇgT+ }a++hPk-P*گ~ٰ'@E&i~g~ |"ޚ6W,@c|Uz$J01?[ؗߗ,yk !,s#弡Ol^/|>8 `w'nC燞'$?f+}X\!C;1v`S0w`w$\$‡d)m¬1qu7 &PH5[p/uI|e1س޲79Ty޸OLgB歟OdL 蝇 MUp-if?E#gG?qroc^\OY-K/ѲļV `cj Cxr:pT'{#0udó$JRVl+^!,3`3/֋P G w eYz_ֻޛ HKnuMUwTjts-[]VW4z@~)C3h89p3|G*|H-h?F;5Džӣ=qj)%>ˋ~e͆e e T0:!xA^#t;@+|D(_P53f>2[[6/A" [4]f;Ӧ<6!F.KCȣ(@Sz-3%Qx4[q,I gP hO!?5W#Flri L/h\枿v*2/T}XrއbVN@\ P`? Xؿpn څ @Hpx@^%[ 7| M"5#' NCбt) o͋2B}wD@`pFf"70A|ˋHwHW검3fs+twx#5q?kܛs<֠+?9פ^;Pcx?+){)N{%`HWXH67W0 `Y`(%UfÃw|;8ɡe|Vd;, EGF︎H96M gډv 6'|3~k0;ƹ~/jf+r%C=͜,7~"(п]rB}gn:++?A ,@{:Ih_b>z1u} Pt,G^cðug7L(GU9-q̟۴~&}};u=2)QZ׸8'׸3:uMRaza5^RݸWT4fN:|$+9Cl aE@eFNO ܗ?# YH; D o[j) tԳ Ku#۔A2ʙw2Zs,cp6Ӄ?:=;=?|f_/= Z@j+_쓮ú8qQ=C璬~;8 UawZ`\|~1/ R 7 F>e\W-U^fio~JKhl gFnS.ϊ_,u?}ҷ󚥛*[+h,Jèi"O ws'@}' Ź񹻦J0-o[ #0 JUbZ}~Yh ݉zYcK)1yQb짼4/jsnK^+l-NO6|8+#+7ontoZH-V|Wl* T,Ж~/{Ѿ*l߳~? ###cccջe Tdtu>%<33ө^xYn $'@!n @-ٳ g]on8`5+-UZX97ᙟ{/~o?4Q4~ӫ}umnnn ?!Z'@vzL0  v=$ݚa7÷b&#T@ed {3q̸029F㒗Ӌ}p$Kl'&&<OPcO0C|or J@zLP}}/ `sr~uk9-pA{5^ -PY@e,}\-߹ѹ$lhfUiJ_[|7_>~/7*} #T?"#9<&@rDŽwD ׏QX[;pJƤZfmYl* Tأ}{DV.g=+=_t/wb_c_R~<_OV C| ]1An "Hs dcO~qqtif)j#mG xV@ell?ξ;:|x 67񘟢?%4h98|UGFnfzqO Br1IJsc' 5 (Qv| /\z{z]cI Ӓj`2{۩kHQYr>*7VN7@2 o5$v/\8w/-/᧙-#K bP;@3/NxccRcȼ~M.UbK _~jnXWnפQ𑚿Bi}X%;=rxJ&7ie`~=ٹx5G$(#TP?N@ɬssY;25򒆞 _~oח=_fɿoɛ0X 1*k G }0B Qڏ ?@u/ lm:wܯ^Oy s~&W!sy>{wٵuFgi_/W?|K^S__ָJC\ *sמP~9(oXu QO5?_ `{_@t$n `*TJ,D7 _?d|V35&ܟ>d{K[=Ϩ\"W**jf ѷPI+PVX CL~ie`&*@6U>B x<ڧo}GoK~ }K}DY%MUd_\ /8vn !H/?pyWc88ހӟ {?jFl* T,#>?8zn{?}i.h,h<.䯸YTa'Ic NGȣ[h M8q[`hs}B_^^H=6 J,X`ov^֬{ݛSj/YCyO6i6UK. -_ `WT_?O7HƣX^y{'cwX`@4JT@,{+uuMMx|p~M{/Y4o󯘪~V!1տc1MuGh&[|.=JA Ha @}`@WO ?M@{-pi45[U+ \) pݱ{s~m'{?=x?l?-.z֯W"mcf,kUq]fU 1 C·DO A'ru`$;#SGmҕ#`*QY,9vrW\Ь}}zN~6 uoU_T9Uءp6%$0<;g|Vom>Vd*TL fM~k,wZfxzu_0+;?i^q/G _E~a--Ng8{l X\ S \!,9]CzR7 K~n xE'W$BeM,`~>рoCJeOg/l\H|sP:^CXQZ]Wyajh$XRWě-trD3*`ˢ#͂EGGF*T}>=~x7_+w^ONi}~f լ?tK<8!p#jʱ߯ljmiD|vepV72/[`B P; 3~/M|ǂuޘ837g,~d/UU; +-lÓ:uA`zdG xUk@au`pyt&޵_q@\ ΂P*TlYAyv$rY9=vvzѴ/?yo&;*[r>t TNo6_@V{4(t wy5@4w߯*x&LHy8){vb3mD''GW ;2Fvi"Β>@ojS/I@v?],gYs4WzCo g}Gfb:TTv*`6'#B[У8Z3=|iPX1>{vJ@}e`PNss=5P;~/E鑧Ǧ^dY_<~,?=700G|6b{:Sf{_Ǝ`5@Ŵ >mo O hI+;r@dCiE`l4:q'zà%[EɚW裞~\l:gfl s௧~f[lo_7nE,P9 {xJ- $([hI,^Hytp"p\#ӯ*) #[菞G|~+67{~U>YgO7&lrUG8*~XrN[7=c(Nn䶀ƕ͊ 2ް"ri( ;cwT~c0?30EfgJ"}/{2?yMhjt<7/?=+^rrg>?ZIX^W9{ (ՀQgG'g@ui0X\I+{7In[Hx?-3 d% .Gf/{~(^m }K}GfF~ޒس{8Q>$Rgrt-IY-oZ[rZgOG M}ZP:hJO |OI4w>O- -ݡ7 !D"Zl* / ЗPB|@|he~om`aѩzVzI;zoY/2_ ^ÒT.pI; ^$$m6|66G|bqd]å (8quWA\YU,Ж<{lߠoRܵ5 3B1+ZPxN^uUkT" TE&%N9^x$bzP+G@u]6~ǷCxo3NWpPY" ? ;r;RW C}*1`Gw:>kԯp>_4g6q޴/T*m`&@z6Hp N;vrpޥ#c,.~%gg΀W ΀XW=  E=76__mxfžSRK >m#&~Ηv{wOr$>tT+wWYPbJl&Y>=2d8}0Z[=*y|R ^SU]FlvhkC!3=ˇ L&л{rh~e_ӽ~g*J'>}~ ,zzz3 ^*mV.ʀƸ#Ы4}|m}3#3,-tYtq(XU]`>ԋt ~Vo_UK/M@?: UEzOj6k{/ɫ{o74iq%^* PueKq4n d8a+u'+Bltwr`q١4ӚO뀟vMhWvoV,Pzo @odT?=BCU;K/}`:!@pV{W-]p<Џ΀SUC06DiC%!W{g_ug+u?+پೱZqn>>:'?:՛dT@UeZ@%ê͊- iu@U2U*ȝ'A?; !9?!:^ ptHSCsZ*\ y`}|x]DPLn΍"'U\%~/󧙾rrҎM5{s1Wk\UڲOC!'5FGGӪ4hn6A㟃qy30t$`e#%7(_};e`'21f8Gַ,mO4E@'F`gRUw`i7Cޤ(3{^EZ8zy_}v}_t_ziG l9=*2lUm4!|k~@3вhr4` `U !Ձ pZ٫Wܧ[- ,ݴҷrzp\}:z6@NdG 4&/ay_w-_ܣM}7o* Zr1YC#{W4v`U[W Rg  # GwkmD"qy`F8.g75蓆0evȇ'5I?: |\EǖÙѳ2 AzE@iʸ^γԻ{-9i%WH,^2;rlc/6{qaBL)X'Gѣe89 K԰A҉J=gїL-U3; DoI}|z7Ke@ G׍7S}Ʒ`į6!F,6iY븈U~<*i޾c,b$o;8`?6 s6r>SNaL>m'DϚYwR -aObhBٳ~6g?^;!=I?*?wo_D,uR)h}l FmT`7 X,(hW 7k!p1@%^Kk-gSoAc&]2Xr, sbu7 8woqY>g`3dvw;Մ?AXwFQOZ^o/awo_jK~Ge1ϳB<#.+1ŋ ^Qha[VyL v2Ò A1UeZ1mYLggq<,wP~9O^Ozwo 뺘jOzZ!s1O?d rЖ>C&}~W~U P\:ZKof=uBFxLE |S* q[`8pG՟cG˧?hBzw;&Jιn5di-9o:.w\rޱI8c,{qs.sٽߚgbV\!sn5r ϵog"ɞ/a}z-hYn}T6G!(BVtϔeSoxP751| b@8U@ ߈>`y/`.=Qz|JRF (Bk3,oc[m~mMX_5 3|zr_{7Ox7g~ՁMm.V^6RWC mI=}zEw\*"(E^=i3džM >6g@B/B ЍM(:!&Mm?h|2!pʼ߶Q{W~[]ћzٟk0t6=6-g$7;!z>zXV;z-!{&5xwAm2|1b.UM[džŀȿz\0Ob8<:`@`E1B 8=LwY::OA^cKlt5Y=['gvx_H_Ru]!P`WHq>i} kb@r&`DB(L/x #rSfVb"ꑓC1c5zuchgd1^HL$"&X nWG9ٖgc"h8f=r27ԋT/=߅q2;@:^8H_y }A-D/܂9Bro>&muiֵ}Uv>J_5=`,~A^-Yyt5basYk`# Dn1bM7rHm !m9fvSU_cչNru'" # bU Ve>zX(B/x{ᫌJ" fkk|f*rp8K~X >yH__E<U!xd\rQdX8~Y نXW(e[9N9mqw1 e}sm,j\ɄQ]A-Xe:D}^m[ꚡbl>yk]1kaỽf$s*QW@ bVS# bHeu@d#H.(?2P.@eccMx"O}XDtn&w>1)nw?~h #s0& W-JxPY`sNE)ou-( '&-D|n>uaF>}Rd q8\m܈rن G"˜T)9\+d( ˈr&1Q.q k.> Wc\ maȴ%ö8H_m#- k1y8>emΰGի<&x}l{|COSsZ;%WoC@3$Gkv8@իW}Qr-hUh Æ`Nqs='Hdmς b7LG: ͪg D!ن}Ι!z:MyRe_%b8Q8 j~!paFw+Qp 0-H <@_'cokzc. ;~C-rAԔU=xL$OlB gqѻZoC[K!P#c=SQ!PlD@d@e[|8D ?> ry@ eO! 2ɻ,Xn>7rYq8sКل2>uyaY!z9:R}#粲@!p@ k,+j9wa0QbHXD# 1 >\-m7Yץ϶{S{c\TD}ǢBx(bU{dv_I$g? ,M ,*si`b.L9;&v3\OOOWo߾u+}ʇ1BF;*[G1- ߅-€}e1}s=B`pks3{;cI zoC>PB#Pc\G(D`8]82WOn"\~WWo~eŅ({눅FB>M l%츈>(UBq Pq\:B( B`F;=b( B(@ _:B( B`=uB( B`%( B(v@ c^G, B(@ _:B( B`=uB( B`%( B(v@ c^G, B(@ _:B( B`=uB( B`%( B(vcYIENDB`il32 r3  +3 +#    88 44  w描H#su $ % 5%   ww)q +4.c4  U3%c   4GT9 $8C!:+8j4: ߕ    ؊4+4$ wp  ؞ $ %ў&  v掎ٽp  44  ::  9    +$+ 31p佐n"$UҙV,jئj$DqѦrF Rx}涶ٽ}yR,\w}}yx}\' .Xpxywv vwyxrX.!HbrtvrqpqqpprvttbI" 6QhqoprssrpiQ89#;JXbglkhaXK:# .549942. +$+3  +3 +#    88 44  w描H#su $ % 5%   ww)q +4.c4  U3%c   4GT9 $8C!:+8j4: ߕ    ؊4+4$ wp  ؞ $ %ў&  v掎ٽp  44  ::  9    +$+is32؁    dHxD3 g HC ۺ_ l J,mڴ {` 4GH3 և HH$  $  $y|y VǺ] o±ɧa@ļ\ʝŠ3׶eמIaŮgfpgyř^azÔYg4MHxחw%3T׫TF]{||~\$ Yosv{zuspV( $AZbjjcZA$.44F%    dHxD3 g HC ۺ_ l J,mڴ {` 4GH3 և HH$  $  $l8mk !:_||_:!*ه'{3*F:4'~." %=/g_   h`:0) .(94JJ43 +, 6jj5 s8mk<<bc ef D>HB ll mm FF gottcode-kapow-350ecea/icons/kapow.ico000066400000000000000000002472471514263554100201060ustar00rootroot00000000000000 h h  N   ~#00&400 %B@@(vh@@ (B~ ( VYZ\]bcjgopsuvwx{|~z{,y,JpJ`z`GGHHHH HHDDHHCC{{mmggll__xx³óôŴǺxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  xxxxx4\d_]4xxxxYkrssrjVxxx1lsuwwusj2xxcquwwwwur`xx ^swtD&vwsb"!xx*'^swaNnf$+xx%-comgwZ/?5X-(xx#07isuwhAKT<3#xxx=6WiospQUS6=xxxx)FB;e^^[9CH,xxxxx.MOE8:GPL.xxxxxxxx@IRRJ>xxxxxxxxxxxxxxxxxxxxx(  . 4F4FF %$$$ A mZbjjcZ A m$$$  Yosv{zuspV(F ]{|HHô³HH|~\$$$333 T l T lHxGGHHw% g M a H{{`z`ó Y B f DJpJg,y,mmŴ ^ > a Ǻ__ llg eHHCCI egg f@HHxxDD333oaVbc] y | < < y(0 > HKLS H SUNWW] ` b hikoqprqsstuwuxvvyz?a?w|||}|}ɻA372;6ū8:2 @KDBCK MQmnKP/PRճ!̱OY/5[\ԉ 4̱V]50^fl҄ѤTY/Nl^k-"isE͵շ_o9kwbvSxWvjU|FҢHyUt~e̴hzrLHıJIg`GeaGcdZZ}{SuuX(0 UUU (6 ... +2P > HSSH > 0O +++ 7 ^WhqqooqrhW : ^ LkusrrstrssuiK1]wzx|LLLL}wz|]0U|}ĬĬ|U +++ G ]yLLLLy G ]Apq3WMND''' b  ` ;vLLLLu"3"L!Ĭĺ?a? H ĬDL!Ĭ}}NSWssxqĶ˽ٞ"!$##&''&### &*+&$#$$##&+** #---+2CTffWC3+---&,..-4cd4-...-42.?zu?.24-$454[U255& 5;6?ÿ?5;8 5>>>{Ŀu>>=6$=F>`Ŀb>IF%4FE?ü?FG3=QL?ſ?GQ>GX\A˶HJXL QiZY˽j]QaZ%\gi]1 ~]Xgi%(XhiD˸):J>"0 ^ h  T ` e  ^ j88jjD6::h n88CgCAGG!Y!::n+++  o 4_4GpGTTla9w9 i $$$ m g UxU˽ٝ%%cc  d _Q=öD/6%44..cc44) |wwww))qq { +++=.  5"$$$ z %% 55%% r ~  wwHH##ssuu :44444-'^F 8888 Y:?3M*###  {333B* G'+++333<!g: _|| _c:<!+++  ???(0`4 47 < :<; ?: = ADB FD F GMK KFN Q RVZ][ ^` ] bbh_j-Y/ hl p,^/qr3^4s o t suvwzz{x ~ FtI 55 ++89]wZ45S{U7.*+%%8:35?@TQACMMgkSQX\PPVUkiW\cehhfbkk{zfhtxouvs|w ~x|~ywD@3,{{~|x~#CE54=?jcW\b]уϏwpϞΪʼߣ  !!!!   !&&&''''''&'&! ''*)'''''''''')*'' ',,)'*.0.*))).0.*').*'#03.,03*.57;AA;73.,10,.3.#)3313317DFYhq||qhYFD7133133,0733537IY|YH7353373195585DV\\VA5855931;88:8Hm``iH7:78:1*;;:;:L{zL:;:;;,!9=;;;H{ÿzH;;;=;!5====DmÿcI====5);@=@@TýT?@=@?'7@AAAHK@AAA7=IADDXSAIAI@3DHIDH÷KDIHI4;IHQHCŽFIQHH;?KHQKPSIQHQ?%D[Q[Kc̨aH[QWD-HZU[Kt۸s$oõqK[UZQ-2QgWWQ\`Ռ`\QWWgW16UgZZQ\`ژ +`\QZZgZ41[e_gQt ;! BöqQg_eZ*/[fgeWcb R۬KQWZ@!"na[ege[#-[eevgPO(UW_gfpuvA6GP^vee[%[efvfCkwggfvp~}Egvff[Hfpvl[ҳۤefvpu[fvpvKjj>L[gllg[L????(0` !!!) 0 0)  + F1z 6 9 ;AA< 9 6 1y%E*  $ H4AMW]agiihb]WM@4HC = Q]gmllopoopnlmmh]Q ; D-:RcnprqoonnooonooqrpobQ9-  GKaossqprtutrqqqtutrpqtrp`JF """,bUjuwtsuwrtz~~ytsvustwtkU*b"""3w]qyxvxzv}66OOeeyyzzeePP55}vzxvxys]3w /a_u~zy{y~66zzzz66}y{yz~y_-` #F\v||{**????**{||x[D*WvYYAAAAVV~~vV* H ruurrsF &Ahuurrh=!!! Q {ZZVVz R -Dq++++p @ O ~~ K %b8866b#0Cy~~zzx$?QwIs ] 6655 Y   f SSPP c ojjyy/Y/iieem%w~~??AA{{ G ;4FAA??zzv##x~~??AA G =?@D3_3AA??yyy"viiD F CCiQCMJtJ¿eer r SSjjCT{TЏiS_ffOO l   m 77[w[-_- x 4466 g ^tjj!!55Zo1=~~ɾjjуzz$877 66 m фi8:++EE\\++,4 ~ ZZAAYY {  -2vv>>uu"-  x uu vvuu t $$$%ZZAAAAaa;;ϠZZ50**????ߤZZͪ++,-PO77~~88KKkf77SSjj~~~~jjSS66fcUNSM5/6.(  3- >-+++ @3  E3 :5|m  |m:5+++ !!! +++????(@3427 5 :>@< @ ;@CAGH JGMOKQU)F'S U PY[Z Q!^abd _ X"f&Y ,X.jj g l +].pqn ritu0c4;`;vz{ |~U`S |Bp>MmL UoS" #!)(01778/ 3*-- S{U Yx_ ,ex`2)24 '(.0\^]Y ZWZ^jnnkiizxz{}~|x86#bZ9&20<=VO]a˃mgtvӊӓΠͤǴ|vۆҩͺ   %%%%  %(((--------(((%%(-.---++++++++---0--((-00------------------00-((.30------0022332200------02.(%07300000377002677620077300000370%(67322237738?GPVV[[PWWG?73773222376( -776667777@PYgnzzngYM@777666677. 0:7777788@WgttgW@7877777:32:8777:8?Pez͕üzeP?::7778<20::88:<:Casӹ00saC::888::2.:=:::=:L_NN˿_L:=:::=<. -:?<<w~v`ENjzzjNE`v~w>v~wlcMIDDIMclwvmmff:vx9@yy@PwwPYvvcIYfmv{{vmfYI??????(@ UUUUUU"""!!!) 0 8 @EF @ 81)!!!"""*A(l5 9 = ?BFEC? < 9 6(lC++++''' (E,~ < FPWZ^beeeeb^ZWPE ; ,} H)'''  &!V ; KU^fjkknppppppmkkkf]UK ;  W"""& +++ K 8 M\glmqpnmllllllllmnprmni]N 7 L $$$$$$94M]ipsronnnnnnnnnnnnnnnnorspj]M6;"""$$$"QH]jquspppppprsttuuttsrppppppstqk]G!R$$$)jQfrwurrrrruxwrstvxyvtsrwwurrrrruwrfP)j$3Xjvxutttuxxuz  yuxxutttuxvkW3"""&+++$;^pyxvvvwzzy 11\\yyyy[[11 yzzvvvvxyq^;"""%5`s}zxxxz|{22kkkk11z{zxxxz}u`5-h^t|zzz}|++zz{{{{{{**}}zzz|t^-g+++  M[s~||}}llȳssȳmm~|||~t[#O@@@3Sq~~~!!0000!!~~~qS6!!!Bo6666n@+++ @b|7766}aC $$$ J t!!!!t I !!! %Kjj$M """ S {mmmmz Q  8k****k; =rz||{{{<r  [ 1111 Z 3mllkkm7$$$9] ~6^$$$ W 1111 V   a ]][[ _  i{{yyg"'qTnTVzVn*.x ȳ\y\dxdwwU_U(F(@Oȳ v23{{s00/_/@@;3zz00s{{ 82{{s00<`<@>@@AJNmN00s{{6+~ ȳ-X-@@#X#&&kRB@BRkkȳ } 0$z!Q!@ H ˆjMAH*\*x!!!'###t{{KA^^dHT@p@yys!!!$$$ o \\K2c2diYY\\ m !!! j 22$X$aa 2200 g ''' BT ~~ =T*ll==jj.$$$ y 22==Ν22 v Ug{{ۆ77zzPh$$$-** ̤++2|mmӐll { -8^^tt)8  u !!VV!! t -66vv66/ p 7788 ҧ77p"""!!0000zzVVȾ!!!14mmȳssȳmm͹ll,4+++IM**{{{{{{Ҏ||++GM  hq22llll22gp  {  22\\{{{{]]11  |  km  ln PJQL+++ +++91-2$$$   ~  '  '  .1  .1 $m]l\# ''' !WI  VJ! @@@ !!!$$"""!!!  ??????PNG  IHDR\rf IDATx}yWyZ{HK-Ȳ>6/,&$&a < y<BH '8l1&^ r0`!dؖmɖ2KLwzV߮Sk߷[sYye ]XYXy ȊeVdE^+"`YYWK}+8B!Wï!+䕈RϦu)Qji>+qr 2wy&y@8 PrPU5߿_l5˖Way ,C)*|%'400@c}J}'pE眓D"AIJG)\s\  &EQ4QJC"srXQ2%d2IJ,#t:M=ϣQ5 C]B>ԧz1RQJ}UU=q" m{LQi;t萏HV`BQ(#JVyISi/iǍQιb9ٜsnW8`@)cN,s /+PD*+ 4-KPLa?pW۹c|%NO_(LK~}B&Qܣ?6@,Av!C=-?j-dR-*b1}GbY:ejg2jfuEQ ,}Rڒ;?1%)ΫXHJ> \; ~S.]hrW엱cSҐ0B& o"J"P3⌱(Ixv~Rva(\T.ʸy뭭?UGcS4N\.u T )lVI$N)58qUUﷸ&O/ u"^"D:% P( hJX;x)RH]iG@;mGJI!FcЩQ!].8p+`Ma(Ř?1>IL)zqZR(,'qOޟjw(!M  j4MkaBz|mkh(,WR|Ra41_tdqSч> (RСtSBPJA)MiВ19|={(N'"{GxW0E#3PD\ ?kpR:84dT%{}Gkj]ZV#>]#>, 5Rk5Xjc5TBQ*щYߌ9'y\sx#XN ` A`Vrg3#Pd>m/ cC(Ͳe r``@+-u=#u^^|lLrCD(8B>ƱQوzP jIe !!b✃R}c}u煿=σy}//YY<͞F^(#p+{@KFA}83i$c:@`Y@4yעz;{uu Jjxr$r8@ XOcPiE I0QW@YŲ*QYeW@(-@u\ ~83RGn=B3SIsLS]=yBqFUU{v`@TsFd?2,at@u*ҋI2Տ*\ HYd/>`dž3*t<6V)83Љ[,=lXRc _Q㌱T#/5 XRF-J }VvE@SX壂 ?` Hi;0BŗW jG\>yۣx+uNC*Sqݎ3VS ɠ0q V222\.(`q2@d d ,l4~ Y= W!JK%^E&?O8yq0Kf` ,+ emMX^}B\Q@lg*U05X,T| a3zGzQ ͖ۏx+/PR;7?Jm+݆yx/[t0c g J`Y N[c/  p!ƒ$~k8G(iNj/uPP{ƋxG` qr9z㽡 be/h~JJ_-'UQҷ;MCO²Jnz<>颕>rEpȈ\ׅ(!Ͳh?3<<04 X˸T RxW6~!6l0\0!dIXLFa[Ei}~ ,A{(`X.% J/~4r?կD[ 9Zi izj(-4#klW+c">R)S"O/_j=}7vk -PG`=o:/ιm93 ߿?',z<`Q@Z.)fue*gK[@+B2/BuⳚ5_/ te6zْ/i#LWf>?^p¶؋^p JA4^"QLLZ) ً-SKg_︮PJݩ)yѵZ =?ߖνxGk=KAAam2KeAJ_U.W=z(?yk4|O@JscWwU *CxVߍ33?thg+__?,}pXb'ù'yiުUÇ/[\,GuN~7T/*0("+^hRRl1)|,C<~"'" ^3__( ? Kq c;>792ưilSHp((cyZ-ueP(myyX˲wOAL`"hWraeZ9diG9Y9X,`Q -.UUt@(?@ZAÕJl47)/wϥ(} w?y7ÏڂϿ?W-C뇸e)@Џ~|$./Q8$R|BB!\x~?"?sz50KY>!'SO=%T( X@Q,e%(Ҿ.^(NІL8(+pZsmD'G#ѲZ}#YB'*ZT_ 7Q B8/A ~`Z-D_jһwRJqJih6j?bmEAȑ/-EF[ L RV Wj ^X~9>p IDATSgޛm-D)?i#gWtq{Ɍ^dP(p:]|WЩA@+?&  \sgUU-,V {TC TUEUk'pX/ Ř#:\G ?H H L_JU}W϶\|Ϲ~h)fQ/{"B+ L&٪*\GCr=W| ,V{\|S~z-=k`TTi* ccc BHkFYl?>oGW+l@D---!D_.~3 =o-׺wF_i>O-[bYuŻwsR\Jf C>Xim.3|>fࠂ6 ))y7s/,x)8vz m3H"@,C"hPWz}{omwYi;xgV_ wMfdX m6\MF B ufL>r}9TUՋ2Mf20?==mpΓv=g4!Rv kk ]QE>8eefs)Tmjl8\0fPZ]?׶N#2[?!?/,^"$ U>t?4vWph*,0~|tS~i!]C8!AgFF@J1ѫGb#brj__+Ժ-\wu hL{;AonD}qv3o-T̔1-l F<8`0̛Sޛ)`Npzt 30B h4 B믪j쫳o (8/B^;e)#9r,@¯V_( G͚ ?"q7i7aҘ,!ڧCީDbΓkWBZcIB*SSSc,y^^oJX<E0`W n˨nWSٔ~>| ڈsT;׸?Nv~>oeI nVoƴ69%FkBXx~gPJSx, h$ h*R(Ȳ$=`: ߳< Cl bF# F"w:; 495##(@)Rj0ƒZe WCFXf[ Lv7vb猗.* Ujk74zg*B#~P4%|r<]L.Fd#pK '\hMZF Wb9QJ[.w^*f7AGq@\^Q~'ڡO\NP혇r}|vKH _Վ~|R8P&=++J?]f*o`گr~EQZ8X,e2Z|? 1|>B Xxe~[9ގ>lj~9ģKY@ wY7=R'|~5[ =Zۃ6mTN>qĕZ9qEQt:ݰX@# Q˲T۶ EQ^Nv'4Ҹ\X6ZG'R[\떂zs 4[糭20|T(ƵP ɅH{ƚ_jp=kz)-qmhh!{A')Rf4u]&^7zآy)Ⱥ1٣_T-/ϥ`|ߕ\Ǎyc;>K?&UR@`Ѳx@4;`&F:)" (Xcx=cs,Kf5\CH) EŸ"Ok X A!G8:˴_;b+Bּ̠k^˹'|{VPe_2叹`pz*2N&0,cfk4ȟo〵ƺ@Z-Rwڵ`7`PDdhPP !&4ijmR갿L%&pz=_۵A]W@Pxst?\?W//c74Bؿn$6#G\:@)MBx< b a(1XYS;›7xkQmXp}.:y~S]mXf ]Z5qEa`Qcaې:Nk1wn݀>kzG ;vXRqնmq8,mÂY"|i9 p;,#Sj(Flm|i1XƺP ]e 0Q|dEYy_M yq'or;߱(Xlel&>p/>E.Lc]: 24=1<M:kt;4 C,ڵRGD:0imm穖e6C\<25lMG<juf6 PUgy&Lį~+ aUs uϷ[\/==Njzn}ԣ<9fח< g?\Wرcx~󘞞8PS@X4%^R}_gѣ g"\Naiuc Ʌuz^\Vo4@Pqlڴ iĕ8n}V؞#Gpço_g}?Gz5J.fcWl{ $Y@5I݉3G;H$9r&''0;9k!"@ݞ+<UU5۶? mhX(Qqs͐qהc"_z]y|׋u0  gy;v<ιx?zTC@22FGsٯ,{>(X|`-`0p)`60M--Ȭ0 0055񰽭q  Y✒`kQ4B288H8PbXEMTn9,šZZGEG^~\tE0 I݌o?mGs; BShНUWZRMمx ?R7@=W8{m$ ;:mbpB\.;oʇ +e@`:C !@` 1F@!DZ>peLs{Aj,'WVj6F.رaGg݌>]<3_|/ۿ%/󼍐}'?Y K4V>4gShP_ScMn #AAu8N؞j 9"އ` p[>BNLTRT́RJ)%ht/u݈L39}PQB_vY}xk^0C3o}l߿{\K ވ~YϻP TQ'_x~Jx汤sU'ۆq*; 2DGGZZZ9`S1֜TGӇld.~f4ιrjiS|8;í⦚0`( Ƀ}VtlM!&D\pL޽{3ފ۟cܵ.|}XrsWWO Pg@}P ٕĦMN#MҠHՅkעmmmahhlReW;"{1pq΢~g(iǏty1*zg&kMcX.E-s[5̵۷0 ٳo$oDH|ƾk4y7? ScT(7慦\@џ+NS:wGX ]]]Xj֬Yv\⋹}}L6HF`@ 3X+7x[\+LXE9*:/hw*jS0i8묳Zב!gV;m_ oZ/ -\lPp9 ;q^yX[8SىT**{%o2V ǔO)EQf>LX3﫾+L߿S ÇS˲TBfwaib@\StβK~ZWk^PJi&_ ']p spe7kAp XZRsQ@zýֶ 2Jk׮E__ڠ(JY->VC60Q;AAЖOݬp:Uӆ(.<gb 'aPƘJѽV/bDŽeS~ *-2[(5_j 4M!77໏|97Wӯa];???Sǝ/, 7!f(AGgd2!0(4MtwwcժUa@4Vş- ]L*R~ l". 1N"n]E}Wc&vT5~EQ_?B`!200;w4M'IX$9 IDAT+0VzL6_k>xA ~%=p K6tm4:C߼XnJے=߉0Gq3 n;&̉ (4Z"CISJU{ABkrD Puu]͏72[Mo8Z\դV`#KS/zܓ?zUo?o]MY,\~$jC^J)WcCk׮E?:::B/[RWY~%?69λaʻ.5kpE4MS|VP+0nu=T4A҇al S5aΆ ՅXR"s|oSw} Y{6o,zfhSQY<7x/ŔqXE) @f 2fә^U+kv?7z<+@?0~OӬGz{{Zh0wLd Pޭڷ] ~zZ 5SJRײA|o*[m _}֯5_Sb.C}+ 3Y Sj fVodek)k #C~po?m\6t.Z6%e7n>~+{vQv[iπ ;ۋ5k`pp]]]aϻ$w?qw*JmE= xøOEL-Ya 4^Csˋl|ݏ ] YyM(!0ŚJe) Vj<լ{##WQ ^iii^ \:?F~״k%o+>q-ݍ>lذ,w)=_/45CPāԽb9A[mV\L}s<( UK\cVBms4| 1nQcG ^3-?K4,Daػw/|Ѣo5Z[z`kV&{Cֆ_>,]şM6 Њc3@OT4&ج@a:3.*nc!SV&u0 _Wf /6bClۊX XzuXk'|H@%= *`I@@jϸyp̜T}KEد ҿ*<[*>|}Ja7'~u)JtcnFi6p{JmFws(NHirLC-\說s^&r\UUԦ֢Z)d_}ƋћHa 7{㜗_J]<{Y|Ǯv_Ium!n>7{""##ڒɪ"Ylu7[-l,2h$h$3`00g4{0ҴIIHH)rDY5$MYUY.ˈ̈Zŋ{Fs/_ņ2M:{5!$1VZ? yYB 1vVDZ"( ;~'n1Z' TƩSnx+w򻰤r1Y7^-++[~y;W~$h5qu,%Ϳg Uy|o$o'1`I 7QZ RʮH)['9'({m;eY*E)4~ww$5K'QJ£o&j{V7M|wL;?<wNv-Nj1M4=CM 'W?AZX,l) (A\<e^۸~:h4ЉO|.]Xz,COcO}o'^~˱Qw>)ekЃ֍4PIys&*$HB$D)@ AЅHNoӬ)~!>S4MLMMe ><< nۍT*xO`aaW^۷g1_ǻsʒ/m,+Ww lvHv?o!R‡AX$I!E E @)% !$D h 4ʥRkm?zΜ9Lm744sᡇ2fff2V}NGEדAF___חA ڥ܏㘿d`Z?(PeFD~ t#DYGsTB NbVU(<f&f{:0pI$3V/=%|q]x_ſo5u^~ihsCܵQT8w#2e=0ERJA8 zFsAUg.:"FR7weeo1] B8!DzOғ 1!ت[K0ɞS! /t%Pp ]7n`ffR qvz9![缣osXukY)+8T22 c1&8خ ٷH$*3T*mVޤb]l$&''3`nn׮]z衁 09m?pQu n3S :i-BbB ⢾7s7eYBJ+"gݙ'ku H"VPe!2$/-xJJGy@kirαV ܪ {i&nϧ H,..^xA4Ah/}8ʲ, Ji,:sPfՔe掽jQ/  䣴h{Q]X-=NmB$,@JU{uK@_2++oɛSJ].܀\Эnd:%jǽ_X 3=z7t`pkVO. Y jZBTdY,g镻)۶Td5em 璛f4HFك#s٫+[ ׆x$~>ݸXR 4Mo=&[&Ĕ8"QV2"VZP(֤~K 4q̺ 0%vS{l(G8OqC[έ 9-B RrƘ0w:TOA@ ,K0bTdosc㗃BJC7 hNqGppo˿y˃@h1tVM u=eYbjj'z< 8 ð$EZu{sfbNL0ح#ؽۇ6&m!psf; RZoU6c,daU /t^;pU R I3@} , - DFb]/z7uo6*s0Rcβo]~1Y*B:gKM) ,ˊR.@`5K@ }3 hI$n71(vK8Iog PJeif?M&$ D [(jL$es, "c Ϊs-K T, -X`/dvcuvw;{ݟ\?&lZ9(9?0_w֜i$a0c`UץmܲH ?|A4]E,Zt,-~Y¿ﴯSC;Rޥg_~=捌D<bX(0W mgΜwo+=@K(qdE i2Aq}4t10̔_w˘Z6n{e0# .;=<y|OG_l* Nt]@4Ba D48JtK)#>!io7КLq i_ie:`0"1{yak~E kfz`XGzo7!MB/(RIv\rE+8R* 4ug: _ht:Umى^;MCd;nfۊQ)6r7HoLB!DTŕ+WvհvZ&ljm\o=iߋ>v8h#DQf7t n]6|>v\gu&,3>ğ<[h;JR 8X}oջECZGBM-R$2v%{1aAE]km?g Űv/o5Yi`]iLAQz_)EQWWWo90 4 NչAePّYlЍ%L ݭ[ oG zyf{>}Xٶ(:Yle`n: 48gffdr[7]+Wm\ g$O60"@IcۺM_-tc@ ^?nWp(3ۑf:|yrr4"F--?5ΚsUJBhgK)e۶t]7BC~ y`@˧.!m>V~v6fyBA|rA-@rdfH8c۶u߮Ѯ@Sb(0mUiv@Bi$"`.M\ڂ&+'Ya)~FxN}@`ZH?vL&.!V ?2xavΧNYB4T8ܩ_'qI _18B HQݓɛm vdJ+ۥ۽zo_x-wŅ%JiͶ2<̈vpZQ5MTJՆ?~e ~x0<8 4zTNEDWNi}7K/x@`Q>3A$HxK O,_/_R9MuJweO huB$&QFUwN?sn?_oԀ{wrzNb~LQ3NT5#5BHq?-bQ* !DRZ-.&[Fř(閯ɺwSN K/@i~@/?ne+$K];Jy^P*`.h4y]f,`QzHx{mqA-85!vc1D0Zws;2;bEY$=vb}dk-F41JkFVƞ?G,<q ux@!Lyda2}[js}uثzU;zitl+g@P-TG X1x}ڐRƞ{gހ4BJjf 0f@#9e >|ϔLwݾ.cbs3g̈́aeN?[=Q[(UJiCJOOO:ϔ}yRRZ\+^BFDI7ξÙm*vՄ wz;봿oG=v^iR0_m0Ho}1 t,h5oջ.Bb1t]w߅;T*SJa IDATJjap9SH 75E"a0=>g̳m;7k)ɠεY~7\-]t+Ϝ o_i,\RJAxvvv?-{ʕ+q 6( E7p'~\lubL/M3I:nu/wvݾcoN,7?(}Y@֝?\WԦy^044/\[?uVBAp#uBMbƩƏ#@7`v%P66Ocm1X˲@)PJ!!B0$ H~)Nv#{~7w s'kk#l?}lzA[AKb]EHsGjU{}蜀0 4B^D8 zb1Ιw0Oh6mL@0Jފ+K?HK_ܫ\>{6[7@ tyՖ| ^hI\ )eX,J%O߿)]IN2dՕRoY$F H%c53H)4pwin9syvs.?m@ ͨW> Q%=gap9c^M /H?\JEa)MB7YEC3n'j9JKx[?0@h,+k@hn_ntn}L7~S?:KI9ѭD1rmukJjb+vSs;7H/B]rEA7RZΪ즷Bi IZQu!py2>0{њ>>N nw5\v73^J .?x9i;hlt{Z,Co{U-2 ~'=VJ)BL#(#ocA;]Tn"y6ĥ`>3:`e l'&p'Y~1NdmN]w `x@E Ɔ>5&!944UEu999K)}qjJ |y? F'PP;^Qp4+_W2WzsQ# v N-YwڗW~Z}̈Z}ͰWz! ꯻Buo,[>tΧr]JY `񩩩-H)ՈhZF寂 hb>*X^o=BH&l'ہ~'9,߿.zf?IFX^HImU_I)cFT O'n,@Ữ[UJ{޴~V37د+va#8ӗpv\f>;b_/6;eovS~o4-l⽑p̥ꯣ{?H+wYuK)koZ, PhCJ:zm/FowU@0'^C"k>)fݔ_) _Ӿ~Yr~A~Sϟa)>kO~*WH|'k`U)9oJR*mdI4MRZf۟oeh=Zt Mk/?2f4Ma&{F٩t}/wú^~W5a^ϔ^o߰o_"Q~T KoyU*!d1VRASSS}`KyB*c*ֿ﾿A@yh4ꌱ )revxQ%z@+#H~#UK_s܉@S(m',S?N1|7MG]M,N9H׌G+WuU+o Bzr 7|s`d \rE={6F2X&d?/RH<+_ XNWFV3/liy@ЉBf0<؋oN+ / dgS~|Ϥ:^z%W??ТFu!"de)2!dUJYa fffĉ'bXo0VIqS@6&`k%,BѴA\拋wL%9AbԔ-,;.RmN6r7@  aEǒ(_ 8AXDP@X̶=σ( m,ض61Жh5vCv n- &2jo>޾<'' 曗 `?Zk2nA977! _oY@l֤댱RiNclP @ IՠJzUrTh _gifB B&;;~=Oxo=3~g1̘٧&7߬䣭2 ^ˈyX  }>,-QPK59{Yf@ٳgm)e! QNH)(W=>XxI 9,aϬ=B- hyǁ8m4``:=(믔¿o_v|)e|o[Ӿ^,b*f%sd{cᵧ_]I$ʟ^'7я)7,(6(Lu@䓓!:!ġd(YHY!  sށ%'sԧ? 0u݌ڶ )e[@F܁^{a'o!YL/}{sAӯϯ,Kg|QfK H,UIKE¾Z"i 8 d,rwc>wۧE*qll$.К2*Vۏ@I.ݲ n}0^{5*L2 M߯JzytY)I)mrΣU~`s:q;o⣉,|~_ ,MH#7@x,ğqMV  kߡTJ-d_hz _Nr4p9[JQJ˜ )![}3m'aTC0$.PI~ڗ7E<uc 1}K>\wJ(KvフP8xj)|_|L+l+Losx; lXD !kݑ[#!܎xu4>[)'RSRʇX`8xrB2 %Ҭc8NAA &8]ة^V|=ش ;s+W)O%-ɧO1TxY̑{/խ};V'^faEבM\_m_D? (VݏN~t0#eY֒r:^aB(:99(z7IixpXfuqx=BFsx0&,~my& 󟻁BvلOĿ~_c'N_&.9DבtäZ"d1)\R#5lm/ ϟgAFcHJ9RA^O->?HKFde>Z (FPljWlMmp]m-$"]Tn!P kx's=jʮ?L0G왋o@dqN?vR$GCS)_C6~J !F~ŋ+p9 AeYg {iI.Bxҁ u a|ڗc%9f^E9&0hXSN3sO@^қӲ%_soUne]- iT`%MwJԯ:.O]G.#Ak>UfߝZLYRbR*6r%˲*cJR7l|vQ|!^E`H r aS+SxrI<8(fo2muNYn@~ݩ?P]6;jNB (?G+G;ݚʯK\۱[c/+nBn~Bjj*~yh7oeY#J)J9<*H@N bhW pXx#xj)<lfo;\O)%`]7Ť^(RM"5|0xBi+ǿ,Ѧc3 ⶔrsjީ܁O>$[ZZrRQqSK~%`w.yBr1.3#ˏix,'4@'mG~էX#7q5\}*v3QzcbFwHS{U}~!Vǣ+Wp܁ܡlR4`s~2I9rv嗚g3ҽY\t/b Ҟ>PBqr$N/ƙ3x l[,;|0-gHE5| 7&n汛X]L>D?KriSi~^?=zw!dV5O8 @;p !B&)Sk}6tEZÜKd6ŷ|JQ`©SxpAL&0D0 V0?3gNJ*V+5q I7G $z[w.Cߎ{UJ9_ww8[8.B*B&)S'6~j YPSK`b#E ̸s0nc6c8=8Q>Q+԰:աUװV^CuXbVTD+I"QE"O:XRY%6ѝ賓- s0,RNTJ=8),H|2SJtdA (   .H_8܁'l";BdG8ٶ@a=VzM}d.!!Z7Sإc$|tnG+?teYMAY~@wHL#թ$^S`gZ }z sF!m*ĥuYl`7-y|zT_H nX%眯8Y՚###wrAv-aB4?w:cҶmeYBfQИgXAz]j ׫y1K}Se)Wց8]%=8\wwբV=4c7Rf-!V8awϟ)+ !'cDn_ˢw-&ľn -0PZ/g'{M=H,+֎8m't>BVJ-Xo !S~.`+ضY5BLٕW~1 >+0*@ &HsI  Չ[/QNg!sREJj5!?11߭ܥ@tvvֱ,˳mRpR:q|W'X`! iN8Yo^~sdi !sBy!ĒkQ9׫ܵl;@)RjOMw%Fҵ"{ÑELDB>͉?yԂbEJaYVs:u*ەh mY9/1ƆRcNJ&O/O-|P ͢C! IE픿}rl؟RAo"k*d59'=@Pbz9B8.BF)4XXD)ll hGr$SuI##d2!d]5 xIDATJYchff&nW~ t]EH`jOM. ,9;]̀V#Keۜ3P~)cl`ꚾ-fpp~~޶,˕RӲcNJKN-Z9Tt`3zEaRdGhC]q!DѲr#11؋^?a!< {wE1wgFGF/SJWlrk:?;;]ܳ@K 0ƜMP(8N݂q1BZ͟(gY%$`!yŏвZeB֕RUJ%HVߔ^$-qTRcq)qɵck5gQ,h}@#Fi?_VL(֊Ɩ^',PJ+,˪ !?(;?|?(?pK;wkollJeYeBHXlo<ÇXh7um@{}deu/R˄$685Hʟ-lꞂZyWBt|`Dk?sh6ξ=ЉDG3yt_~K׆ V!+5BȆA\.AĆ_Y}SKВOZ__,rR۶KB2qBx`cQ| zQf$?JQ(Շ '}<6_Ƚ74WJaF}Zkb Ϟ=kJ%kccPpG3 b'~psl% EA,, _^LDHG܀D^h>UoG,_ZUuݗt@*y`jj<Ϯn:ʰ$(B !qRiEs ̞ wcaAYD[zM\}Ȳ$QQ|V;[sH~Ri/.G[L p]9/SJ0&89<z|Y:_vb!4+^Qme/RʪeY0 R`hh(L_W."T)HϭqCCC<3ror=Nө)ysRTQ)UbR A15R/ןnOFn VVv l{h諷&8.Ğ:IM ۥfJZ)T)5Ni90♙; G ACP*Fa0\BH@rRZRBJaac͡gC7<9Ѥ`U[~hfg- EK z)]fꦲ9Wis̙` 'rНjlI)USJ(U)eMQwqS)s#"R#أ=`X,Z۶mO)URc%)eY)5D0D)N8,4tDJ/9 4SЬB- g2w\T~7ڪY^L`0U4p"g Exݍ9T@RZR)5!DR 4 \ 9QP&ϟ/^'t !HBb;>[8`rQvX(JwEQEt`5[6W^"o(+"^SJCOSem۱qEPz%;ٳtxx5MEs ж,+%8BH)BH"t8G)eBlEaJ)M׎$ҕT@%!4bTҐI@&;BTJqBPJń8URI)cO)Rc,N-{qH۶ͣ(Z&4?:R#8 1\=xHϝ;G qr̢(bQYZm3ι9cfY[JiBlJ޶Rʢ2SJQJ)@R$6-"()$BR BWJqJi,)R*[ !8cLeYs0d o۶RG\n" "Language-Team: Arabic (http://www.transifex.com/projects/p/kapow/language/" "ar/)\n" "Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " "&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" #: ../kapow.appdata.xml.in:6 ../kapow.desktop.in:3 msgid "Kapow Punch Clock" msgstr "" #: ../kapow.appdata.xml.in:7 ../kapow.desktop.in:5 msgid "Keep track of time spent on projects" msgstr "" #: ../kapow.appdata.xml.in:10 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "" #: ../kapow.desktop.in:4 msgid "Punch Clock" msgstr "" gottcode-kapow-350ecea/icons/po/bg.po000066400000000000000000000026371514263554100176270ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2014-11-14 20:10+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: Bulgarian (http://www.transifex.com/projects/p/kapow/language/" "bg/)\n" "Language: bg\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" #: ../kapow.appdata.xml.in:6 ../kapow.desktop.in:3 msgid "Kapow Punch Clock" msgstr "" #: ../kapow.appdata.xml.in:7 ../kapow.desktop.in:5 msgid "Keep track of time spent on projects" msgstr "" #: ../kapow.appdata.xml.in:10 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "" #: ../kapow.desktop.in:4 msgid "Punch Clock" msgstr "" gottcode-kapow-350ecea/icons/po/cs.po000066400000000000000000000044741514263554100176450ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Pavel Borecki , 2018 # fri, 2014 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2018-08-03 07:27+0000\n" "Last-Translator: Pavel Borecki \n" "Language-Team: Czech (http://www.transifex.com/gottcode/kapow/language/cs/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: cs\n" "Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow – evidence odpracovaného času" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Udržujte si přehled o času stráveném nad projekty" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow je aplikace pro evidenci odpracovaného času navržená pro snadné udržování si přehledu o hodinách, ať už strávených nad jedním nebo více projekty. Jednoduše si kliknutím na příslušné tlačítko zaznamenejte zahájení a přerušení/skončení práce. Pokud se zmýlíte, můžete se vrátit a kterýkoli ze záznamů upravit dvojklikem na příslušné sezení. Kapow také umožňuje snadné udržování přehledu o hodinách, odpracovaných od minulého zúčtování s klientem a to praktickou zaškrtávací kolonkou „Účtováno“. Součty budou odpovídat vaší práci od posledního zúčtovaného sezení." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Evidence odpracovaného času" gottcode-kapow-350ecea/icons/po/da.po000066400000000000000000000041561514263554100176210ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Morten Juhl-Johansen Zölde-Fejér , 2015 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2017-09-21 14:01+0000\n" "Last-Translator: Morten Juhl-Johansen Zölde-Fejér \n" "Language-Team: Danish (http://www.transifex.com/gottcode/kapow/language/da/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: da\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow stopur" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Hold styr på, hvor meget tid der bruges på projekter" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow er et tidstagningsprogram beregnet til at holde styr på dine timer, om du så arbejder på et enkelt projekt eller mange. Check ind og ud med start/stop-knappen. Laver du en fejl i din registrering, kan du gå tilbage og redigere den ved at dobbeltklikke på den. Kapow gør det også nemt at holde styr på, hvor mange timer der er kommet til siden du sidst fakturerede en kunde med en praktisk afkrydsningsboks med \"faktureret\" - så vil den totale tid afspejle den tid, der er gået siden den seneste faktura er udarbejdet." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Stopur" gottcode-kapow-350ecea/icons/po/de.po000066400000000000000000000041711514263554100176220ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Wasilis Mandratzis-Walz, 2015 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2017-09-21 14:01+0000\n" "Last-Translator: Wasilis Mandratzis-Walz\n" "Language-Team: German (http://www.transifex.com/gottcode/kapow/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow Zeiterfassung" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Verfolgen Sie Ihre Arbeitszeiten an Projekten" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow ist eine Zeiterfassungssoftware und wurde entwickelt, um leichter den Überblick über Ihre Stunden, die Sie an einem Projekt arbeiten zu behalten. Einfach die Stempeluhr beginnen oder stoppen mit der Start/Stop-Taste. Wenn Sie einen Fehler in der Stunde machen, können Sie zurückgehen und bearbeiten einen der Einträge mit einem Doppelklick auf die Sitzung. Mit Kapow können Sie auch leicht den Überblick über die Stunden seit der letzten Rechnung eines Kunden durch die Bereitstellung eines hilfreichen \"Billed\" aktivieren - die Summe wird Ihre Arbeit nach der letzten Rechnung der Sitzung an berechnen." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Zeiterfassung" gottcode-kapow-350ecea/icons/po/description.pot000066400000000000000000000025331514263554100217410ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the Kapow package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../kapow.appdata.xml.in:6 ../kapow.desktop.in:3 msgid "Kapow Punch Clock" msgstr "" #: ../kapow.appdata.xml.in:7 ../kapow.desktop.in:5 msgid "Keep track of time spent on projects" msgstr "" #: ../kapow.appdata.xml.in:10 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "" #: ../kapow.desktop.in:4 msgid "Punch Clock" msgstr "" gottcode-kapow-350ecea/icons/po/el.po000066400000000000000000000053341514263554100176340ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # geogeo.gr , 2016 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2017-09-23 20:29+0000\n" "Last-Translator: geogeo.gr \n" "Language-Team: Greek (http://www.transifex.com/gottcode/kapow/language/el/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: el\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow Punch Clock" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Παρακολουθήστε το χρόνο που δαπανάτε σε έργα" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Το Kapow είναι ένα πρόγραμμα χρονομέτρου εργασίας, σχεδιασμένο για εύκολη παρακολούθηση των ωρών, όποτε εργάζεστε σε ένα ή περισσότερα έργα. Απλός έλεγχος του ρολογιού με το πάτημα ενός κουμπιού Έναρξης/Διακοπής. Εάν κάνετε κάποιο λάθος κατά τις ώρες σας, μπορείτε να επιστρέψετε πίσω και να επεξεργαστείτε οποιαδήποτε από τις καταγραφές, κάνοντας διπλό κλικ στη σχετική σύνοδο. Το Kapow σας δίνει επίσης τη δυνατότητα να παρακολουθείτε εύκολα τις ώρες από την τελευταία σας χρέωση σε έναν πελάτη, παρέχοντας ένα χρήσιμο πλαίσιο ελέγχου \"Χρέωσης\", παρουσιάζοντας έτσι τα συνολικά ποσά που αντιστοιχούν στην εργασίας σας μετά την τελευταία χρέωση." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Ρολόι Punch" gottcode-kapow-350ecea/icons/po/es.po000066400000000000000000000030151514263554100176350ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2018-05-28 17:55+0000\n" "Last-Translator: Graeme Gott \n" "Language-Team: Spanish (http://www.transifex.com/gottcode/kapow/language/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Reloj de control Kapow" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Realice un seguimiento del tiempo que invierte en proyectos" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "" #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Reloj de control" gottcode-kapow-350ecea/icons/po/et.po000066400000000000000000000040201514263554100176330ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Priit Jõerüüt , 2024 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2014-11-14 20:10+0000\n" "Last-Translator: Priit Jõerüüt , 2024\n" "Language-Team: Estonian (http://app.transifex.com/gottcode/kapow/language/et/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: et\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow - sinu tööaja arvestus" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Pea arvet erinevatele projektidele kulutatud aja üle" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow on tööaja arvestuse programm, mis on mõeldud väga lihtsaks töötundide arvestamiseks ühe või enama projekti kontekstis. Lihtsalt käivita ja peata taimer nii, nagu vaja on. Kui tekkis mõni viga, siis klõpsates antud sessiooni salvestatud andmetele saad neid kergesti muuta. Lisaks on sul mugav pidada arvet kliendile esitatud arvete üle - andmetes on vastav märkekast ning siis kõik summad kajastavad eelmisest arvest kulunud aega." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Tööaja arvestus" gottcode-kapow-350ecea/icons/po/fr.po000066400000000000000000000042171514263554100176420ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Guillaume Gay , 2014 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2017-09-23 20:29+0000\n" "Last-Translator: Guillaume Gay \n" "Language-Team: French (http://www.transifex.com/gottcode/kapow/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Pointeuse Kapow" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Conservez une trace du temps passé sur vos projets" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow est une pointeuse horaire conçue pour conserver facilement une trace de votre temps passé à travailler sur un ou sur plusieurs projets. Pointez et dépointez simplement à l'aide du bouton Démarrer/Arrêter. Si vous vous êtes trompé(e) dans vos heures, vous pouvez revenir dessus et éditer l'une des entrées en double-cliquant sur la session en question. Kapow vous permet aussi de conserver une trace des heures que vous devrez au final facturer au client, en proposant une case « Facturé » bien pratique. Les totaux refléteront votre travail après la dernière session facturée." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Pointeuse horaire" gottcode-kapow-350ecea/icons/po/it.po000066400000000000000000000041321514263554100176430ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Patrizio Bellan , 2017 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2017-09-21 14:01+0000\n" "Last-Translator: Patrizio Bellan \n" "Language-Team: Italian (http://www.transifex.com/gottcode/kapow/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow, il timbra cartellino" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Tieni traccia del tempo speso nel progetto" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow è un programma \"timbra cartellino\", dal design semplice, creata per aiutarti a tener traccia delle ore di lavoro su uno o molti progetti. E' un semplice orologio di inizio e fine grazie ad un pulsante di Start e Stop. Se commetti un errore quando registri le tue ore, puoi tranquillamente editare i dati cliccando due volte il nome della sessione. Kapow ti aiuta a tenera traccia delle ore fatturate ad un cliente, grazie all'utilissima check box \"Fatturato\" che ti mostra il tuo ammontare, partendo dall'ultima fatturazione." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Timbra Cartellino" gottcode-kapow-350ecea/icons/po/lt.po000066400000000000000000000040661514263554100176540ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Moo, 2014,2016 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2017-09-21 14:01+0000\n" "Last-Translator: Moo\n" "Language-Team: Lithuanian (http://www.transifex.com/gottcode/kapow/language/lt/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: lt\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow kontrolinis laikrodis" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Sekite projektams išleistą laiką" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow yra kontrolinio laikrodžio programa, skirta sekti valandas, nesvarbu, ar dirbama su vienu, ar su daugeliu projektų. Paprastai valdykite laiką mygtuku Pradėti/Stabdyti. Jei savo valandose suklydote, galite grįžti ir, spustelėję du kartus, keisti įrašus. Taip pat Kapow, suteikdama naudingą žymimąjį langelį \"Apmokestinta\", leidžia lengvai sekti valandas nuo to laiko, kuomet paskutinį kartą apmokestinote savo klientą--sumos atspindės jūsų darbą nuo paskutinės apmokestintos sesijos." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Kontrolinis laikrodis" gottcode-kapow-350ecea/icons/po/nl.po000066400000000000000000000041771514263554100176510ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Heimen Stoffels , 2021 # Heimen Stoffels , 2017 # RobertBorst , 2016 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2021-06-16 17:29+0000\n" "Last-Translator: Heimen Stoffels \n" "Language-Team: Dutch (http://www.transifex.com/gottcode/kapow/language/nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow-prikklok" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Houd de tijd bij die u spendeert aan projecten" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow is een prikklokprogramma, ontworpen om gemakkelijk uw uren bij te kunnen houden, of u nu werkt aan één of aan meerdere projecten. Klok in en uit met de Start/Stop-knop. Als u een fout maakt, dan kunt u teruggaan en elke invoer bewerken door te dubbelklikken op de bijbehorende sessie. Kapow laat u tevens gemakkelijk bijhouden wanneer u voor het laatst een cliënt hebt gefactureerd middels het selectievakje ‘Gefactureerd’. Het totaal geeft uw werkuren aan sinds de laatst gefactureerde sessie." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Prikklok" gottcode-kapow-350ecea/icons/po/no.po000066400000000000000000000037171514263554100176530ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Lasse Berge , 2016 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2018-05-28 17:56+0000\n" "Last-Translator: Graeme Gott \n" "Language-Team: Norwegian (http://www.transifex.com/gottcode/kapow/language/no/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: no\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow Stemplingsur" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Ha kontroll over tidsforbruk på prosjekter" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow er et elektronisk stemplingsur som holder kontroll på ditt tidsforbruk, enten du jobber på ett eller flere prosjekt. Du stempler bare inn og ut med Start/Stopp knappen. Gjør du en feil, kan du enkelt rette denne ved å dobbeltklikke på oppføringen du vil endre. Kapow gir deg oversikt på tidsforbruk siden siste faktura, ved en enkel avkrysning for fakturert tid, - totalen vil gjenspeile tidsforbruk siden forrige faktura." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Stemplingsur" gottcode-kapow-350ecea/icons/po/pl.po000066400000000000000000000043151514263554100176450ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # M T , 2015 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2017-09-21 14:01+0000\n" "Last-Translator: M T \n" "Language-Team: Polish (http://www.transifex.com/gottcode/kapow/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pl\n" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Rejestracja czasu pracy Kapow" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Śledź twój czas poświęcony na projekty" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow to program rejestracji czasu pracy przeznaczony do łatwego śledzenia swoich godzin, gdy pracujesz nad jednym lub wielu projektach. Po prostu zastartuj/zatrzymaj zegar przyciskiem Start/Stop. Jeśli popełnisz błąd w zapisie swoich godzin, możesz cofnąć i zmienić jedną z pozycji, klikając dwukrotnie na sesję w pytaniu. Kapow pozwala także łatwo śledzić godziny od ostatniego rozliczania z klientem, poprzez dostarczenie pola pomocniczego \"rozliczone\" wyboru--sumy będą rozliczane twoją pracę po ostatniej sesji." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Rejestracja czasu pracy" gottcode-kapow-350ecea/icons/po/pt.po000066400000000000000000000043341514263554100176560ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Nuno Mendonça , 2022 # Rui , 2018 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2014-11-14 20:10+0000\n" "Last-Translator: Nuno Mendonça , 2022\n" "Language-Team: Portuguese (Portugal) (http://www.transifex.com/gottcode/kapow/language/pt_PT/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pt\n" "Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow Punch Clock" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Controle o tempo gasto em projectos" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow é um programa com as funcionalidades de um relógio de ponto concebido para ser fácil de rastrear as horas, quer esteja a trabalhar num projecto ou vários. Simplesmente registe as \"entradas\" e \"saídas\" com o botão Iniciar/Parar. Se cometer um erro nas horas, pode voltar atrás e editar qualquer uma das entradas com um clique duplo na sessão em questão. O Kapow também permite rastrear facilmente as horas utilizadas após as últimas facturadas a um cliente, através da opção \"Facturado\" - os totais irão refletir as horas utilizadas após a última sessão faċturada." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Relógio de Ponto" gottcode-kapow-350ecea/icons/po/pt_BR.po000066400000000000000000000031071514263554100202360ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Enrico Nicoletto , 2015 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2017-09-21 14:01+0000\n" "Last-Translator: Enrico Nicoletto \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/gottcode/kapow/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Relógio de ponto Kapow" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Mantenha o registro do tempo gasto em projetos" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "" #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Relógio de ponto" gottcode-kapow-350ecea/icons/po/ro.po000066400000000000000000000041751514263554100176560ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Oprea Nicolae , 2015 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2017-09-23 20:29+0000\n" "Last-Translator: Oprea Nicolae \n" "Language-Team: Romanian (http://www.transifex.com/gottcode/kapow/language/ro/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ro\n" "Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow Punch Clock" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Ţineţi evidenţa timpului petrecut pe proiecte" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow este un program de ceas stimul conceput pentru a ţine evidenţa orelor dvs., indiferent dacă lucraţi pe un proiect sau mai multe. Pur şi simplu cronometraţi cu butonul Start/Stop. Dacă faceţi o greşeală în orele dvs., vă puteţi întoarce şi edita oricare dintre intrări dînd dublu-clic pe sesiunea în cauză. Kapow, de asemenea, vă permite să păstraţi cu uşurinţă evidenţa orelor de cînd aţi facturat în trecut un client, bifînd căsuţa ajutătoare \"Taxat\" - totalurile vor reflecta munca, după ultima sesiune facturată." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Punch Clock" gottcode-kapow-350ecea/icons/po/ru.po000066400000000000000000000054061514263554100176620ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Артём Давыдов , 2017 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2017-09-21 14:01+0000\n" "Last-Translator: Артём Давыдов \n" "Language-Team: Russian (Russia) (http://www.transifex.com/gottcode/kapow/language/ru_RU/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow Punch Clock" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Следите за временем, затраченным на проекты" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow - это програма по учёту времени разработанная для простого отслеживания Ваших часов, как-бы Вы не работали над одним или несколькими проектами. Просто используйте часы с помощью кнопок Старт/Стоп. Если Вы допустите ошибку в Ваших замерах времени, Вы можете вернуться назад и изменить любую запись с помощью двойного нажатия на рассматриваемую сессию. Kapow также может легко отслеживать время с момента последнего выставления счёта клиенту, предоставляя полезный флажок «Счета»--итоговые суммы будут отражать Вашу работу после последнего выставленного счёта." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Учёт времени" gottcode-kapow-350ecea/icons/po/sv.po000066400000000000000000000042101514263554100176540ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # Jonas Bohdén , 2017 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2017-10-27 13:07+0000\n" "Last-Translator: Jonas Bohdén \n" "Language-Team: Swedish (Sweden) (http://www.transifex.com/gottcode/kapow/language/sv_SE/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: sv\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow Stämpelklocka" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Håll koll på tiden som du spenderar på projekt" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow är ett stämpelklocksprogram som är enkelt utformat för att hålla koll på dina timmar, oavsett om du arbetar på ett eller flera projekt. Stämpla helt enkelt in och ut med Start/Stopp-knappen. Om du gör ett misstag i dina timmar, kan du gå tillbaka och redigera någon av posterna genom att dubbelklicka på den aktuella sessionen. Kapow låter dig även enkelt hålla koll på timmarna sedan du senast fakturerade en kund, genom att tillhandahålla en användbar \"Fakturerat\"-kryssruta. Summan kommer att återspegla ditt arbete efter den senast fakturerade sessionen." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Stämpelklocka" gottcode-kapow-350ecea/icons/po/tr.po000066400000000000000000000027631514263554100176640ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2018-05-28 17:56+0000\n" "Last-Translator: Graeme Gott \n" "Language-Team: Turkish (http://www.transifex.com/gottcode/kapow/language/tr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: tr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow Kokteyl Saat" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Projeler için harcanan zamanı takip edin" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "" #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "Kokteyl Saat" gottcode-kapow-350ecea/icons/po/uk.po000066400000000000000000000054221514263554100176510ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Graeme Gott # This file is distributed under the same license as the PACKAGE package. # # Translators: # dsafsadf , 2021 # zubr139, 2021 msgid "" msgstr "" "Project-Id-Version: Kapow\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-14 20:20+0000\n" "PO-Revision-Date: 2014-11-14 20:10+0000\n" "Last-Translator: zubr139, 2021\n" "Language-Team: Ukrainian (http://www.transifex.com/gottcode/kapow/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: uk\n" "Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" #: ../kapow.appdata.xml.in.h:1 ../kapow.desktop.in.h:1 msgid "Kapow Punch Clock" msgstr "Kapow Punch Clock" #: ../kapow.appdata.xml.in.h:2 ../kapow.desktop.in.h:3 msgid "Keep track of time spent on projects" msgstr "Слідкуйте за часом, витраченим на проекти" #: ../kapow.appdata.xml.in.h:3 msgid "" "Kapow is a punch clock program designed to easily keep track of your hours, " "whether you're working on one project or many. Simply clock in and out with " "the Start/Stop button. If you make a mistake in your hours, you can go back " "and edit any of the entries by double-clicking on the session in question. " "Kapow also allows you to easily keep track of the hours since you last " "billed a client, by providing a helpful \"Billed\" check box--the totals " "will reflect your work after the last billed session." msgstr "Kapow — це програма, яка дозволяє легко відстежувати ваші години роботи, незалежно від того, чи працюєте ви над одним проектом чи кількома. Просто ввімкніть і вийміть годинник за допомогою кнопки Пуск/Стоп. Якщо ви зробили помилку в годиннику, ви можете повернутися назад і відредагувати будь-який із записів, двічі клацнувши відповідний сеанс. Kapow також дозволяє легко відстежувати години з моменту останнього виставлення рахунку клієнту, встановлюючи корисний прапорець «Оплачено» — підсумки відображатимуть вашу роботу після останнього сеансу, що виставлявся." #: ../kapow.desktop.in.h:2 msgid "Punch Clock" msgstr "" gottcode-kapow-350ecea/mac/000077500000000000000000000000001514263554100156765ustar00rootroot00000000000000gottcode-kapow-350ecea/mac/Info.plist.in000066400000000000000000000020441514263554100202530ustar00rootroot00000000000000 CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleDevelopmentRegion en CFBundleName Kapow CFBundleIdentifier org.gottcode.Kapow CFBundleIconFile kapow.icns CFBundleExecutable ${MACOSX_BUNDLE_EXECUTABLE_NAME} CFBundleVersion ${PROJECT_VERSION} CFBundleShortVersionString ${PROJECT_VERSION} NSHumanReadableCopyright © ${project_copyright} LSMinimumSystemVersion ${CMAKE_OSX_DEPLOYMENT_TARGET} NSPrincipalClass NSApplication NSSupportsAutomaticGraphicsSwitching gottcode-kapow-350ecea/mac/background.tiff000066400000000000000000004457301514263554100207040ustar00rootroot00000000000000MM*@4& !p|JC3PyZ?$r4zYdRcәD5/cT)a&Nf]3AQ 2ENI*5ֹ_XlV;$A9ee  v¬4&}\RˎႨKٱW;+xW\>vfNOߴֽW]yl\؝MVo%RJƢ59ͮ<=[Sq+cϤ9W{Xk -j>OֹO3w+oMD 5 K2/MA:ڳ,-+-T' ?pi 5! Ep%3TπJOL&oJ(rRlȲڶJo-)"'OC+K0,?M3q|B@XNMb20[>@3aΏC4B4\m/LHRoWJQL $.yZux|oC׼IhZ4=쾓^qPW$}צN,77PerL5e|ȳV[io,JkUD\JoxJ94y q%r٬GK lb3.q/Mn%&riZnqNxQlCZ}wv7^O5Fl9Ĺ5Ăs['fCc9+˶/7c'ޱtv}n^v--E.d 4et0JmMuj#N.XAыȅ y|PGU1Vp,V^}?T8qI>US[G(ΒqgN{P?_֓+V+QG (er|F0]4y>Mnj`:T8"ҦYSaRL#rm~GMǎ :Vu]MBdwr#ҁՙT:ZIm,UR(d*/:q-r֐RK Z=#6NȆn RJcb͌RB6# E6c@fpJASt{6kXmjDKh%;*]ԉv>KU.Er_ܩ+5jKxvʛ] .OYwM5ެqz^ۆf5ewjWg(E}T,Ƌalk+]- ]aK]m?"8:_ZQB6X_if*ƙd' |y68ѯȶxlN"rƦxOV&SoVLۗS:o8FJPs rF8Qq َvMW+dz" hl}diޑwH']@iU, SSRo G޺-']{#sٳXfSڥh/ﶥA(?傂ab6%ҘAǦ/?,~Fryr(Yq+Ҕ@`"JxJսb8">eŽ;7ٱ8ocl۳3BLnvj/Ewm+ 6o2=F܃ oj&PR &Y_PjWyޙD7Չ*=DpcՠHa(s-וȍ6>~Qn^9r<'3&Gy_@3ub{˨B[8>:KzX~|_HmWʼrO{| oP5HϫhZOTx.pm뺧ƤBE@ f,\(Z;LȰp On,*H4πm0kjVLjo(o*9Zwn6o (20z-S kX缩/T1,ގ# 0Кn KfJy J'lЭХ)*BtvZiE̅pL0Nvܦ/#No&f|?[ ? |ԯ. KN>Q -|= /AP4hRC#%,gu1nmO r!i_ bM>qSOvnq'gc t:)qap 1n!JSR& 1$"2@ǯۏTݍPb2b7/?B&ʙKW(G/e(oQ=' f*$.)+) m++$q,A.mo-R<$/ko52a+lB3 226cА18Iqh1S:H)]:n 0 rqm'ΪnpBď,'q6G-I6;1 $S`[  ﯴ2^ 7(K@V3Qp'/VOF.%DE q+ RXM\Oo>4y>j7- >23flHW5"@094-%@)@W$A8Nq%T "5CyD|ֳ1] 9ӿFQFTRoq<=RwP ȵ40NtɕSsLAs4pYмS}8rF BLb-GKNNPf~SruM3TWr{23;2jqFH^ҥRUh8S4jeD#,{TtQ]Vc82tTѸrQ/W4>BJoTGtKNgEFu')W(\ Yw(2 [a&QMԉvh;\ےR]7+u*5E?ϹB @ @`LGUT//-q/T4sWO lWv 6%OW[Yg ;3 QNZ9 RZ ~\sTvbDŔXTSQ#UII4B2hRS2LxQ_ceVt$]56c6ZvGEv:#(QcT|4 6NIZrT~3)s׎#*%Z"y(PoTTJtPE-lOUUml.K488e8 7jKj+OX`/5'Vc?cKw÷/ōڛzO{׽_KZØŵ=1[`UsQsKռjP Z34^}P^vA>ė*ׂ{<-q:9s}H[[žվ\ (_^j}a~\/V%tY>>DûtvtAxooY^M+or+zќu5Ags] 9y4_?!_ouSX1(<_+I<+?6~ C}f(I?#>={L  PXT" ?D(6+B9 :Gɤ-$|K2H1(bM8S V7[u*j|SUjhB[ª5{._٬_Z+mnuTֳ ,Wmcnu5,dar9< Uf/ 5躊W.ܤZT_aӧm@`ȧ c4C'[Mֲ7Ӯ'Fm?w>Cp8s˲+F+аK0+ )kC4>o164,  $\F2os).Ȕ/ bHּۤn(9 \8{y)ԥ.od;sa$I{%lcбdQ #0BStp2ДWAF$F,kr5k6,rum+ a# [JW06\Hc^HrĞHo|e1o[63< t<2,AMNRtO1< SSSFUEStZXakRR[œ5c'֙&K\yD&XWL!X|ؒ5(R涍aNLƇkY\uןf-~a+WH-݄kf7R PNU[_V&dT>Q?B S[am"wT d5Lreѕhz\yKs ƕjW&Zѣ^:fyqaXړlؽ]r}ݞW:[nU0rDPҙb9Utmd\O-LA=!&Klp պ@xL d[1=vQPRBB}a^;OgLݬζ5tn9wC@{z)-*dm}y~WSxm}=fz4_Fe2.uq͖WY{ ZiUOf뙭{w\zvNuʯk`:8cOj5OJFgfPZ^sx5һ~b> Y뼯)SG)vjCgk?T`vPV<񩜒5[2~F'51+- rkׯ.0u8$QF* K?J ;̩iྡྷ־#r@"i>k0& 9#C0ᬤ2[43^ pJ5;>C܀G̱dzOEE ʬ8#k.1RB ˙ÄYA NNč(F$`NيjvC{?$C<1Iƌ>Ϝσ<G 5;CěL Ą@^1ʔBlO1:ckwٴ4B/DKS< | K,7R7@r6θ~QЁNR%",!BDrAqãE"ts63VQeRV#4=hP޻k>g<]G+DZ$ N8a0HMWYUP|| `-pwhtdzxa a6S6S6NUaU>^R@~) ZT95]VlZ;'ٺOelMa lS[C5\'t ./UMe|B?GcKCK}EV>מ84CȴKwMRSNh N؜˱μ ܆z`xH*1*jXlc(@e@0h6X]X6YY} M!iZnc3Yo %f3q;Ƥ--^Lj+ھeL^SaM$~q4\-M?37[FP]9e4F<ŖFYa5m=SR̒V-jN%޴Bj j~knIݠF,VS6H2f˝\VأyXKU O_ |ʽyMuԄ}pKN}chRU=S NoU' XJX|\yyp+(= qjcVi`mmmfVWav]Yu &<Iu^S-gb̦%ꍣjݪּIjG3͜Z]o(hoNE4g^w7xg~8#&6A.{Wf6)~N}vN~#VFItVM ɇQ0w6!dgpi`8Tma!$݅&6$ydfcfBlfu-F\gnbVd^vAF+6En]s[Q6mKT_F_S[2=CtW#l1줎pT UL+p}^XՎ{zw;r2`t eY0OO>S] ,尥7# ,jrfRr),fڠfe2ew-2զfo,mha+Suegvp$Wd$.sH[m@g#r} Dy_O} tN1 MmS6Rhω{ܖIܝXptnh6N/hg/&XqO_%p%ՕVmr_=&E!5r)]ǫ^<5.j<0+ļe؃{w8gCoNs_80B|F AbP/c(.7dx6Ge1IBY2g"$s({?~S_{{>_W|鏪[Ҭ;-& 5iR]{TgtrKI^7-u9@P4 6X `@ h-&G@  $=sзqkD7<eˁn8|{nnOv;Gz= gmw~nw7w}>'s}O@-FHs$RK'6p w $  A)t) APPCviG )UEqRBkzGڹR   *Ҽ,L)ny\ @+8L F BS`팄 #?oc?89tu HO}Q/AQ]9@.LSUHO+Cԭ ] E8,@<_CtFHqՃWѝ0l[cG,UaCV|kgE%p#[7dױ|Bh5ʕ?- 2i9# #>+ɜc' j32L43tN;Fd46WmNՎ;H>O啥RO]%K[>SN9ՃW< 9kFW0mnzSWu[IZ{b]VkX m"Wqm_7tXqE[zQr[lQ[vm_ȫ<.aʡxg%N]v'!`j3l2 S{Bc#Ny+b"ޙ;ZjtE/SWjM"iNnCi]cShnJz~V{T}Cy]r0_+Hг&1"p׃xo y"[CZ 8 DLs7K9A>0yotC?Ʋ`*vIri@(d&Fx=羨+Cjqe=&\WqXQkgr1GC2}/ūaKy/썛yC(M@!ЄoEGob vlqx_\SRJIac> wBrSdLaLjbvʙ@bgؙbDH`D"-+YzQgeOwXt_}ɨOʥ2|OZjwO=艻r@D'%D 1$lmbi$d{wl!8FM%YԺBB#I%l$r)bxW&=1#) 2Una2LHMWfSy;DUg1A@OF*'B:oDiCTLZ54׷`}j.Xd಴1YFE2'ڟJHE(i0bZ8 -$R:SQAGsҲS))*`:AӥmH@r JN/w:dZ]Ɛp e& I8ha$As9Χlah4P D5rc)"gMxoWA{>OFf]&Z nZ=6L-hK;kb;ˊBPBRjNJu yY_,0a;81W6.Lc;V9Mug5:|7GCzO7_f|zBgmZ>0Mps;l?.[[K%ӺZHFiTDlkJ's$8 d 'k-<~B+.J̎;GHV ,흴 cPr e13 %6;LˬIJv@ԉ5h?P-Gj JPp -P ' n' Xpڧئ0儓lEKyoO.~+r&ؐbR.n `qYAhLvȃ>dwuSiـl?ًu \ 'AY%zB58l/R9 Img?}SlL#)3VI%bg90#U'DsnϠ Z$33N)Iq!2-4#^ՀɢJ  a2agI341@5s#X6%j&5:O475vn62%[(bSh6sssaO/S~ނuHkhİ8oEW/8+rӧ :$.gJ7˖-;&.L=E-> X9R*¤8 f jHI LM͇8vOM}e[?ə{k{0NZ{ kyUz迷4!5ɧmأ$7; 4!{34pԷ7w~*[ͽ~d#4A.-b.,ː JOØ7dK -Va_\./ʚh$2|KLcC>wNNxI#8u4 1Ƿ};lGtwtjsGC9{m nKʠ| |7XZh"]͝ԍ3GUtwoyd{ʨ7= ď7yI)h)lVnm$ ÜAAAw\vGhM8O)×x {myC}|sq~MSE2R&|C6 ڂFײ*xe]+ӍκqP=ΕGj}b"Q];+-j|,+A0 "6!~2vլMi[$6*`ƙ~"k64ҷ1{y|wuQ<;[mA~nyt?U!1}@ ;9:ͅ{Ȩ׭|$rt},;dtH\ $IIr*²t`rj P0 @ؘ@`( d2)0#J\DRg9Nw6N(4 މCz5"B4Y^KU'Tba֪fV%D_m+Ճyo~/QaPX<. CЈdRDQ.!y&-&d\z1'#2I [4LD+!e3Z;"N1*4J%ӊ}:VVh*VfE/M `Y&u h?֋~|]{= ,` q,< bx 7h1z9Rmlhխl5}~gmWw;M+{kimvlKC ox:{o^|}GvT\jT5I2Ī&Ikbl J|@֚A**^ZbjuCk\/A:EMF)Ro3*QBڢK^,I |" cL̩*JBJKP:=s;?3t!̳{oL|OjO4ͳOTC4&Nl8Q+EI)0D3G1Tn@`U _m]mgWWռ5qSa,; BVLb؊XrZսu>U aO73.4~#I2(rԾű=-M+@ 7\mkm3җ%%?3:5QϻvJ`=;JL8Xv;S=X[2%qEA\cT cB0 X+P[jÐښUSWk9guMTGٙDrHts N42I!0MraWˇaef3'rx Ls#Ha/v%>7SQm91f纺>/Yj6Uz^S[1>=eo1l%k[irκn "/—izu'0͙{TuvB,vN59wJN1uB \Y.@p}YTb}54a,q0arciaXvLCJB a+hJ0!pZ1W{Fj n)bLl16/ۙ5HrC3,pG͝4-P:-LP)he \}:@o2rNAduLB(Q+-*@N> Љ*ĆЕUh=wޫW1acE8h{oY1:ie)霵SU-p2NHI)B>´(|鑩+%j"{ΘKs$'lе`bftCD~\Qi,&*T'&nȇNZKPIW&sM g\UEG\]H+MI]=5c`"\h| KUE,yZSJa0e` {'S-DUe=h Uu]#u̢}։;V#{dJ0wGmHJ+g)|T!!rK)8j:_MD%kWL#e*"c x# ՌboWJUioe\1FW<pmnv~: [ aag2\(S BB]Z0۸2ڱSH&.ǃ[3¼4`Y:ZYg5Lǧ#Q婑idZkDčͼVN. [3{g Km#hYaiX]7Z3u|9r`< l?Z'%pgܮz+ngsh/mR ,~ʚ.ϰ֍dn,iohGIxD+䏘J-LːnZُ Obe ݮ+} P+QDϦwYi? ih֮ <.όN^r0glXM? 4fM@𐺩20:POeBڬe8Z{ ; 20Ȏ OY6̣.)p $(N&F,Q ̰nl,̌Eа)BQJ/0qͿO 1BhqZڍP0 YOp둄hHqrC p,{#L+F|̷%pi//˭ ҆| rPo[*)\r : !n"N*MBC#mI:pǑ%-ϙ$J@fܙ2j¸lrq+vq+Q_,R{0 O*qTP1]++Q!C,%Rξ$N7>˲KRoEm ӗpHr2%m3O s<,M"S&+O,FBR 3/ 2*2ҥ QA5SgK+Z6S6o77I7G7=.ӆQ$!B2i8P/Bw![n""/0eE,G1S,,oc2LWR(T88)Ow.#QwM$˳1#s!< TPj_FP#= u$(/ËTsVU=356h_TTS[Jb2(nyUK}L1VBTtN4#/`758RO+aNc-ZK';7[S αؓI{=Ua r)HR lP?p*_A?Q_p5t@uhUm77CM43bP6#aObLDYjrb?;6G&Rseq%?+5_9 HuREIC\f153G7 ڢi+hIjaj`bNkv6M@tPv=Wcd7g-iwW%Z5owp1\5rpQpi*^t47]#^3{W:׽APecK6s t6VMKX0wsXVZ_.Wum3Nrd7YrU0Qbxvy3exz`o t }qi+[׻U7T7'Ru;Wg)t 2$7Et 8l!fPWuVvA}aE5l'm$lZ5 mx%;Q}ro5G7JV`snF3XY],{)T4 ^!5]j7|22 b/(kVǑ~4X+Y;.OB/Ls -.È}WaA,gWT2[ܚ9jU>7WW֝xļb{-V93m1l]Q] d}"4|kSSOU"1R+oXIJKiLo*U5Ô̳3m`G20ז3Y_m$6dL-bM4jImlT:+BK0 3GPpE@AT\ w,{NlBߵQxX%AO5X WbqTָmVVԭKeu^utH+*VGeSZ?h͒|1ӵ=rq58̽7u+= y]~I%AO=`zk0?\x&t|WnQ[׊o{S qT}eZX{W<6qaGmWrJr[-c9yݩe3n*Q`WCrjߔC]x]nΤQ?oT_Nn#︴etOJ%V<չW9[YZsɲvv#ỏҲ@J4#ҝj.ʹn}] zsCڏ,B+llU_m| +SR=Ğ|,Q>f)U&ķbq.U^$X_H鉝2E e,@eK)ɺᣱn RyMz'=kbs&@X&GFXc"؋3kDk|\#h-_2XE߆GV!SyC!O xiB"+jp7ښfq P{C'd/)D{AI8$wh:֖g3Y12uo, Ձ[.hjnY3fyj;ɩK$vVhNv#8^9 ),9H[;dCI3>jQ6>눬2X95?SKޒVu1;nU?.&-3J&dtr;% &΄*EԙN,|ۧmƙ{5:RzH\؋Ց&}UdETF-UgVm`ƭfCKu#Hbn7@H]+uWKՁ#xS[%e=s55$EA,0 WeOVn Y;9j} ZTyLyV^='kbuy`櫨R^et"Sa69n8rQ@0Ż K5Z _‰k|7j]yi1׆S{ ؽxpdw!>CjR:/2 xKʣMH`Vb}67)n <W}Ei.g\EHs`V~9#l Wcu=7H %.T)5~9嬋v(kuU4^jN2ܼ;E6.rgrnc;Rt9cRut> ޜ/c(nMQ|/&X;ە%Z90~rZMp$k Uw"$l,Ps,ط^C_To@ۗ1fr=Mx\^ݓ?M 4;+(Yu\[.iu/Ii>riZo\R6arOck⎶autկn!VQ\-9^:xΩ%ldP0xn"B nWO}gKzj゚xwK,ɿ[U4^\7*43bV"z9:,[h>49" &L K(qш{<ҜqIx4N345sz9:嵄B=2d,11)[6lY+5A7.C=AȬ295S?3$!T/R+EdBCdT[;B69":F$pJLe<-$4Hc+<ɁnCY9 D[IqG+I|P{Qª=^ELV1$}G;'6E!)CD`=gE<$FHCuƒAdG#8 8K) DDk-yCBlhA'}DL!:Yɳʄԛ2)#dܭlBl,;J/1kkCVIlUH$ AJI2{FKf9쏦,I[z2{A|c\KӧR֢DrGTL"Ѿ)£6|LEJV0=mnjLJnDaNȘCKĉ̕D9ݧwAMTƤ:S6?Q@S9̉|CsHr3!MMD#T&Ĝm 9m ](SUL;3Q3EU5L"2*>3ϔ2=7ѴE^4 S"_J>L}OR$%zFDVjTRӧէlУ):}0I«}@D- {W5]=ŋӌSM,U^Õ:.V ?,sH-ԌԼt?MKK4,ңVˁӮR1Ot׵4$'\)M 7]@T6U ;ʍ|+{ћLosMոo[\cP[=FGD,%R3A;4M$"?mP=,NMwYۮS8WBĨYWb;:_̽āXT{erUUAZӎ!gUHkmOX$Xܱ]AKR}YR]C\#~$I3r}`׻;ylzU9=fC|5Z]f_mV-F_[T\nmŹѸɕtW\ w8^N ?&`D5׭ǝ`^^ Lz4GH=J eQ4]Jߜ[KųBWٷK'+`YeK>&Ԥ@Х:d& ^]-2fQba601T%tVuf=c%_գT]SU^RHXL=%%/Cf%b P(}4ubٶq\ `sb4B@;_Wc]܅+B8lX%\faJpi<=ed3&aZuuj˥VFK:f|bt&nCPO).P^.(i5\k2&x3N_ѽ32ZBZ5E@ZeT)(hUHC( pTUG/Fj]jƌK^FU`4Yż>!b.LfI8NY Pi~&vUUN7kԂӴ5]|cc{evh+o( :N&Tj_sN6GI:~EjfzH:ߴ5/[xiN*Ζ뮙\Vk 6Υ:5l+"ElDE"lue&.쮉v[|AhtD}n/.kD2fӭBLk8-mskqSvi{՞|kn<JNa~]_V cTcZ߆j1/nܕ?>duHfiRV-nbN݆dM7oDr={k%̆wNhZ%GnQ~pżmXѣO,8د kVdYu]Ɗomk["'fLEkFs6oT1۵}w%׳\Dc;Ke~zaE`9.j-@ 6^n'^qaHjh%Itof&R mmVmtct. LwUG|NZUnE_ZhXG-No1j'S=Yd.qޫ]P:nghbfGtiwoCϛvFR'#p/tf>L^3}o)kQQ]7 l70)6(7us.sUDbm mαUK~u8Vf^fOX0x[ޅ_ v&nfy7jetkm\]B(f:t܄Q@RQVmt|wwYWN]uCkvb]B5$xg@/f36ty.gr.NVSrcw?p {gT;9yƽDase"GZqvysjqvMwfx෧>O'qvxLze/hO|wcϵ}m#Ywf߾}a罈@0X$" A\:!CpZ.D`rE $Xl~U%I|51MfRILu;Ob%>Bht#?R4*}R*4]BZT"aRV!GYjedիjխ-g,u EoIrcNbw3r٤7?,㢒M(M4tI#x?U 6ZɴEQx{˦^p\]Ҿ*妿osy:vOnt+}ߗ[-ڽ l+/űC*l 2Д-ko$A5%-w DQ b8pXELtBq;r lGѬ~G*r3)2z&s<,ʒ'J$+ $Вn/l.+S<ߣ"ɷe>7̃cFL3MF tkETJ(8UNC1>r%YVΌUi5Jj3)HKl:l]>bA :V OK 5Y#1fAJM4SPipU^ ]3ہ{74-c~ ${RԸ$9!~!umXW27I9vU5J6hO9-iګͻ/6N5DO ,`FR6w1hD]!{_SKfU& O9>%չKvn;9UbW\d={fpgc4b֖dq8 ^M@x39'YeSf{<PB=)PEʭ[Kl>W{gkAfAk%Bv_scA˫'ao,?m*p|?7O&p̵$ñ~],QzvelDQn:] " #R9j+!Ie"uT-jZFr򧢇C V ;K!fW|g;t _l"Ż˟!ջANf,}C;V)(NƲA;ħR+owL̎گǘqi=?~oksuetޗ bYf,#^SWTfU숺go7/hcߎ@uODWe-{g\=v_Swj廎 i;490qru֝nkEN*z/X{a>vQ+AkvIRwkK˽?yNs-Ί8ם֐~O9~⷏QW3oQNk}Wˮ(MP=_OV-%rVBL X koNwp*ʏ6lVIjjސ2}<ÊҰC&&nόkDpq,ό7NࠩbHmɮ0 ǥW^/ҦLЮ&Ͼ%xnŢ   P & CtJ DmD290 YEB%ѺtR&* :5S'>6ޱ]êzoQr^~Cuf~1޼ǫBſLk+ =H A,8mkP*.ZD ҩʖEN> z'nO:#与Z-JH.Tgjh6t'pAk @/Pk4/5*B.D4L̽;R';L/@X}='8/ W[ݓ*Z&S 3-yks\ۜ?@~?PAmx`چʣwtQ%HO_F̍wr{Q]br{4Yփ+fY7hdӿdK^z7K-'{ 9Brd}hL4rO?5;GNvԛjA#T؛s`$ &+<\ ȰCn1BnǞ7%G+{e*%^|,> i_{E>7 Z- De$bz`_&ɨqŕ \j^vyB]tpR축C w2'od;sd+P{ΣʤeH j؍PJhȗ) VZɘ0:#Y[浱Gk:gpc9>Mgm<7DHb,IR'iyRӹ`,m>|8L&E+:,֔?ڵnee-_{[]mfʸQhZ)J}ד/qBR2~Ũ$Mۜ@,XZ')!yb}^Dx,Պi%_+ɟ_KG/ 2L hw:d[yHٛr+]4ƚ'vowkŒ̎XLWJ<,x^_Cnm(aI8wT}ViT:ʻىrW,ΙxQL}ۮC9'-Y7CӑRSHh]@L-hP$^vΌ;5ᪧN~:zv>l=6^7[04ym /i%hq}4z3N8[7VbR4iζ(fX~_gEeVo/F~tF4\C^ ؍WnOB젴J/lm: (Oh{?)|$p/uKNz !ڀߊiN06/"n0JI൏ lrیt쌎e P*@ܜVW$` RO(/ p ΂TF. o+0[mPQضo ?W0`ҿ7"L$h N|q f9:yO 3qPqXƪOL~lpl~^g-Z ޅ vi2ѱ({J"j)wZbꎍ+bЄm/ChNprhjZlQqt=1 p,-P֣菧*'ѲPa g k"9$J$$ʭ %j/T޴WrR11NP_qQipb)/+er g#RO+-2)+4qDG2 /$U%J0ymq(2qJ'1Lf^M5(ZS" 9)N4"*P0P?;Rr8+?455s%Tذ6g.;0͛'pq7Sm.R%3 =)Q;W) 1+R13T&IJ:[4S M=*lC=rPRQgp6/Ik0Qsc4tg@pL sIL%:ө3nv1JT;9;s<*D.4ğF/4PH8mSZ S(*)EeR@s u/g/I1O{;гB2kK0 6Դ!Ii,KNuH*a19M^fKeyF?qؐ?y2 "&Ԁ Ӗ†:Ֆ2V(琻GlQ*˗0T>atESUGLKTT46ڵa.G>}&Fo?Us^q7 '`/щ8,uZ;RKm,#!S~6F9d4d=U37YE>{>TgXU<.%P_O a*v?QT/bNqRQT%Z:M\-7){cEt٩ ,mF%.9DǹŲv[ 7X`])AZi,)b9uXNzSˠ9ctMˡϰ8M {mO%5 5~@;/'6M}\/E.ݻ~6\yw7zq3eU{ۻ eٵ9[|ќykH#`<{܃V˜u#x|Zяg;M/<)Tw9imWE; <ݹ[(+M፛GGF}- 5c[V\~]yx[SI؃¶BZt:5}%Ř<_l]?\}]Ke3q1c1fs4êS \$A!yZlQ8Y I7J PV<[zi*E>5wuKGy=|mj}JNUgry(;?d}R T-=#AѷJ˼]ƦGMIoLY[t[Nٱvun"}-SBʾ-|Pׇۦ;,<<~7x?tv[{}UvR}W{)]2B .K}A~'ڛ̲kޟ:\I^tc[ۣumw |>>蛻*}9~。\4C+Q;=ݓn'?3!7xMXvqh}\!OMOӷ+q@+7cڍ  AOD.C@,J! E":1#y EbhJO*JarL'1MbryԊy%eĂ_(qa4چ@]JA*n!P+u\X4j]Y)վ3^Uq{YKn+eX/<=cl%(У1L75?yZK]&-<t=r\ >[L_qWʭ k_2:Wk =>_ռ;> ^G^?еLXݴP:}AFA*L$5jS9; C= S)֦=K;ћJd=ϴxΤsȯK ># I(?IJ<@#+2 30q<ı;Z467;6/ТU? $Tδ,i%QJ*EƻJ)0J6ITH>O1\-T}cVT 1=31m97rI3m %8Mb3-oaMD͆ie dʜ=XHe,Tq&SCp9sEוK _5eS)ɯ[}֘& 0^̻AWլjaMM'bLf69֓1Z?B)-l7ڿ\e!ݯ5$]XzޙQUMx:6E+f5f V8RSԱlmY1yL°}9DgVXѳTg{ݎe|6zփtr<>xG2N*j||[޽כ3ibu9VۭY)=wyيP]l7D;ujsrWz~jW晪Rѯ; VoQk_ZG?EZx쁲efKlQ CW/ t:R+y_u Htnö|&CT~m.CZutṱb#y' <'؟/@3`N)7GCP%3]tBhBQsf$ltc"lKl:'k06FDYBsnM,3q§ i|rƸnE}a;NfALtZ6Hɠ՝\C OI&)Zn@W ,,dxWw<|M%BhNeQ|/Lu/' &c.fȑTM9<כ@ g쨣rvj9J" *+ygcSJi@h˙HRaԹsn;L:PDzp)#T@*-YweS<$'.K@b{P Iڥ*Jc[dtFyyU)ɍh H*4ښ*ƪ(^j='b mJC5iLnSgl)mXӦsDSKd݂+J &|g2[C7e}B !Ygl<º>Ȱ;'u>%h/ՀziZ2:9[_orSkg;mi#GpnVu,5͖*~j]]{1w LAE3Q7"cyWZ]% 4xʒ_0܊krd#kПuò:e|C40ĵWjA٪sKy صvuU]&~d eə;+hjɶ2VYvM!m\ bsmVZMW+rlzVn9D4/hQ9z{fgT&W4Iua =vd9Ws0jVlySIg8$loN]8ql㮳:Yw͛UΔ`kN~c]p)xcka %^e#SZ[nOcػ{ĽrS|,)*tØS:Atђ!񊇒(?pj(Y} QgQ NiNp"r'cҍ׫y^j_4\xkի>^KF𾳸F}?^z׈wVTnW^Z{a#&wGy<:newk^Se5yb_SN5hӴӚ;?Ѷcoo_ÑNܮOuv>K{G S[xox5AK#* b]<ۦS漊#.ϲS>м.=Z?"!?*?c+ حX-s〓+A'#~C+29@+å.,#;E84E9 m3M8&:A;Q.3)"C+z=WC#ۥ"B8WK;3»pDCI۬ *>I@+s?!=A#<9S2;Z8{;܉CUt;sy|>4@!s)Cd#&, 8d 4Č*<|MBtL)DQ Oql&D+*AC_"E.[qs=C][2!>;DDlHF2'ML'D> $L&si5ATnTRp-4?%cⶫ,$%FǴ|J<)FKD ¬k@4Bl;"ȫ=D=5N peJSC;޿Ail{|^\~,g1~gJ"J,DÃ$d3V!JvACLrG|ԋGLJ9SK?tKL$::,F <;4#E<Ĵ@ӫD<䌫 LrIE[HË{LuLD%,O1M,2GBD0جf,BȴMB ݶTJDJ=Ó?dvϦ7lۖCL̒G.G|"itS¬fσMϴOkNLL05SKP3rsJ۔&K ͵l_*R|4J7 m0VdKF5 GKESQӖI07C\5%@JuY vU=1|C.YU.4bWE|fTC0ӍYGԴY <͙Š`5 ׿$Lc"NI6~#8 =PU)TSE}|~<ܚ4DibQR mʳO~]]Iy\\.(W$YA]ӰF6U%^%#e]ۆ!]` :YUMQ GΤe;l,ɕNIL K<eL-֕eT.f8h楂ȤZ-ݖ].=bUcĎ[v>]_VJFOGMu)f(` ^84Ji7 }ckeM?S?=^X]UMN݃RNCM$`@ *m (1:=S$s HJ=HH?4%?tbackground.pngtiffutil v301.1 HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km  L2CbxN ¢Ѹv9ģ1~E!CRG,9|'5F$q=Liށ9%LMd]J\"ieSEBmKW΅t^oW07 `x,27fV2Jdlu1gu}.!sk5u2{M&']ƯykUx>FN0w~=uM|H JJt B Bu' '0.2/IJNsum_k܆/۷znX$pDM;5b_˓pn,[7,$ L \΀  G 45>JY=rՕB.2^Ӡ&"&c $=hYCA ^Q=P⻴*!7B2!" U%eDkm=#j'k~p Fc3kj >0 M-?r5+VNCyrx i3_ ddl~(iBbg/ ;i+X60LK"|JP]Kb,Mq"OKؖ^bҜRRVX2(faq/I #Zrr69or Fik}R!>KM6'i DxChIAHcrjN2g'C'cTiarvVEG/řt^Zâ.)thq)I)ǥ L\ԘJgb4Bqr͙SXr=etq~ʅH"!Ýt g3рNckJjeeUDIgUunp@k~ZSȴ麋3B BX҆wJ$R֜u)K%5MԟjgSji4D;CO%2ȘJ6-EBAZbjk:˜ZMZNܻ`EϬrFq8LZQ7\כbXfUK蔨mvn_b*=(A?\:o}ORKi Zխb[upbtSN̮?m:I-ΝOgefћƲ ϰB$Z vop}4_nE?Tko(1~e)G\m\띭uWZ".]oؐq ]i>R9ϲT.Oor5^cnm=\{JD7CbKalҎSwkqZ#| eTXx.훡Ez[cc"婸uE7 w Ǒ\>P9kvՓy=_<ǖ|Ȧ]} 9>X_ASdΣ;:Ӝ={Ӷ}/Fx դ0{|Q}E|ZC~NOLY r [V׉h*.R匪PPp^oL oꮏd"JΎ.؈0!l.XP"oF`nOFn$:v⎸ybB&|jPvԎY} oOq 'Z f0̐rF+ɬõONٰi8-,C(7 N5 A0΋&ϒϩ&B$?lp :Vϖw5 nwCʐgbkH% xpN1-5| rE 1Zl#Ѡ85*Rǰ pL1 Jqf/?205 Jtߍ4WPY-(Q!-;4Q?kV1ZXp0 Бw%YPq&i" } LQҊr )HПp% r]}i+P.K V2>ґ6Qp+( %SL_.q%R&Qk}?23Lo4 AA%BY+GANoFq8܏(5uOTP6r~oE}QRr1Oj 2 #@Hf->T!f Q= 2aJijWS? E@3r_W0T/9&!؛3dr4kG DB-o0,̯r2?*4ZKS{^2l*N,3y,l L9bISBeM1e.5!Nsat4“/5JTJX5.S; t?Ms3@T2SZvqEˋt[/(*7NP-|,AQg!P/O5F6S6_O_98Reho,K8i`Esݖ)3mĵ]LdGm{fScpTԕaGkKv=I3qWWWYg&P\/g75N/ NP[TPC[E7q]VlWC\֩5QuCp ,?\o_^5w?R֭(t9vM" UnVEomNaU^S#-;ci!uo0ՔRw { 쵁q-c2ye<Dƻf7iv Z t6)6olj4\w)xYQV֧O MD#i 9ΗP"|LG1r=jwmm eW2^zxV՛b(b5=rs6sZGD|xtOc%t )OehUv^s+vrvPv3e+mii^/]^j]r "{v.ecV0Undr 4<؀Xcpt1n18v'd,:XYi_:kU檲Ռ ۀ/lC68pl_ه^)CowqU!k\ FǚE`b|W϶yUonN{bS2:Lg}Xrz+~om#7qØyAH_Yv[ͧ<9 5ٹxyVP58vֳ8U uA>*4~iacUUI~}y߾Kz0]]θõ]i^̸ER#c˞X ^-Z͙ఝ_Γ["8f>U5uX͸ AhD, Ȕ>!ChdFcPX.I#YDvO"Kdp4W3ҩSQJMCҙIKDj}UϪjuf\W`Yd6{M+[-7t]׈evQw#yq;j/؛t.ُc+7<\ij;^ItA9F Rtis=&'l3l5E5S*n:Bk7;s?Jݚ)4^r89Jz^7Ƈ&L{4ه?'O>Cʲ,O>pB { 0PA:tN^ĊKF. ۊ7LS͸hnHs7IɱvJKe$Ƴ/ 3W)Jͳj쾼8L)CL/ <,4ONL0Ol QO+=x-!bӝO]_$}O$vccy~0cYVk pi5탧^ߋmbD^k. pඖ{sۂ^%\S9pk{v[}7nysAf\#f;ijM\L}aEb9Njg<ICh)WDsYIt5DbxoMNZvu5 ;=XhjOˏz]ƭ{_kG_/!/ˮJᄇ#xpw 6f{~}N=@djmq |#Py5 2pr`rNtAK:O+z(q' 3(еB;F~[h.} |VolBt)v+7")'ˑ N_(#c#Rne6$ g6A3 b8?[od:HDx{}F87 o 0iAK:[ ,Zr*xr(DqxvBT,'OW,gj.Cɕ&f-dwe4YWȯ&ܚkNh:CoA9(#\GxӓJrFG< 쓲JcS\(I7Wt4@}fR~H$e脄)h6DbS  *{ [U0b{'ΙG8{K3X2aM-N#E8 y Y8sҚ*dӪ4Dd,nk/PاQ΃\}K@`$3CHBzzD&r5a#ZX+%Icb1ɲ~)Zz;S,#p7cT丫hr- 0k]l[6[wUj9ue\xYk{Ub5kOZof/~X;Ǵ |1aku]=l/ѫCI#/ڑ٪}<Xel| MtmlKrMNԶښ)Й MQ:Jqٻ5aLVKM4MX+!ŗA[ڝw&Ŷ<(dd/>={/N=Ѿ`C HB/Gcnъ,eoBK1dzW2_zg0,:h(e{MM9w~2r3k1 6 d?sU#\U|"e'qd\ϲqYgglۙknWht?߆S4`\նIj{\'.5 3 HߙhWvrd2'kIMU5,bdYmf`yVFwS"-{{qyv`ڹalzїjm͵m{s(;]}0/7l}.;ftf -#x}uŧp%9&sn8=CT gyI L! }hp7w*7j䈃]h[vwx>酡GհqW۳ow:߰Ӯ=E}m`!~O]{5P71ӸR枊}e_G/1S[;{쪃?ֵӸ+%i9[=r05=3Q:3|A |0c{ v[6i);>7+wꀰ k@[K;qAJ )]< Ӽ4ʱ9R[@R[C!{Pbr51R@36=89ɿd2j%CBBI8D$)$aD+I7ɃlnC*ܸMIԥyGd4$P8KWbCy@dMNһ̻'E䕜`O O# P,%;BJģ%J{1lSXҔ мݡ޼1̯NiN" G|GmNn2B,Bet=] NF˵ ${: σ\R;lOTOc>H) :="̭,ȵ1HB.HD#t?#oF3j 9+ 1R@?K-Š9B$G%DdzYHx;/MX5'N1];-3St\7UEՙĮQVUXM:_ά3eDZu;mvMg}`pW p,+*RbYF1#1u-5ѬM ]&ewP\)8+{v|.O/en;\8x4 i]mJ冽]oT'/斦A*‚IgBE-)A+9Bʂ ?O /s°NFjDsDz HrȒ Zͺt{I):*;{һ5R;+ J|;.lLһ/d༎:rI 5Q;25\N45=,.hFKTCQ*tM\CW?p )q2CBTdhDqAg+IXYgelٱչo E0UqKGsϷUMnC]D7ԍ IM3-'~M@Or;85 a/SyMlvnEtи.#~aaثя^*63u%idGم/ecqecSV5cb&U=mMiWgyƟֱD'hg/ř_k{ӱ#W$mM!wܷ]3l%`$˟܆Qq-71X/`!zԜQ-'-\^O?G9^lG\9ywx镬#P陸Y=n6G>zkchT?ooݸ?uos7&L5BqvJCdvz$d9d-+rΊ XXuZ \,*}tԃf σ~*6&Y?H^+&;֦'VMjQQ;ۄ`|I>6{qER9S!aJ^D as} rj07 !tY6I^a~Ԓ C U+$G[.a E?&-vuWTifڸ+tfݹ6dA&Xn&Z=t]e`[g}Ӕn Ўs\.q2 v?+FngG+.^5' ӜT)nΘB|'m,ooɦ/ U 됵1ⱘ/ P9 o.f0bON/(qcNTD-TP;Q pE/s ,`h>5O5aOV2{FCAG5Fu# S8O1)d ' bC+5KUPFu;F9LMbPTSTV:;1IPyK/ tKSY.LI?)e#Mls(fHZO]61t%grbjh OJ =C7,m_I_u_ a4`_.]UVVVs4uVlVGv9l27$dM&Y"J0[/QqJ3g5;&t/0e71s0SZeh4د3U3svIirM%jnO(r)lE^W l`C_u+lm 17n*Hx R%DU)7cVcDVB71+WtfE!V[}Xa0350u1svxT4U#OWT{@S/uaMw3 %X7J˃Tw *  UU)BO p5W)+_1P[EP3TwaaSp37 |a3b5WW58`8~Ww$Tr//WmVcutfsǵg8'Mi&fxEuSGwAu015VC~Is|kw{myqY}l._bZծiVXGB27-=`xȼnWe7u՛"UO8mhWC&qAtY9!?J[iÀt!SGT #BQ WE6%߄ב)'SU{tl*FRGQ}oTecQ#׳_BpFޘ6KrcY|xRX2hT={/4t$ǜXwcKߘ=M8㞹3Y ؖ8a65Skof5W7k8x{`3VxYU+0#dߥT,fTuWoA=\}*յs}驸v N݂$c[zڪI{Gx1ߴ?k-Y9QZQ;hmVmk_:Z9:8j؉Z `]їMmaDN?YM#[YfGIV[=sMw]vۺX<3Z[k~oMWsNhcĕҐ䡚V1xD[%{( }In[*+>OM|!7Oq6\9y.YDU:ip  `Ј4 ap|>hƣ n9##)4~CIɄbS3f\m ̧Z F>Jӊ,uCJzFoJiѸ=Wk2eY;Il[Q;q\.{y@Ѽ A7"6o|ay<.Kt܅9hs7&Q-w[[,UiQ|wGlw]:{wlɽ:ܫSS8͗ZV< .sz5mOc/z>Jn(< =b]oc;b+0PCT8I8$BdUCR 'p3NpFG ,!Lsֵ {j2#:봒S-L۞Ҕ.lġ$M2LĿ#G{V^c,#ypuxQ |;yB3oV?n7Wԣo@FW 1(ݒJfuFWLq&-{/ /.9 ꋔ"sLIѧoP]B4ra!dA(C Omۮ2TEg@i`y<[ {3_"<2iA"ũ劯՜ 9$C·W9Uh5@2(d@W_t}]5 !ztAhխ Q+5CۻeԂN(@e4Za/tM:l&t39,]Nu8ڇ1_ċ $]s.Um](nȣӥH+`I[++]+󢍓F]絠gkpk2OLzX| Y[DkСs5>0ZEoei\9o4h'naʻ4Mt VkS|G:#!4M@xDp;Yv*1ez_h*F`:T)cNl )~pvlx<;%j&ာZ թV1f}TJZ9{"7=dCim7f4~(O02GNN,tH]Fz|[-[9T..j7>X2o-l{.G|Ν7-źbPCי5?U=}56 ok>m3bVVg ã=yƏ׽`${p>ibPȿħ^,> O W|;ӍoA\ %#k CC2[,K:S9=(AӘa::ZR,;B0' 2ż3+!4Y7c m/º4J>Ej%Ϳ=1/B4;|> 7;7}Cs(8Zl.46kDD,HB- |@ (Dt3I1{KԹc2b=\f57#ޱa2ijCU)\T=4VEK$-g"$[7!F<> $6L2 -t?TEFC;cJF,l\bGyDxICH8$sƻ4lh}4LƜvDl ;Jtz+7Dܯs/B3W4,N8J 9C$-G͔+ˤT<@~uYKROE3&dRυB=. [3T>s|Hc#̙LP4Dʢlt]|M 4HbP9m?3#YD}HpB}K#QSҭJU 5ʢUu?J`?"U4$aK[$E#GDcURV UM~KS].OJOМHc2 IM4䙒RvTW7SU6Sn@DCO*B&T=u•iYtTIM{ClY4XV΂+044KQ͍UNu:8,p?b\GJRk-(AVC5+dWO10։/VX<5Oե-p۽DEd̼%HwP]zɽ@PWմ}^u/e[33X+żM҂D?R;Xԯ^KcXyRX[Ŋ\U\Ν`%Z]Iݝ]-g%Iu}^tLev"mZI\7%(-S]%B,EolLޝ-|S a *C1d.%1H,*/Bd+㱩LZU-d;6)ĒY;(R٬}Fhz:htC%ʻ9Ji ¯_finVj\i{2}]8 & N30㰙(.R$9l%A SIN|G QW[mUnGypeOؾ7xgv:\/Yrv'[x?5(%䯦T%pj/­$PԱƉ <0.ܭ,D20 - %qL`AQBrPt-F|Gqċ ?#J,Dh;rM4>.13+:n4MsMӺM \Mn|LNSP>\6P{yK@5mTS8rr-+t- òL W o'k]V,)őaI%Yg%YFVyG ֝fݖĩwEtcx^iկ.tߘ ]7%+902STĺH5] MUVO3R FLx;F. QKS#SE,oW.gNwPӳ7=^9cF?k"YnX^k=e&갎wWzBn<]Z֧r^׻nQзi{Wڗ xjZ^/i_=q=-`-7ʳt~~t:lL ۊ9~Mezs;~&-b]{Om34D[\Ӯmbk e8_\s鱷W.ȫy~ R@7#Pa\X!aA4s.YͰf(_SKf)p;i/;n󌻺x.lL}N#E"؊:F74_e>^Ev/2<'{j|eMF_VбsY2I/9R1 DLX: YPM?W \r~I.Y\KBx7\R9m"䚆L8ra䀇# LuĘfsf 5akM4vOMc7TQFtq^ӝ3dqp)f (z4/ +eqJgEf$(BVܷtF\ɪ2 Z*tI"X% ԰nW_%® 얄U R [.K)ja%1=Q, LvYv*D7YA)v#cUZ&1vO'ubd%F U'TT+VJc5jyVE-~qڇ)ݥ^z{3Iݜ\*+hCQkT%Ҋ-*wh56[47ʉ'mBEI~RM`MU2c1rPDjϯ*f~yydUaP*:^mdӂWb9L^Sf]dQQvURK1FL#n)ӻe, V~J{j)-JmQ+q5#gn"_B pzb4㻢K.VcL5tёY$ݽYw-v4홯.2g!XcVqSWȢ=-Xa}d9L*ZaI>M[=A$B\2KX!Q~'K}Fmc)hQl7"H}H2n,ʕk1uv؛k,۵`cf|4^hA2}`էKn\VXt:c7WbL,nC/܇ta[Ͻ4vRw'ijϗ/䒧孷Yϻ|pۄ<|p]}KVm3޾|6w O}+Wwgk|Dϣ;7}CpK4Aݍq>كMĜ(?\=y~~}lڭguYt(ʺar=qЮwZ{r=[bn>%gc:{ג͔3opҽxeWά{ xSt}C $&OO JfO؟j# BkNO; @20v`QBpb>;.q0ةm#Ro zL,͡G/2ąӘs 8鳛",13s1.s]%?O,Ч4soqrwҠRe4022gOi1{p 6CM7S,C1_/A:u+_31,;,}F> @%,_.<-"*gH=0Ϯ4dEIS"ө>tA4 CqB) 6K?5 i@)S4.o*2C5)c'l Af6T' T,T5NnQC pN8-}tkg,NETZ(Z4.R)-,sT--470iJ*8-Gu_NtB=T'//5Қ3D 5Nէter5OAU ?(\'ynvsKq[ 5GrRa;\pSc.2`/R3`eW1Uf/)mbq %Ic@%/Uy,?J v'>Sr^=N (.O-ZCPzii oCTLC'3Z)vYOM`a_oi"|Г8Mlb=v:s<:naG/ISMnИE5StY9RUJ6 Sa`W%e0m?RMhu?|2USi%hQCNk 4A\jWL KW>i^?]wTL j{8GG@S".[{ p3{z,H>&KacwXicHTֱYalTwU 5'U6}'`TwkqxqQ]fS\V6EYh2t}pfַKU2O /amW;roXt@;pqWv5n_'`CTa؊wya8q81Tw8rz~x$xoSv7Zs%f/g+t(sfw3sxi^wm'w֓l1xS]kM5o)Bv  8q{SG9qDث{Fw9|{qu}YuGet~~Wsq}ٍW0r5|VU٢(2Lj 6SYu7GOvg6h|0Y vqu#;wŅ7k,.ްx  YQ_GUmwzx80t/].Q91XTך#:6-EkcˏV4m6_QSE5KxuaYC9yipڇx xv݆f7S7y[3iב4.6Vc -1y)Mxv &8 !smNyN;nR1`zYc+m8͗6X3:'VkSX0{E"5:MWGCpV\N2C%k swAI6ڦTSNT&yuYV{fQ:Zhgi3i9:^wQ L/fGYyF[#%{x/;4o ZoG{X_F7QOT1Mn[t֛{t|8BA[i2ysɁ%D;rm4uhgɫ5C{h#BiGYӷ ŵ'{}?8wԫY3@z И9\܃ؼ$UٻA' v3tp#:!`!} Cn/\ ڌw|k?m{$ /,y uU=>vΝ㔜3ݧVC>h#a~1 #_ľ1e}eY䙵T;=Q)EgXY=Pcw<>,֯86xQP(z>鯕 {m/6r=4Um9Svzgݿ=Ŗ!p:3+OߓXXt  ?OC~CotI? G@@8~E#dѨjU+F`ti5MZs=M so< L锊|^wBjtjVWUESJelXQ=K׬Xe{Q-=ι/8+ |r5Zј1ӊىL& |e8-g?n=O|yߕ2n^uV~7kN{|Gxv~fYy_m>Nk>* +Ao; )J Gi:JOq?E DPHQ ")52"#/<%HT-r\J63ξԏ,+)2/+kƻ &8MRK':,ڨK,r:,3E;B/L*@ϴ' SPSHAqSM?GQ8cPVVUғ3NXʉE Y$eL,Qy//P٢-F?9 şǫz՜RY?z:w*tIR-pٶS[;i<qVJ{YV%~6cmoCѵ>pRU𐅹_<{7)E[pnDA)ڂZ)z"fq@0 (v `XF4e[Gu뭘Y^Q.Ϧhy։&!\@m7>[}-T1ӼKTk-21w)1j_&VSI6M[i\ιѡCoΜ,7umQoB [rΈڹ!ۍhDTga3OJj9˷LIy/ŤBf S|Y30d̀iy(hA0TqQ)]FHޡgpK(F7;T47Ѫ|JB~:l>R.APJ)G ###*Khers3Oh_@ 4!>]4wP cPf q1&II&4ye= HXdbPKkWJƈlSvhW$:mMA:MiZOqWBlEx>L&h-6, 8#a$4ʬQx M#şeç=G T|ŋz4PÚqod-sJWtn]з湺Nhk\vS*Mu( )tV$*m! J˕1d.$>w{Q<Lj !T3?3@bt9\ go~,EU/Zڸ8<>LnSE7Sk|l~bC ^Ky<`M A!5h~3 ^OQmtXq##CkZ0خ8b뭍PIe -8׌fj;$nϭ 6A)f d>( >;kvZal, \7t yQc(pQpN5Pa%WcaD$ZU;Uo恋 [. _l{o>,V@WdV7\/\io+`xD4k$dg]wP9s@;Qo }/ѪWz#-Ð};ywjW>.(ĥ8#~5ҡ@ypxhu1*`t eYXy0*0iYЏ1ҳ3)-ӬKy]8R\< K77!B * %&+={>C<(7; 8[2=B,cв> k'7>C:sG9?ikzۜBD:0=4QC"a]GD3๹h?D땕7>11%:\H.@PWaw{z@w8t2LJkxbXb$AR 0Yji)RE*2C{skB{2s&+7=+8ᠽ#13ȥѸ C*ǫ9Jg8L4, r&d #<33=ùi>kD>Q(SKH'.>F:霃dO?H4Q>qS?ӗ:JDU\c5$:DcE4RɱE D82*S8:Ű;+YڠAytb2U zeu@q6@6Ce0HMAy mAD:=N3JҎNAuE]5yۯӳ @ v@+8>Hnf8AKd= FJƪMCmD2+dsH/s>ޭTz”3zQɼQ#B ڽ̼Bl~&G|< ȓի̈Gd$|89cM翃ACIO&I\}3/S>ΌD26NJTN\cʵ=k JR#LJE  ;H\EJ;[PPt4 ~g8\meˣei« A67ŲG;uHU*L~Q"ǒԲ 3M0!֕*7ҧTK*҅!elW]+CW=wH0d<3r.$53'=OlNcNF(}CS4DXTӣO4=-ԵD]A;O8TɘO(J*t5 Z\A`A@ƍ bM邶l m1(s$zLjRel[yRm'QR)=MҬ|WUj։5Mw̚ ץ})M&4&rWm}ې-/ٹ9*}58qnՎDCΔE:U >L#N.]MCX\ٜ)UNu;J5C8S]:LK)ErE%5쯹i;<@ t6\e kpb[e<6ka 1+o [tۅq}M t\+]M`GԲѲRZ\`\m#LkW%W֥Hp&%m=SXeD^#>u*3]L OݜO-:E??>T47I,) D횾śgaِ ?"O?d5[VK @/CߨXxhYpp0Ce;ۿ$HMK3̏1:q(-2Ya)LUۦ"7Ϳz),}|\L۸\kavf&\RRfr>%wW5 "b4࿴V&-T|(cv*t݄<ӐD5NKԝ2N3?-^%.gc>E[Ͻ@4=h@si*39^J=  PV%KeeE١Mak{VݽSf=~ׄR\Uv[R^fBAhej\(e &qzu־:w9ݭỤ;HxAT,M-?9O8l&5Bcih~NG\=* ;ũڝJ}/xxu(;E];iUceaiV;×3ūBSveLr^ܑS`ȎjƺGnM kFp卞. {aj&LF\j k͎7.tlKyfl)O>YN{gkC9͐0@g5烬^Tg%.6g4Ke\\#|hEH'QrmiYyUa~$ [h5Ln}`td.C Z #iFQ,nFfd ꦹp. O +.f]ѕLk Ffvm\Yu'CRFtu kAFlfwbI3l4bvcF,h^bE'l>6_$N(hZM'?uN`6GU6^ןp:N*v547:'^n>ylG"tNe8ŏil_{OqŝgfƭI]9+&/@b=, E| p}@ccmf-.+/zPչy/=Yg7dKOI̾t H9ߗ;WFGXFpt`yw̗YyFpW)1~Tfu?az$ azvq_cA@$" ¡0<ĢxOzĂKap|F'p*`l 3p&t`0ZFUT*6?7M.܏?{}?> ?HcpD@pCp=nhF*LE)jʄJn(B+jGQuŪ~(qh蒄rʬH ]%*Qz#Jjt R~2lH.j|4LI2MH $Ǔtrֶr޸y# #F}!HIe|1rqF0PLKH4uP m[R5-pַ-h71wΫ @/B CZ.1XE~Du/`0լ$+YwMpL5v]a>0]Pn_rð.m>};(Q  0<. áP#ĢQLn3G!'Ad?,%Ԧ/1F$9)$ȧxGh9DAQY"/UZVGSg5ʭv&Z":֥V=e?P[`}/xY`^fsYw=F%{@pP0  @ m{&[ DT2 %=.R֘!r)w7"_9ǃz<'lܪ?30[@o*<0S/&B1C0 <<-Bq iJ&˲G"q↕ȩT*r|'KbhI ָro,K̏3L1(+1Jԓ4Ļ4JL5+"'r\>Oȿ/~ь+ğ i{2GuӔ=O <yk  kdx  +l܀ ހ` 8KIEZ?l i?ŧB{j=lķ ]Bj=ݐqSr1m^]]omu\ea-ܑ^S߆X;{ho1)D2rn?JӄՎlTK|} wz^oOi#ޟQјnOZ}sIvҙDdY_gHQI9\PTڙ0'MW]mC`Qclc5Cxvo"DX8bdYq 3jlW.Q'0T`Xe,\+9#c[c.-&|Qz'py^:ڍq^ЎW#]diw&r3iX t^rU/h]{d1AX CG>h- ea˔ DkҹA=1T2@W3!T b&Vǖ9{4RjMqMS %P'E?{ce km5CGTPR? Pp H 5d@ `܀S~X(rf}=$nwr# %7kA#)Q4m y; (dӺeJ>uڈRѝ.BMikԪj+=26OI{p%;wJz[Po3ޭlMr2_݋"c_*H~ bJХ_[lVOYt$Xu<.p?r-w g=m=2c+pp3FiQR Qp)XUh"ʫW[>EO .c7ƤߗCX0бUi 5ٻkOuZ9gqjy{鮜]MH,yyաGZL6X& Zv$h )`>"[33&RcFcÌ g=pl45mS=]C `LsPG J}0E ͥU8p8@ݽR.Z5S MW޺~LhyڵJ9 9<7h̤ϫZ!k9W^Xtyz"n [~!L["lĒ%Fnove6mG1x'.1Ҁkt0a^ـțl̝irjZ}=w]ݿXz;` >]1,bd\IYj=FU㑺^^"t_Iš uT}7FhyOt-VJ}p,v/a[դ>V~ u_/S]tz>auǛ?Vd4ڌ|D.~,_/"H-Еۯ,+ON)0*MɓP<ۏ6& #POX0p"!r! +CpGWN<Ϯ>姐`O.q ϜLrʼO u̩K.N ,({-6+b hKliWލGMki6 ,8p?Qe Nxbf0,0Ao$ Ћ!!5L6eb%f'&D!h󥖫 ?%+篯N / AQ)!.ӥʫ'Hr0- wM7"od +Y$D*&E&LftPpZͺf|-q}Qv*nM'MR:I<Qѣqf1-ͬ4n6%b67nOX%XRDD 0HޕNN1|1iW3K3Gf>l(/'!E95'!{S̡2Z2k(S& N%у(H2-&q)k1*2yҒk- RU;O6 &qQ.?\ᡘaja"5 .Vej6R8%j0$ǖ1B֒ s 33s6pDI)7G"03#%5k)-6_.3x&}3=2S&H#;4*$Mܯ2@(Li<fݰE;=(t5O|iԹ)s_RNSЮnpAo)m҇+O9d+,2ajC--V+c9szRaT/%llXeNHsugVPZ,uOifs/Cuz4[WE3N~mFa "Xt mG5VZzNԷr)>jf-+k;Įs)ҎٔKmqVnlvR|i`o: 0>VL[a+'`,`fa-bW3bsEj/Aa +(vRs5H#*f6fq5nUg2IU WWV׵z2H jvNQwL%g5|ݐ<\2LWZo~Tj]MCnn3տt8uO'O %O.-r3rx6G58IyH1ARaqCreV| Oe-jwcJV{ط6|4WWvfnvՁz#2?Xiwxuu]x4$Na8[XՀ3ҫ\X ~2W}7~onː|`wo q:  &Wiym氝r/>A?12۔EeBR!!e)ںH3v'2k YfcfNa9uٵ 7UyVi:wiy}FJY5GZ0$Y+k:7l E|l}s Ϣn3pK{^/_KXKW:*ɐ2%o=7>7,;Q'?zC= c8ZV_BÍ9k33CUlh7xbiyY{ݨ[yJhɛ:WWX;eyZYùہl=ZǠ!չIӠs}X7ҡwYD߁ԭo-MNsܷ[+Zk[&85o19QA<4!!AH1wOu(ukrB %oryUwsv{UgeFw-qYXi:ڿ7[pl׽,k؜{՟:x˫IƘJ:]T٬l5OX#<$=w7})<>6=dEAJl8u@s;_vT3qR=yt:փh|_iڀXy{!}{Xu|z<@<L<<ϻղ5ۗX';se]  Mܙ#^z]͋q|`P'<-}+8ER5'R 6Dc\n*/=F8uD$[v]ֲU:o[f}{X\}u:u;0s%"}giR7ޏ=׹6ݭZqYk}0c~omQ/~6š9k?߼NP5E_!Q@ A4qҹg6+h>.P;w13{J1I}}ͭ(\|?A~[| !$CaT2#Ţ09?I"~?_S{=ޯ7v9&by=OEQqb5 ` `T@p  c@0 mA. tb1@`ؘq6^rZ&G'frW RL^!iuVpuu_Y;A"~_2XP]~}y Ay KQ>_[*/'>, #l"P h ' p BP4 EQBN1VF([#$L%GX& h' ҕ'I)JrId꺲,kbе-ܸ!b9i R1N"|8[OYA9Ô2>NuTCwKP ?Ѵ+yBR(J-?7C:nEQL8Խ;є} WueT5gMQ1T!^t ïj1]dVeGpOeh\O<F5eYQt^5pCqƐ]kvްͿrt$QE HIJVxY, 쭓dFSei|)ppF J0j3j6P N3ނ3u;_9ãC׵nCX3z63֚/HǬZ~vR3mFqu\e}o--GUHvW8]t}>\F.UsGO۝v%yC7gw_E?Esu8݅x&OȸܑdI}~hnrxPWJh,VZZ#G-i9414Mƶl վ)em!oAP!!m=+Fܡ.捼B|aU)WQ~YJktKFmЁ9] ^%> x(Y7^Q](k4 eXC̎L ݽd:6uS\:FX$BzhbAvZqRHQČAJe#{%<+p%ԣʑ2!@ |J>*L!ii9؝fyp  Rmq:% l1n͙ՌReziovH)aҧ.xNi!j;&ӌpQ #IDX<ů%ޕaV2Q:c\zsѪ7oV!qSaL`;hh]v$dM(Fź5Q[bvOJ D?%$vA0{ՖVyhGNz>X:fU a|0`ilY=t*32+i[5:7챖f[\wn]k ubթcy2B#dAMnK{rr^S :w[>mVےo|P;8M4q Ei 1.4#;u\J_{{9Jѵ)/=v]'-wF~to5+덼K5A M^^RrQgu)$R~ǐ):;,@ x`au0q8B_1 @Ze S{p8[&,m *H3@".[CC߾s4v>5[> >:[JC?"*F3J>3)ʇ$}?{:ux.|E@9C#IԇC;đ>슝E/|C>B#5\>S,VK0,K뫇Rh%4LJ8qP`૦pE63 Ji6٦r06GLuBkA-',,hAdzFrF,PF@ַí *#3 ۼ{Kq!WGxFds-} ߸¢d/II䯪>GãDQxA?s|<4$܍>MS*lc9C򯜌N4IkT͛Xɨ~C5x"0JDOb9HY2T@16Y8t1aA$+/ACqKB<"LkF!Ƥ%.K| $P83$=e z{lvP놽YL1"kD8 b$ĀLND>CkCʕM9ȓ9dHCHDR{,A;M>{E5SD)\G 0IZP;0Xz@@*%l}&$҄QNIQkMhRR(kV3+Tք n׻$ N A#?ӓh| H}%ɲNPǰN%:Ta$K):zyI<"\a.Pt%J`@f 41T `@F 0 Tw\,c,Ks1UQaGuQ%XQ=V˒zTyTռ)[JGE P-KA\cCCc=erC P9@:j9EkHlD$WSF$amfYb}^*LɭԤc CP dgXEwX2H!|UŨJLKDjiܑ8!dmVQ&He56mlYڕL}嫽NHA<'ۆVUǨVle]Qf\` [f_(`[gC~bCJN%#G$ W ιlt4@-qfoARu[BbV[wW/cF4 ]V|9 ϳ=;4* XC:˭9S۴?+į,1d@ΛiFZUߣ2+sԬK 6F|U.U\KXgNVum&\\~ak|Hdӛ*Nkg"UzѬ:n#o4x]|Xf(ݻ&!Dλb׉5vH/xC@D8qOPe٪eKtoe5ZdoM`j[cm6dis&`! " GnV[oYKee>^` >`| NojHQfgLefMž5oWfaE' SBEpU lR&dRZM?BulUq-6x!\֯GSzQ k]B6"^}Bخ^^ i5D6ɨ&>W.sn9Ksx=7fnEs j@w6C5e} rWAOBj(?FG?oetjf~&֏GP?\y}Q\̈RQ_OHZuOu[M"bI$^)"5SNُ5w@,H@, e=JoctY7_m6+/Ppxzw\w|Bo3BZx6nwߎRxLgʡnLsg';[>e꿍t=olkYyQ}aDy'zWdl\GTuI,.?Zϯoס.slzE_5 MaL⋩:N{vjig.&P @4:" @,\ FQ 0+L_+e97瓩T.ڝ> >/=<k+ #|Ի* [(î% ,'~~'{zGqv">C2Yn)s@ PJ0`2D2J$)TД%#޽+ȵ7̫,91&5>PM1LgB4+PPJ DٰT?S9cEm8 ENՔ}=Q4͵JV,g\4mY)N Ӎ>q+dA(YO:pMOYV]lgoEd =n$hPgEQMr<NZ]v^Ven=vܑ%~>׌Mwx]}C婄5`'y⨰F[dGq'{e'!i*Ԗ`gQq,6:)F3TИM Q7ҍQ?BR]_VusKT;>,=3` 鶯UM$k{vͰbbQו?VF]sZ\NM^_.<~Xno9d.v#yCJQdk{ATJ*['&?8g!S@F=#nUйA <\*1-*Zs^)bcΆENXB;x>/=dv?!Luك>WxHǗ!yɅ\M2^bU&wg YNOc~@uRd#@Pxu#A0cćĨșe.q!%)TOo=hgc_37C"S`RKKMLKTh ^SAmɈ@!#l e6R1?jZ<ؒkpB'3Gp3b[9 mCB6 ڔ͵GvtPZoi8>\0Ѯ40t_Rnf,ebYFYz>T~Of>1Ww.섎opH ݒ0ώlRK$dt{FIʩ,ϣz-eD\h YTgm05?K§:PЙh"BbB=DUߛQF.4jвvLx\`p,n¨1,ř:F0~7o:7Ucc~hæ8lgBq5r_Q J|%~>DK:OfBc3GMQ82 :N;@QɈ1,Ʃ YmExN38qMo"\/lTj*.@TUzTXIZqZ"u>ݻ̍4~2rOV!L]ث;0Q]'WHJKUDJRh̲ 4k 83d" VN<r@8Kcp3Gfms\0G!8k+ϻ^,kI)F@T1>w;TaԜ mRJPojZ0(ѻ3ʩss̻OZ|%-~F[RzzU*srQ]h#Sf Ռ_6Y^4Di8d^X:N;v Y~VI%V 9u}]y뭜pD n0kóYCZxADTdJor4^Wv{ٜn 8g;mnїUCϛzS1>;&Vзrfh:/EhOw|m櫫jft42zJ NX#$KSj}YnJo+r{[V|E4N2IX$5@ {NU2C u*0:0.v2)o(ї6.lZ4u9Iq<έ YGQQ'+4-AHl&-2<ҝ/-ޔ)BħT>ICS!2e!M1o!M)!:cT0Mqj>̯i#M5TOs+B+4>@=bhm9ҩJSt,3;t70|~IN0TTSJ,PְN 4sT_TsqSqFX.b/T:1KYSY'@MN-0MC/{E42+.& O4M # rS!0N?u[03I[1[ B%ZA 1K(!ԡT7KTk- bv..dUб8T s <Vf8XԗSuXqUYqg6uRs/K!Z Qu?%MU U@x \uԤi y!OVt-&gOGhMPSXo `w2nX-SFsWsfWf/\66ʯ4{ HUUyJu,STpwtwIYUitt]0 cwVQ4;DQpAWug!p+O_cA]^5s-"P 3Nmk׌ !O`YKw( [EПHNF/tn bAYwKVPVFڒFӳ|Ww;<#}vMb c*Чu!_KwIv'Z#66^+n?uU0T'RJrY"8*u yt)1 wQ˕jxc WUU1o3o-=IX03Ym75 3's6K|tVnSiWꟘ׷!|'oHoX8q8gt P֣xiLֳN˭[W]my8L]gN:E+w@ui6z+vxˇ*g\%Q A;ryf(RRQ/} 0zΝy>Ҿ=˫|{jbV'f)S{8({e >C upK׿ )Wv/Xˁ?#щY ;*y\K=eҽ$Y gZ~i\7ފ%A~A%y^=%H].&NQ]1~*= TV5_wS?%?P{>QvAb AH<.aPlFE"xJ9ãX|ɤRI Q,@IlB_#fxnk/#^EQe41JiʅFUSUj}fW֫ d,%hڮ*;M]ntu_ZX.i+>i:@sؤ>K\DP ?B\PDZ+ cW4. 4M>[0R}2 GSZG Jj'32rݫlvJnF2d*;O/E3.ƍT67b5S,1KS3Nkh8n,,?0COET :Ԃ'E42KIDjNRnNh T}J'IZ|1T%X?ãFDu\AWWUVE[C&oygXrDÖm32D3$6Q{93Ow$nF4 S ˲%Io^,1w~ oL}\4aU_8]|]NxNsKmT%+KXukWpL<ϕg։SW(7cVyAѺ{fe9T5:oYVŋԪ.VEkaE;Gv:麝Q4gnYnqEXn;pطM'rdn\avU-=LqܤSQȶMv}==tvOxK.V廆_lzglRVDrYogUhͺl iwŴYӫ?Cν;=GJfLv܅3z{MG`co .yT\+u).7x*LF4Xq0m§N0)2]iw1v](u!u*h }i!)!_cx^Dx)̣R$.>gTt:\9o,K.IdKyS2Zy!dJ1Ml$ӕp@Gk"E2#42~?!v(cc͝WIsIGmel.y }s (Co7%d k/֌JuGT攴DhnJٕinNRS[LSɇbWU0i]Q)>1:e})PTP\؛sX)ާ9-η(hYE=TU?Ϸ]Mv=L7;#bT*Qh{(rjJI c||tX@6#TjT5(l6 ٚ_l`i\1m5ʾ)6 B`幽yK-ڽU]J޷U:S<=t0 КҮ۩aS .jgkKѺÄq$kޮQ$k,f5ZZ%IXkѬLz2Z;QBo٪&9H"읏g:pj[FalkR-{ݧ8Jpe@*欼Ork Iȗ>2HݴBUk4i7VƮ乷"MPW#_ QjG7,'A(aҹלLxuljqrZjz2%o:l1^[V/kpEx JpX#\՘Mf7 \7W*2nv({̎Vbpe I.cݛ]x:mqYpH&sX7 8 n H =YCR{E_x#aZQW}?Itu!? q qbֶ$kͮ|;KcۜPjGذt\e番] ?yfs:ΕZ6]Ss4vPr1?vn#wksU=1Vejg0e+ { Y?zC0?oGiEOA\/(nIT<>B8ưK;9?A;#Ÿs̿28[C\!DL"pŌ,TĜKwxS5{Q?<90T0#1C|;C34$5+$PCyǃQ<.%,,J Ŭģ2sbE\Qڵ^[H9gEE| ["3{h2,E2I'$_: OD)\+7,eqt? /0ǪGFu;)pGT6;L,|Gt>;ZʄASnj62d:"E]:DĘI[ IT#|e3fIF~M?/2F̥I,\1$J4MCy0̴>K VdНv;APT^[- ̰5F]XͼCM>8A[UWXGRR\|]%cҕĺ>uD\LLLL5;{]\L<.eBjrB]]Bu=,cщH%3^EU^T}Vm谽G=-MbIM|G)4F>mBhZ(4 3MdڡRZJbu De1HP\ GMgT庿K5W^([Tv"jJ%_VTn*&ai,3RN/܎dM$,`9>5l\]rHlETV^q2nI7f1gRrV:N>QHr Jö|,g/dX&%[agb1[͇N[CQhlJ_& .^.1eul߲dftYS18Đj}qjFnݍjdRdp]gcjjTM Ba ,*"0x>%B1Xf9C#2Z?!#x2Y$!r|J)NsNqCCy:=ѤTiHfZ2Vv>)%[fVʝekv`pX<&b.&2d08+j1XxF;Y>[E;>붚-{oڽZpN'k6o9{g8uWzU s$«$ZAP\; Pd"/ Dғe5ᔖӓc^U5H5R};>8EEfT>duF qo( CYzMqfBZNj"" Y5XEΙj=Ͳ%pD2!Tݣs66hi݁{&VU]^\Occ'aa\z;M2+v){噧5ٷ/eɔvW+dW-ݻ'aF kdMɲ9lSjfI6RvN~ջj޶[歳\$ev_2:lOqߕ|鹾_I+7ד_,RH)Ĭz,Z"DfPLŸ0C@Ĩm}L7-LJAtZ5*lwFsF$_,eKWd{]R*!d2o4&}x y#QId0JOI ((䡛m&B.f3bcK)[4*^Ӹo4LYӽ>1K$ɍUI)y'E˾e[ *n9cmj4֡kwTś W[RcaQ;"ͻqF97^e[k2kpYxVLvgIiˠ ,Ԃ<`v PkpTY P%t N3k uV+*,+h}%YmrSTg9Ր:Oy%.I7 -7*\usmź6]n:3i-ջQRӇwv̏4ߧn[w9V*1PZ'+, Ep0yO27}{<=ZjVg.G!UW+8V[ U1c_bd-vebnp,Ude3%ȧ4ǨlmbfoSN\r͛:](f%Ћh&GO8Nq~TRU,o"i¯'ѩo*#~5įW)CIyY@&w*'e}ج#U{+RѐB /'BË><oIn9PdjnLnv#D.VnNg&*c({9PL"=H:(1jwNۭR\θ݅ kM "C P0Cn  K6 Og// H00qpH%8X1o` m/JPĠs3̌.% /-w 1ڑRVP \Qo+Α*OD l2AQ / / 1h FO 5 Gr0kK ?հP^,ἠ*.g!6qD找o+ekc˃ OtrQ!R{"[#q_#ihKm*rE j[ 'l9 '␭0A(p(-2})uo*g/,'p',2njYJ*7-O.2˲=Q04x*܋%S #Qg&#)/ %μ1у?O341?.4I6sTp4W#)Bp3!$6k)SwD0Dh.1ƺҙӫ+oA8+.Q/+"g-:M͚'O!-lLQprګ</y=d9r>?>.$HLC$Aq4p-22Vn ( 8Tc%6t?>lQPEQr}G Y8+oEtsQZc䢻03GDHTsʭJs-qsEɞM;BG/EG>ܫK2oQ.5sXf 54@s7& t #4PoO4*}ѨsPSFR6/7/QTNfsR,]EU֕,KFgFQtkq;,rRR eHCZE.M9Ntx k/sGWuJ KuKY GA u Ny&u]m)Zfpc'ճ?MReMO>dTг_PU [y%5⳩C^U57K/iCS +ְ'=7$m2teg Z/hvh-6T\ ]4#\Bb6]of,Uk7VH)SR3"o*6 U1,TL.O9bwb;SI .idzwofX5XW!jϝ>-Ot?rsvoM=K4pU@euqA't ֛1KlIw# U~r! Wl5{U7<_yǵ9I}nxxj6}T-6%I;ҵMVOn2˖=_wpqh;~W~hrh-1m>X[4&xNgatOA3AчhrMmgU 8xuxO^QyolL_˅Ǒ v 9n3_P V'c47}.d.\UK}/}Q~vT vGˌ9qel eNMyXu*<3XvuhVak1[y\wGkWńo!4a9y+l*yU9^?f~գz:܊IXӽ<tet v2ႫS%4y\7EI<72׍³Ѫ&|[k`A,7a׷-|zm9s'yW/:+IY2Ї$˷ue|s'Ws|$[ʘLտv_Y4!}"X#Q7\qY_ŝakcE:U7Fy/9W[wS:ΕzŕXM] f%\VP-b+[YXXA!O7Qsߴہ󌹷o{5N|uWJ| i\ձ ټry9MN5*EMaݹ5"Zaw7zz~]8=B[rw¥"g]U[PA#YLSKw>GH}A7 tEܹ=*k%cg1c:ĘWnQ_=VnP;'s Q#  ^5ǽ^M~ZOٕ͜i;V͒^ݛXc;{cFѝ  ?D ¡|.!ш4B-c/ԂC8^O,JQIW)D9-̧sDf (IiTjLޟ TM}%DV k5t.֋} j^o7%|vˌ/>+]`sk r|u+h28M-k}Nr6ze#o{ q+qsgQCSP;9پS?_wkj[*siBT㪽)OjδoLЊ*0@/cjn L41[H1;v7<7NЈkoaE\FѼG"8 JGszȲmI5KQܱ%I4̳f̳3lMΌg Қ9Л Ot,0>ЉK:/F i Mpʋ ҉==UEQ/$=XCUGZ>T+R-X1v/4rtJ#7-te!̭;#SEIvlvcvąnWc[̛(YN*vҤ.N0Yw{o,]6_s;axf:G4+?Et?P5uj8V5ND)cC,eP5VCM[OzeiT?vF (ٺi|`,FY:_N8EZ~ZF]zĤnUl j\>ѦLF5^:a3;fS-y^AC}/EiNt+eYhqR4ۗS=7b>>wwׇgϥi}p?7bVZgf7e_cr0:m{0h ˩Ƕ(#rA\#D˞[t,^=΅óV3H^u2Cן^3ym4nJN sS3vD%oaEu  g`w}ˁڵZNJ3h#"1kA<ܤ+ ' `w! E8t$+(땓>BiQ*NKNLN'4kyLle*[I_# jQVZa1"#cg.bl'jm(řyOI臯N1F(^F5^U26Ʃ##W^rV<ILOće!T" Ց& FA\# 475E 9@6@eU+4T3͗32QTpZ S!~zZDTe>>'̒,5@Ae`1, JT4Ut8#(z@c8ȚGgN@Y5bmsMzlaȭ2Ү(nJU*m',M fUVw:V! C5bԊlڦ~uE Zx-_h]BݪpJP!`홱mvAKg=w&ak4f0 I-[Xf?Z]Kjӫ=w:* ֌u{3mwe˛xo$z\y+4yz3ѭ~nm-ѽ 0&eI٭,׈5u{7g%V&Z*j(V JR٤}$F,t{,iZK 14Z?xE\*|z.5X1ƣR%qƭ;ܣZZU/D=RJji(W .<ۢ+3t7f{0nXc?'p,hmCǝ#}s(>7׊U 2ƺqۧNuimșޮ\lyr2ʈs 7YKeݖKiPl8տGdnwls_طVsa=OB@^xWg|a}席 3O@lIpvWhi+|_x}wo %Yu5,:= wwڗ%IỎ.;sW='->9%Շd¢:fۙP&j_Iu߃F{Ӿ>{4o̴kwNt_=Iֳ ĸ[IL?.9e<=9I"5 9{Ϲ5d+"-K&Sc@{2 8k& e*.:h:{:/ 3@7rѠc3yۉ8s@1?d<$8zOL?J>CcC V ?ȝkǡɐ_@J.Ó̹<㖵,Ct 1 =1 [6Z3ٹ:)ض=xD+.֢ @/Po4kz> 3\N? $+vS'h7$$$0;[¡arH>QGE`M?[qAw¼[1F$;%597*[2*C\HA>+#[ѽ "22)CD 6C*C QDk y@oA3Vb mDSOEPdQF#8ECutVAh;V;L"ýA)/WEKg-*#(络ɢ(ƢGK354*UrA$ Fq4$FRdHӸU>ǯ?+0lһ#Ft+u0D ,$SPTMҘ} @lC:+ӫJ<6M5t8%1GI=9=M9фͬ:%DMNQ.TUNL=1= ;%'|Ȥ$ɩqvӀº+L;>OO/:m6R1;6A7ӄ˓k=SCУU,Jj5CǜGБ6 OML<\)GN"&CάЪ(Aii@04 /pz P/? 9#,sEocDq|oFq} #깑%<2;'p @7҄)2/3r$r#W5IC2399.js:Kk,M:;t6El:0 9>HGS/t/nA\,pP* %C܂pD8׼tpC(;$*c J9\S0>(OcNCVd9ieq=(j̉rK{:"hc F6w"V ^NvlS^:Myn~S;6匜~r a\ Fe(G?,RqtB'Ęa1);HP^\/.jVi*atvZ¯;s-,/;w@D=8o$YR-gF98ќ\-OWg'9NSq:$WI2zz#>[e2CWtIhw5>ԌRVGCM$tRQ ("v5ٷšm|qPW*xU?jD6U*HLginҭMNzNICpwmb")VV]oE鏵-J`S]wyP*^l%63/,-՛g섓trYS<%|,b*BX`>^;khŬU6k0g; ܆Yۺu+S].jU9Q_ivqN}-:o62LEޙWQ^;y_PYo-s)<7``khַ8h吥gCcQ>p&8ngK!s7>L1EHb܌#,Kwia++.mA5!ꖫ:V9Yt|y"8E߰\ysffL*gfɥMHkT[Ch.vܬp R~:Mh?5Ajy~*Lq7jzfhwxeU"߳\֭9:,kTu!*|Vbs<]ܷn&+d~Wqf3&歳 x&58ygO؆:ޚ*H=bp[;A z[ 'ZWpu.+O:R4X7djY#.xbx}71w@]N_X2<#[>kN=>~G#Q{Q!t ={_w ߛуg;dO${kζg7G:lԆsv~p)>{Sћ>opo\wʈ؇nKVgvZO3,\U tEɥwٛt wglLY`#jvɽyś/K>5-KEz|˔9'MvKX]2':>CEqüQN Ϻ7'Mڹ5^Y]\2Tt#5Sy2>A~yۧS>1F 5-5K>wzi"A!]_Hn1gY *PCm/զwK(?+B7!͚ǹ~9sZۡwx]}Ik[Pޙ_ܹ;_ɥ_AU APHD. P<#Bb1X> n%I!9DU%y6aiD(oepZAhM&(C) ]QT*jXիrJJMXkEGZzo.{=H^-wWpUU6&L_z6kD<{I4ڝLރk:ίgL96q#ΤymCK7/U"?ѣ2Gfq{\s[̛z<ȷSI鼶"Ͳc(,K3CJ4@/l @4+2P92,0l?1#-ElKJ ƫ,d4L$A)MS'ƑHRTI҂m"c)J)?5N73.T܁lol89S{C39P*s5r5yt1DGpAOaREEN 8bR;GэY# 5 ejXՍ1]DZgMLVmHݷo[*wvLĐO{V]#fN.GocEX >K/wO<|[ꇹ=h'A[UuXTv;U$d6ASMX_eu]fټ!dB6}lVYh9GyMjkZU\ñlm\K{WFنL3)RM}8n!{^21;Jώ1Qϓc<`?b'Tf_{\w's|^ޔ R;^B ahZ΃]:.Icv ٬[lwOvYiv헩EO'36nhZ{ðo=l<<]!$_$Ϲ 9='(;.¿uJ#** ;ϥD HP4L"iؼ>^{ BD!Yg,";zace- 3 ӥWC#YJ&=DmIMm_[u>c`_RIM(5ܣT%:w.bI e`Dm`ԉqFqoE?KdP#÷ax0HXKJO؎YBF+m ǖJRRTr\IZbB"Ӛ&7H"TlI(Fxs̰\S~3x,ڃ3):c`2G*`flA%I,ӈIHh4Pi̝|feT+(IX&$K(p΍Lr&(3/^OKls^ PIgk)jG( [LUy%XjMθ: lR:t3H1Yy炄ךm[삕q'b%6c,D**]l&h쫢)-ixdS+mJ61|5%Q F&Tˁ6DݎuJFwַ`W6ըcs_sF*4_}1 u4-7rs7F)$*VNZD-ue;+c& бPY[R,Ѥvb2PN'_CnHmv(ۉj&sBݭpnީ{7N4¸jx^'dRwϏpMՐ/dWBۯuV^N['[%dn#hp>(e{aH귦,O ,ahPf&L\WK4DEKR1eMLkt3%ànq s];o.HڳߘmҨelq#=G3&YGT787ao酌GTnh(%R[}g*Y%J1itHYvtz{J̝xk-=w. rXʺQd8yNpݾ7Wq3뜟r\R;9}.c t+=!6 GhO:"(6$s*:+v}Z`M0"XFoG~t҅o8O oUn6$e'OYqkS_>s{YeP{6rM3PZ<(y=bvMNt#*uXD.AoJt-̿yvm}P}D(8P3t }l"m<[n\KLO6^U=go2ddV~Kǧry[+gB82\ :=Rؖ =ťk 3{q0]:{;!;Z;{z=:2=c>ckD!#̛ @:s?G8k< ?s"+J5R?۽2>r?4Cr2cq<64 \ JRpc &\?aC9m0- D4+v>Bs>3 ;P>{# "ِ? >1DTxDMǫG>-~ECgU>y;TV[% TZۻ[YE<^F# XT46 [lŌi9;9dI21+bt)?[;JHDܯ7O!;TRdS˃&\$#*F;?E=#PH<LJ|K qHLo}L˓stஜ@DNN L]#I#ŲkILcȗy.cN5㌿̻@zɘ B`ЈT6A8B)xr5cШ̊GGt.xW iLzy-OpMEJTIME N%HG+vON2,V9UdVKw+_,a|V# 24ܞ2<ܱ773+t:,u[#gm]D+7sH6]k Ki'jMᴻω}>vǥt8x,\k)hK,_lXk 7̾#obot@zT ژA .PC? t?DpLGLTZø1r0mtː/q4*GȎKG2j&92y)7T%rt4o1.d#6Mc9Cp³ )L.0販 L-0;ooCte(F+C R CR/=FOUEIXu&DrV`ͲY^JYr ܯmg27̖i eXM8s=:\}\cgRN.4NU_S8#B•[ U*5Q(]løF3- <&A<^Lk[dx;09]Xq1y~w{s6aź ld]-4Zr[,&h5wk-/ؗM6m33vzȗš}j`uUᙦ+fYU!UmtU -tXWCC]a/?i}y{8X[{/鲿mk l0:>n:rN's)ꞥsxۯ||#/:Q?IQ9WY/.$.> ;#uYR$}]?A`u͙9 .u CAy#Cj]Od|tko$=֍޳Lmn&?Q{}7%Xo9f:~.Ɔk2(N},p(U{r9ǓDsBS'eWuW |P B>͘+iJ7Eҩ+H9p%4R}xk.r҈E1c]EE0_bjO<ˋɎ5D٠fٮzq\h \}+LA H7:R.O] I$qɩ옠PO%d0nIy %dIOI gAQE<|:ty<9߄pyM#h&LNcK("l]ĺGy2т!EXl/Js4 +"9F 9L>~G%F INKܥgNԥmI[s޺8hg6X ]*UkO촚rK`NE!>_yU->65HS:XQO-+խC+1I^1 Q ۽2:joWNjRm%*Y-?>mh. 5L3\EḾ,\n+*-ÑٺiEHxc(Mԫ"*9 jH;Fr]'JXȬL%_u$<͙aF/_)njfFyY]qJBZK'n, ¸[#.MU߇{s60@VUsYuܫϐnLzHQidP-vYE̮taf,sP`,44V_~Ojb,tx>g:Y-.9a 3/-54V`LPΆno=FSDu]ZOܯ atFS)c3@xM_7ˌkͮc_q*v9MS_Zk6S#΂x;l6Џϩꮑ'FGk:Wwv]A4 :_%3f exFNϑ[ȔԔ oU;.W;$Rw˾Ίǟn:~zM~?}?S&JlGjD~^)ݽ{z|];eH^^x%'~.wӻ޸=$j(v`-, y'kQlOx\w*.EMNOA+lꦢE.Z\jjG&o~F|P,H)-.,:!OO/ LMP$od毰cN8ll nhALbRrNB /5gwLGKp>ήlt*-,[iĉ![.1C}nP -^$,ի6 /OǤ p0"Sl/0 0FOQ'| ν#]OLk8nk8 o!3[xFr2PSA+: 5/Qt55,Rgn5'E5O`l7W?sU!V37Ai*L#44 YUM4'Ҋmԗ3-bqcm(߭{R\P F -r[ I'Q!9ufbJEU3RO;t[[N|Sw(;[W_Րc3sy:o@;?N<4:UF;YD9M9#rgkXguu+Z<\=5/½{X[}<\Q|?|C ;yVjEmxH>kQq@-yx={ ϳY}=Mv#;eE{^Տr]%W!z;ᾱ^~'_ՠZ/^EHb>[_U^!_W%R'}ރuT6{={AK2  AH4 tBH,j"1>-c2iG)I)_3E%щu9\5L(tY.8Sh 7;*LNYQ՚"Pi{ElX_Rs][xo{01`P}T Ltҩ۝Qi6n+ZT{jot|gV;=s>Ҥ>Ȼ:NP+AD P+ A .CNJ «>5?6;E.XEJklw73Gmo 5t~n<2R"GCҷ32dF幯г*?)kΊ /t6> $H 4p={IAP}AI3 8SBUIq1SÍlE1dI+s"2-ƱW"]&֕ܫ_H=xV՛$Y{*XM_6JH|/9*>\B3+sr7@ 9ӷCO\L)Ԅ,^ԽQWҗJz`XSӞ1OITACTNVP[bGU,W.]]pe{f5X66Xcp>iəuov{cWeR6qhZğ/S\Վ_>O:17wm.CvSBkp[sad!9d^-QhWD6=.6Ց˺Uiguuݧ>zn0v:;_6`}mE;P$~{?5XpX7تC9B;yr гdC`xfӮ"|ѕD[\XqquA}\lpMsp8H'`N Axz!R vr&<6d[ n#Hx?jɘxRK× dNI,!8nAP]~V 3bF6IS F⋒G4{xѽGW $R*g;8<1w9 #]rƮ2ݦvt { lGg,]RP#Ը9{k\]5J F=avv\P[#RoVǛP zIyqqV+T0O,-A%+e]yx~ď/%ޯz^QzB]EW|Dj6lOeR:|ٗ4g#6Lj?amO6ۛk8O!q3JJY 9x]:{m;t˙"RcIaAǹ(=O-۱2·D{H_d9#΅δ誃 M8sr`gͳk΍5IE(%^ޒΠ;)Q6HܷB5[U C茪\:4o]ȼ_}&G:lKpg=fm1Q1&gg9KI3vt)]j׫BM5|viG$:1Zk^jF|7aeMY,'_xk(]_ckvܖr{!7>_U#8m//3[JhǠB{[8mofᇹ9[O']^rw1pZػޟeX^ƍ=|g$5㸝Z&kϫaG'O9g?P!z=30{cڦKxBὡLӻ@ y( *KTÇ,K8Y/K8|(Ӿ#\,;#;Yk?;ɩSs*[9B9ж4D(*4jj#3q9=oL,= *KsBGت&c4l:=9>49$گ@;3N8 $Ak粫~]!n><3';k2/DJA  8 A0\& !Ј2'"QXtƢ9CId3H*vߟ\9Dʺ>{}7Rc̰t%xSw0r-!T,\Zi(D0p-~C4QT)5WXR=fE^2őIZeekf]QmofUͅYu쯑ۙmזr؆-ux}\lzޘ]twvlm3Otw Pn뗆Bs{ |5\o:!wz~kV竟+jx% Gf6t29Mhm}6iWxf*j̛e=>>f+<Nrl~_hfy`GQp_ _L59S3<ó.2SE!g`ü6R;hHxn T뙳0 4NKƂewrzm< PŽ=Ca.1?~I} P@H[zS I?Dic5+r2.@+Cı)%}gDJ\T}WoTrF+$$ӬH{ŤֻZ녔q:RFR`\B$Jecq$jόExIGDU=mysJjF5AX8Rd#*J;mH9dHSH8'zU<9&ajKH*r+J"k%C>:[KG0tƤ ]0Kt}V0GJi\r,l^+=~ &ej콱+Mh&_@X b3wҐ5rbj\mm O`|u Bu=~WU氢Rm$rDe~wp;7P(KlIbqV #!LN(^N6QQХ !GF ')!# ,BeΒ+(¬" #=iRXH&pM p亱&Q.莒1nVzMҳ)1mAOSϵ*o r*ܾ5I, B2p3q*5#4e3%m1I0N@3r9y%N&Q<rNcm;W"0.\1Ƣ*+S{/'u+7m}6 uG/8'!C 93e[.J#$1Q:rCD3=iVro&;Fγ%03P=2S ` '3 +6R2*GA>n* 67++QEO5#BB!CL%Mљ-tO s3 aDQ}:0@I0Q%O$ ;EPPuEb- sFMHIJҚ5qhnK~VWt!SXtX09\L[Nՠc\9E[IHgeU[vs;O:c 5&Ե*jjr4'U-aA^e34 oo t&6iWMVQc6O5tNO{FNtnZΓePIeNb%'RW& 2wq^j)w^ԝL7pU?U?uVV@A_Bu0W-*5iA87kW7#jw#xJxTKvQr6QE TmoTU:x(:Eζ/}X&: SRYJx5\wJ;}[zؓi5KLͱzw {6: Ǹa:w}լ-:)#yf|8]m{'0ݹy޺Q{ve1 Bg[{VEĐ{&{zy[݁{iu>o{A_BM8bcXNoʓs<'qy˸=]Efm÷̜1Cgs9Y=beWZuNF1(sƐn{uڧ܁cǝ%Z7;[MMɇ!yv;<u|+oWy5ͻ˘c};0操]7ԇ/w}_SֵZى[ގ黍}sѯ/"^'Iw^.彗6O^lz>[戲 /ҧkm e]똼Y[ͼ;pVM Q>}_Q4[0!?QI y-* `HL. @ؔ&Dh27c8D$<+K!2Exs:ϧ-}3Qi)5MS NUU\Wo^YD0}nsڬ3봢u_d*ŚM`!= !xc8fv_4<^gIehsu44tj/JR1&G̪cExFSsjT)jdz}^̲r;{{s}4L/ Jl00{60c4Al*@pSK/CHδ- 11K!m[Zz(6k81lJv2`4y$;D'H.dҵ&RuasYݞuVtN73ZٖccNS6Y{(TjLybLvoNe!6߫kl*b7CC])Rۀ^Px-EBm D8+]FGp9'ӿ>TWsdI9gZ丛\9:dƇ`sDu /)^xV볷ķUOܿn[~Ǽ鄯OtOw<[Uſ|?_S}ƽOuNm@ 0u.| eּX IvpQp;e`Wsj:!j}4AT1<0=n|[44zA?W|5>hE|1wvXCE'\Cu10 "XJ1w*c"45 F!:gUrL{)Ax5WvvPFxM$f߀+5bw.{XT۵bn*7vuرbkh."8-L\lU8Ek 9Ci5S D`cʓgjn2neϨ;m]`|8^z!&R?^7К#h=wnd'WɌYyQys ӭ PD2 Cap|F- Ģј,r7#7%G \~MHe $AM1lc3gPp CQ*NMU RFU9j\Wkv%EYVekm;svK׋U~0[alL:y6|Y2Hf9gwSr׫!l"}+"`-~Cn"(%fOIbzl^bҹq;%cQP9=N_̙K,һ?jI4M߼e֮ޱ ش@P, m4ҷ3(2TB0o BqCg;&0N 5L[ 1s~D[z2 8FQ{Gnoԛ'*/9{;i?O"J)9ˮ.@s0ϊy4Kr8K +:6M ϔ=.1CrEt H1r,CO9ьE%#0=T)Uq UTiTHQOQS-7X s`WlUXM&P+=]ڪkٓBqK5]‚[k*s@۳KPݷ%mN7s `KAE]t!$TՍ\Vtx}S,#dV%AZEGQ5XY\Ӫic ~7]7%US9Pg)s@ȟڎ7]Vvjk2Z~;6O߭|/ Wd]t_WrO`g̩J.Y:4<` rՉv-ﴥZ` 5i]kp/%^wRB[l-d@Љ=AnD؝#oE(p_Nj,m1@fM("rO)( +FHs(K󲃰g'U!c_prGwrȈa$#͈ô d|l>)CnGFeDPR+g $u?*1 zģSN&+K_g1=># }g1bGäiF#4&V@$4h"OG$OL!E!!JW\$!?28Ǐ;Hj*T& toKJ-E |/ lTk@5X=r}iwgCj& ζA nTF$@*TB%U$9-dk]c|*ъHU,P2lj(zFP|tޢT'A3歁thkqeޗSgQ*Tv?hRJ{U9R4:y)CNY&MU8s-\B[x-_HarJ⸖t-<8U]uo%OS"]=w2phU^+Eo .%}1݊EJY!@k/Iy5Ӫ3K/y3We іnh6Jzдjl f#leWRԽ*7,}t҅PyRaN/g(AHewy=J_{ק﵇*&eCM+SMC9n(vgSs~ƚ?H(qUaJcGnQ!u}-@(2涞 ,q ǫֿNMԷq*~xx>F $v%ۭ7 y//7C(m (6s CUAv힊b<}#zi%j h5OߜYM:vR{em-iW.n#WwVW6L !.}zxh<+m+^c%1wls>'ѼwP}=ooݮz]?/zrbJk;7ֲ ]{ڰ%uw>˓lȤγj ~:Rz":6[˧'_7)LΏZ-.OXKDDa ,OxՎKlz8{ lnI $.m!PdðH@O2Q\m k %N0&NR`oh, pܛp2 n#LM`zBF~~+D&FaĢۑ-O`I

CHү??9T4е+s?ԡ8m"qu5y9KQA8p#Cqh$#Cu=1%zP]6Ge}Hd\ѹ6 iTj |U2Vv]Qjs_9g4TJbTAhUkeq,ʹ[YvSYdZU_'wiOeu[pwzw4j5gT5!^6ȑMTv v`3ks40gUQhA8j7k9rvV#BwZIuV&&$.ntY:W d4^)pPK)olCf Cg(r|Q Tq;r8]};5iJ4PU{i+u+WtEQtp̖jM'w7w0QWsNx*NynP}cyjԺ83USx_usR~qu{rT WiKK8mUuA6m#+!u4wH98Skgvd xio99Y*&7mC KYO1Z<]81ooy=oX6w\qTsf1dxqr f s-m91i1~Bdgv:9<!o[s1ޡ5k67ˁ1ykwXy yy:yxe8SKyryyuwc-|~iI Ob5lvYX Yx7cPcc2yX18۟ӌڝU]W9xS7sM =@QBv4/B0ZIU\q)~9S؂aueG:Ds-tRM n8H7Q&*Dz=r[O|ɪڱףz{t:͆ ypqYWuBpVkY"cٜFw)m{w[!9鹹Z[Ղ:H[Ǫ[K2+1N˵|a[xs}!++'wAwm BYK.[z;G7Š;{9ƹS蛴.U)ewΉd| };_ZɆ]k5< 2ǚ[:;C4ӎh5z8".X!t; /{N5={wg2{YI-be3x0];?ڿ_q4}~IqX]ܟcwKT7~} PFޓ<єɕ)מݖpQ3؟Bk#ݩ>8  A@D. "N)hn9GI%Io\Q- ]1&iw-Of)QbD"KSh|JD*(:`f8W"6*zf*)6ڈFcCdW ǰ M4!ob`3<,^zK A=.MtKixT~%°GkәʢP=3vsFY{{3{<&~Ns%O>2"LKf۵-V($L 6PBBAУyA#4 E$TN3R'%]DitgDqӕD!Hr$<3>nɏ/;J-IO Nܝ+Jr3M'.L,6Jڶ.9@0P!2 ϱ}̵TQF- QDE%E9Bme!F MEծ57N.U+ZVs$]toT?M`Gҭ{16Y;ٶL:+vU>r|򮦹u8_-=[YY.Ϋ;uZ'/}7_WW\v]GEeݩ?ΐ=o ѴwDU՗!^Gp^ V[ }3nٳF?p usf.:v;]Ft:y`3xy s.T }%*F!<טCnl9>_ 0HϿ'Hp/1߄;uPbUs IQq!K 8 SkW;¸S3NpGy3j9b'6zh/%TZ1J)ŃuQo*"4 P1IЬ{/C'"^,h&\db|9*BzI=DI*cAHR$;iǹ4frԞuҺK5!LLPeeBlӉcHi|ڛBSL3x?gZ}Q6N) fzEZ=;{Nd "tfZ,"Hjit֧ԗ8&́X4I,*ݑTM*؊c#g|,MqZcT$`~Uj)ŶÈmrj= 2>] XrqL5Pu]uodrE[AKז^gd*[N 6$bW+D:m|T:M @0d6 C(VF"1XZ/GM%ȡM/J9\a-M#456JgtuD"{AӤJ>UmriUTņgZmVeɮ6{uC/x`/˭iܫ81LNNu7Ȯk5vgiX6W^r@%BOҸ:t xɔəqsDP;TSEWm5nUֻ^mcv?g}_ SJ6{ ZcT5BA* C0|*C) %t<شC!$(QT'$,o6ѬSҔ .|ȳz24Jk#KC.08#s:+?R580$ʷM;oO1Eϱa@FJij @+ 6R44Eұ/DS44H5u-U%;EtCU_͏7#V(}ZHnZIHQrff2MnX>yf~TÜ|;J7f`;9~^XzǗ]B>^G씬]aGtүl-RUYUl;dcVJ]Vd.fVqjhy-7ziݥb8vHֲfE3a bdgwtR;Js8c@=n|t-3Ջwf:gD}C5.ZKz[~U-" 3?w_vH[j˫T5s][r03kvΖlvnlqݺ5iw5ko49[$'Z7G}C0{cbH4'/:wMZzq)Ӏ 3Wήq-ۛ7bɮh)3>{ϰ{{Y-l5\}֝D>O,eR;exVu%E<DePkLՄb`aWgqQW/gB]|wO~V_.\C$[K }<{ß?GɲFު?z(mX3tMN X.&*nzKoO!&ot+Oۭ<oʲrfw8R 8ӮzGj%0n}n$3r駠&:-,~PS :n PC 0,ϫY.. d|, K- .) Ѐ ?/ȍP q8l}/  I"0)0HI.8p h.Ew] 0|p~gNi wp-1  8T. nǏI<PRzVLA$U(OJj9q/niQ i & 1.j0ɢ 11-U~Qp&p6MZ0%[ #2qp2(z҃\125Ϟ(j;!P$U"0KUC-3"WW& %R0k*  M ҎQ06raq-1qK 172d2p*IL_-qnlLgC,Q$RA*MR0+. e&ѹ//&ˏ;( 19xQ[;3qI/&Q3R)2v31Q 3 m SCH Np\"%"26>ؘi!27-dz{D-8Pw@4/<20w9:0C'=Sڪԫ3<k3a.D۲sM@]( @$"Y@$NtT-c$T)?CtLD;&([%}$lTU1419N-Eo/E52iMSl9Ehu3H 5+#TpYR15u*pQSeOK R5U/L4/LtV4MCӓ)[M;A;QNs: tOq!NnF uEfbQ5.U4E+'55--t;@%J-/ IS\cRU!(8B)VUJ_WPLDRGQ4DYs3# XEY;s7X/=T<`5u>KUW^UY2euS"O6 \]R8TkT5a6gc_5uh 9/MmQOUn{[iU3GD+Y6+j%(lV;G~ Gԇ"t-Q{?2!mQѐVf=5-AAUYg4KquU֓8 r,Ww(|VBx6`;cv PY4L#XsOP'in#W,%zv!pwqrΖW6ZMǓ6w^WAmTf,^ r,׹'{cmwbs11cV}_~ wl7]v|Z/q6krwrB6Ug5ωpYo2o5\wfwIqtwzKބ4I|T"V?Lm/Dt7Տ}} 朷k+F5чG9&)@x neeReO8@X?6SezO]Crt!qC$QՅaX趿ukmFai)RFTS=b~ω oPa-㷟YY?pwxryJxhX_aTE[ٓXᎹyt39w|mXqusCWVs%:jcWXtwvֹؖB@wYSYafIPژ/,pwA7ϚQ*055hRokT>MUyMؽܛպEYc=O8=SYwal5g~~Z.Y`޵ٗA'F>ŜUAJH훃ܣޙ \K+}ߞ<ֹ?<'/C\~e_v׉B^ߟɵ7> ApT. pH2%EXb9BPy zI$ǤXA*Gei5My=N%GhLzEB t"ϪjfYSU]oݬ(|_4)*W&FvJ,#%KfS&{eY$_Gyocbzso4qqW/s:BR.KMSo@/'cZ+ߢ| 5O.!kģnKnL~KgBp.8p$p,0>ǧP1 ]BͪrAʛvFp %lHGQ˟$#H댊'҄Ij)L-K-I.4P2;0+̹AIGͤm14,B- ]!UI&ti1EIqbPtkPU$SuJyVcXKΝe:=,[@O۽W36=6 웽R:سzf֓~Y639KҬm:3ӻ>S _?6Tru]57T=QxUw"Eu!QxXvR5WѥwwbX~%VVyn9Ғ[ccyJevm3ZfefpmcW恑gVq8=ɥCL1B_4z^Q6J"xix^F^|_p sa^:{Wɋ{&KXک{pg3L9g͜|[9esϤfS7OSѫ۔#u{jѵ'w}]jvRuQ9ئ{Y?N]?p0?~IV\=[8DT޻"m( z<|cl,<! #(O91Xz7OzhqYL:7 V;e xcJ? kQBD_W}mLA(0)W3QKKW;t NRzܯycԧ)w2ȢzS^<È8]$Aܒ:|jw=O^<ߧ~bzJf?8 V2BX*L?L4A0J@[4Ф Eqk!M9o\fƎ8J;ѻ>NHjDr;2/Tҫ"Ib-*ܯ 4KS<5͓l0 #_8>t΋|E+C1Q>(00>4EC?A4єLuK.7$4<2O!T]kT2e]TUWNyTKol2+j4[W|aYkLlLSv?;tdQBt+p4-LtYOD-w Sn[+EД~=Edؖ_U׎կ!͍G]+ZL5Bʏ}a9U/׍a_cag` &̓>lqޔKi ևP4^_z6%㦨Q?k9ݷ4nWW>eY/Zf>9*yKfQq Y{{_1V2YDFyg$Q/i3+Y>.fq?(b[LjHc…QZF/l_Q]F ZS2B{"!̨dR1QUiuqUv3;Yku|`&D*N¹YzUrt=WZ#4d۫e;7-stKQY.XN!&=ç4}Uw]IEkJ'מڨj}W{WUTLׁſs2^ \Qhj:IEM v'8[,Ƹ2be2=Slfj`+09WA % kMӺ2]ymqxb=^bH{/Uj#brwz+{ B,,˝fhey2^Pzk)dlk'`MK5Cwa- dƷ8jIH-/ꎫ֞Cw',;l7]-v Im<꣟'O_˙w:ʖɫ:?&v;\j߼lۺk7.hĶ灖m}qŔK>-*ܙ.U|{pfS6#ڀdɛs\>+:[̷V՗Komue̶֏Stsԣ cIe )ͣiK@f6xL>}֗usiRmo~(ϓ-MF.ro6Oo$pB3E8L4B-<.W,2=ESH-A62r3G@9H7i@-&ABEhH*B*1qw'wB =!c!?tK31E4G[ET-G2sb>tYNDSJ0H P@mK&) jME9790OJ6MB:-HbACL *qMQ44=pJcP11G%UNjYCH]PՌ\Qk(!R4N{R&3ߴYAKᔒ=MX5PT=TMtqwN3n]^mOu>?X uU5:s@QVԡ&)0(U0C9Krb%S@PP\]2'WT{3yU UEvWT]V[,_]uUG_g`g8i4acu?IIեboJMoJ1T5(+\f>h24Teȫ.%UTe=m=1hQH1 WѿWxm$vO`um_5c&U\QCԉ0'-9IA)ӥS W#lVvTufQAn5fogW,e6wwPma6jjW@]r0v)ikS//@-[[6!3S35c7WwvTfِwhv{jf4w}_W78lvZkvdHӵs5GLWK9y||[}4u-pt_xv߀i~x7ux]A}xwwW!es.yad/07Zx eTLl5i7ba$b񋎑tiMVہW]qR-iiK+npYFVYW4knM8{nqpQW87zC%R mzԗXOVCc8ƣ˄h8+PHo%w^v7y<5XFxpUO؁~wq/bUzx-1W[hAc}r dW8˹PVg6T=co2~Yi4 F},YyۙzRY7/hy%ױ6/wH1uQ}CZo"˝4|X[5T~8Z+Yw٦ق 9:r'rGDG-r9kz ?d3'JQU"vGgMc#Z~uVxYr6r_XZmzS9=%嬄78?J͓ty;:cZE1{l{4Zb}:aI:i箹Dz_/_fgy:%:D qZS[@qGK[ =Z/)s&i>ՙ V0 韧lռmWϚ)}}HZi)ۛ?=[7J;Io  ? ?n ?86 ?>>(1?=S?hs H?"$,2k&#b!@,\"dMtGsW*background@2x.pngtiffutil v301.1 HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmgottcode-kapow-350ecea/mac_deploy.sh000077500000000000000000000064521514263554100176200ustar00rootroot00000000000000#!/bin/bash APP='Kapow' BUNDLE="$APP.app" VERSION='1.7.0' # Locate deployment script BIN_DIR=$(pwd) cd $(dirname "${BASH_SOURCE[0]}") # Remove any previous disk folder or DMG echo -n 'Preparing... ' rm -f "${APP}_$VERSION.dmg" if [ -e "/Volumes/$APP" ]; then hdiutil detach -quiet "/Volumes/$APP" fi rm -Rf "$APP" echo 'Done' # Create disk folder echo -n 'Copying application bundle... ' mkdir "$APP" cp -Rf "${BIN_DIR}/${BUNDLE}" "$APP/" strip "$APP/$BUNDLE/Contents/MacOS/$APP" cp COPYING "$APP/License.txt" echo 'Done' # Create ReadMe echo -n 'Creating ReadMe... ' cp README "$APP/Read Me.txt" echo >> "$APP/Read Me.txt" echo >> "$APP/Read Me.txt" echo 'CREDITS' >> "$APP/Read Me.txt" echo '=======' >> "$APP/Read Me.txt" echo >> "$APP/Read Me.txt" cat CREDITS >> "$APP/Read Me.txt" echo >> "$APP/Read Me.txt" echo >> "$APP/Read Me.txt" echo 'NEWS' >> "$APP/Read Me.txt" echo '====' >> "$APP/Read Me.txt" echo >> "$APP/Read Me.txt" cat ChangeLog >> "$APP/Read Me.txt" echo 'Done' # Copy Qt translations echo -n 'Copying Qt translations... ' TRANSLATIONS="$APP/$BUNDLE/Contents/Resources/translations" cp $QTDIR/translations/qt_* "$TRANSLATIONS" cp $QTDIR/translations/qtbase_* "$TRANSLATIONS" rm -f $TRANSLATIONS/qt_help_* echo 'Done' # Copy frameworks and plugins echo -n 'Copying frameworks and plugins... ' macdeployqt "$APP/$BUNDLE" rm -Rf "$APP/$BUNDLE/Contents/Frameworks/QtSvg.framework" rm -Rf "$APP/$BUNDLE/Contents/PlugIns/iconengines" rm -Rf "$APP/$BUNDLE/Contents/PlugIns/imageformats" echo 'Done' # Copy background echo -n 'Copying background... ' mkdir "$APP/.background" cp mac/background.tiff "$APP/.background/background.tiff" echo 'Done' # Create disk image echo -n 'Creating disk image... ' hdiutil create -quiet -srcfolder "$APP" -volname "$APP" -fs HFS+ -format UDRW 'temp.dmg' echo 'Done' echo -n 'Configuring disk image... ' hdiutil attach -quiet -readwrite -noverify -noautoopen 'temp.dmg' echo ' tell application "Finder" tell disk "'$APP'" open tell container window set the bounds to {400, 100, 949, 458} set current view to icon view set toolbar visible to false set statusbar visible to true set the bounds to {400, 100, 800, 460} end tell set viewOptions to the icon view options of container window tell viewOptions set arrangement to not arranged set icon size to 80 set label position to bottom set shows icon preview to true set shows item info to false end tell set background picture of viewOptions to file ".background:background.tiff" make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} set position of item "'$BUNDLE'" of container window to {90, 90} set position of item "Applications" of container window to {310, 90} set position of item "Read Me.txt" of container window to {140, 215} set position of item "License.txt" of container window to {260, 215} close open update without registering applications delay 5 end tell end tell ' | osascript chmod -Rf go-w "/Volumes/$APP" >& /dev/null sync hdiutil detach -quiet "/Volumes/$APP" echo 'Done' echo -n 'Compressing disk image... ' hdiutil convert -quiet 'temp.dmg' -format UDBZ -o "${APP}_${VERSION}.dmg" rm -f temp.dmg echo 'Done' # Clean up disk folder echo -n 'Cleaning up... ' rm -Rf "$APP" echo 'Done' gottcode-kapow-350ecea/src/000077500000000000000000000000001514263554100157255ustar00rootroot00000000000000gottcode-kapow-350ecea/src/3rdparty/000077500000000000000000000000001514263554100174755ustar00rootroot00000000000000gottcode-kapow-350ecea/src/3rdparty/kdsingleapplication/000077500000000000000000000000001514263554100235215ustar00rootroot00000000000000gottcode-kapow-350ecea/src/3rdparty/kdsingleapplication/KDSingleApplication000066400000000000000000000000411514263554100272630ustar00rootroot00000000000000#include "kdsingleapplication.h" gottcode-kapow-350ecea/src/3rdparty/kdsingleapplication/kdsingleapplication.cpp000066400000000000000000000056251514263554100302610ustar00rootroot00000000000000/* This file is part of KDSingleApplication. SPDX-FileCopyrightText: 2019 Klarälvdalens Datakonsult AB, a KDAB Group company SPDX-License-Identifier: MIT Contact KDAB at for commercial licensing options. */ #include "kdsingleapplication.h" #include #include // TODO: make this pluggable. #include "kdsingleapplication_localsocket_p.h" // Avoiding dragging in Qt private APIs for now, so this does not inherit // from QObjectPrivate. class KDSingleApplicationPrivate { public: explicit KDSingleApplicationPrivate(const QString &name, KDSingleApplication::Options options, KDSingleApplication *q); QString name() const { return m_name; } bool isPrimaryInstance() const { return m_impl.isPrimaryInstance(); } bool sendMessage(const QByteArray &message, int timeout) { return m_impl.sendMessage(message, timeout); } private: Q_DECLARE_PUBLIC(KDSingleApplication) KDSingleApplication *q_ptr; QString m_name; KDSingleApplicationLocalSocket m_impl; }; KDSingleApplicationPrivate::KDSingleApplicationPrivate(const QString &name, KDSingleApplication::Options options, KDSingleApplication *q) : q_ptr(q) , m_name(name) , m_impl(name, options) { if (Q_UNLIKELY(name.isEmpty())) qFatal("KDSingleApplication requires a non-empty application name"); if (isPrimaryInstance()) { QObject::connect(&m_impl, &KDSingleApplicationLocalSocket::messageReceived, q, &KDSingleApplication::messageReceived); } } static QString extractExecutableName(const QString &applicationFilePath) { return QFileInfo(applicationFilePath).fileName(); } KDSingleApplication::KDSingleApplication(QObject *parent) : KDSingleApplication(extractExecutableName(QCoreApplication::applicationFilePath()), parent) { } KDSingleApplication::KDSingleApplication(const QString &name, QObject *parent) : QObject(parent) , d_ptr(new KDSingleApplicationPrivate(name, Option::IncludeUsernameInSocketName | Option::IncludeSessionInSocketName, this)) { } KDSingleApplication::KDSingleApplication(const QString &name, Options options, QObject *parent) : QObject(parent) , d_ptr(new KDSingleApplicationPrivate(name, options, this)) { } QString KDSingleApplication::name() const { Q_D(const KDSingleApplication); return d->name(); } bool KDSingleApplication::isPrimaryInstance() const { Q_D(const KDSingleApplication); return d->isPrimaryInstance(); } bool KDSingleApplication::sendMessage(const QByteArray &message) { return sendMessageWithTimeout(message, 5000); } bool KDSingleApplication::sendMessageWithTimeout(const QByteArray &message, int timeout) { Q_ASSERT(!isPrimaryInstance()); Q_D(KDSingleApplication); return d->sendMessage(message, timeout); } KDSingleApplication::~KDSingleApplication() = default; gottcode-kapow-350ecea/src/3rdparty/kdsingleapplication/kdsingleapplication.h000066400000000000000000000034461514263554100277250ustar00rootroot00000000000000/* This file is part of KDSingleApplication. SPDX-FileCopyrightText: 2019 Klarälvdalens Datakonsult AB, a KDAB Group company SPDX-License-Identifier: MIT Contact KDAB at for commercial licensing options. */ #ifndef KDSINGLEAPPLICATION_H #define KDSINGLEAPPLICATION_H #include #include #include #include "kdsingleapplication_lib.h" class KDSingleApplicationPrivate; class KDSINGLEAPPLICATION_EXPORT KDSingleApplication : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name CONSTANT) Q_PROPERTY(bool isPrimaryInstance READ isPrimaryInstance CONSTANT) public: // IncludeUsernameInSocketName - Include the username in the socket name. // IncludeSessionInSocketName - Include the graphical session in the socket name. enum class Option { None = 0x0, IncludeUsernameInSocketName = 0x1, IncludeSessionInSocketName = 0x2, }; Q_DECLARE_FLAGS(Options, Option) explicit KDSingleApplication(QObject *parent = nullptr); explicit KDSingleApplication(const QString &name, QObject *parent = nullptr); explicit KDSingleApplication(const QString &name, Options options, QObject *parent = nullptr); ~KDSingleApplication(); QString name() const; bool isPrimaryInstance() const; public Q_SLOTS: // avoid default arguments and overloads, as they don't mix with connections bool sendMessage(const QByteArray &message); bool sendMessageWithTimeout(const QByteArray &message, int timeout); Q_SIGNALS: void messageReceived(const QByteArray &message); private: Q_DECLARE_PRIVATE(KDSingleApplication) std::unique_ptr d_ptr; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KDSingleApplication::Options) #endif // KDSINGLEAPPLICATION_H gottcode-kapow-350ecea/src/3rdparty/kdsingleapplication/kdsingleapplication_lib.h000066400000000000000000000011611514263554100305430ustar00rootroot00000000000000/* This file is part of KDSingleApplication. SPDX-FileCopyrightText: 2019 Klarälvdalens Datakonsult AB, a KDAB Group company SPDX-License-Identifier: MIT Contact KDAB at for commercial licensing options. */ #ifndef KDSINGLEAPPLICATION_LIB_H #define KDSINGLEAPPLICATION_LIB_H #include #if defined(KDSINGLEAPPLICATION_STATIC_BUILD) #define KDSINGLEAPPLICATION_EXPORT #elif defined(KDSINGLEAPPLICATION_SHARED_BUILD) #define KDSINGLEAPPLICATION_EXPORT Q_DECL_EXPORT #else #define KDSINGLEAPPLICATION_EXPORT Q_DECL_IMPORT #endif #endif // KDSINGLEAPPLICATION_LIB_H gottcode-kapow-350ecea/src/3rdparty/kdsingleapplication/kdsingleapplication_localsocket.cpp000066400000000000000000000302551514263554100326410ustar00rootroot00000000000000/* This file is part of KDSingleApplication. SPDX-FileCopyrightText: 2019 Klarälvdalens Datakonsult AB, a KDAB Group company SPDX-License-Identifier: MIT Contact KDAB at for commercial licensing options. */ #include "kdsingleapplication_localsocket_p.h" #include #include #include #include #include #include #include #include #include #include #include #if defined(Q_OS_UNIX) // for ::getuid() #include #include #include #include #endif #if defined(Q_OS_WIN) #include #include #endif #include "kdsingleapplication.h" static const auto LOCALSOCKET_CONNECTION_TIMEOUT = std::chrono::seconds(5); static const char LOCALSOCKET_PROTOCOL_VERSION = 2; Q_LOGGING_CATEGORY(kdsaLocalSocket, "kdsingleapplication.localsocket", QtWarningMsg); KDSingleApplicationLocalSocket::KDSingleApplicationLocalSocket(const QString &name, KDSingleApplication::Options options, QObject *parent) : QObject(parent) { /* cppcheck-suppress useInitializationList */ m_socketName = QStringLiteral("kdsingleapp"); QString userName; QString sessionId; #if defined(Q_OS_UNIX) // Make sure the socket name does not exceed the size of sockaddr_un.sun_path constexpr int maxSocketNameLength = sizeof(sockaddr_un::sun_path) - 1; const int tempPathLength = QDir::cleanPath(QDir::tempPath()).length() + 1; QString alternativeUserName; if (options.testFlag(KDSingleApplication::Option::IncludeUsernameInSocketName)) { uid_t uid = ::getuid(); alternativeUserName = QString::number(uid); struct passwd *pw = ::getpwuid(uid); userName = pw ? QString::fromUtf8(pw->pw_name) : alternativeUserName; } if (options.testFlag(KDSingleApplication::Option::IncludeSessionInSocketName)) sessionId = qEnvironmentVariable("XDG_SESSION_ID"); int socketNameLength = tempPathLength + m_socketName.length() + 1 + name.length() + 1 + userName.length(); if (options.testFlag(KDSingleApplication::Option::IncludeSessionInSocketName) && !sessionId.isEmpty()) socketNameLength += sessionId.length() + 1; if (socketNameLength > maxSocketNameLength) userName = alternativeUserName; #elif defined(Q_OS_WIN) constexpr int maxSocketNameLength = MAX_PATH - 1; const int tempPathLength = 16; // "\\.\pipe\LOCAL\" // I'm not sure of a "global session identifier" on Windows; are // multiple logins from the same user a possibility? For now, following this: // https://docs.microsoft.com/en-us/windows/desktop/devnotes/getting-the-session-id-of-the-current-process if (options.testFlag(KDSingleApplication::Option::IncludeUsernameInSocketName)) { DWORD usernameLen = UNLEN + 1; wchar_t username[UNLEN + 1]; if (GetUserNameW(username, &usernameLen)) userName = QString::fromWCharArray(username); } if (options.testFlag(KDSingleApplication::Option::IncludeSessionInSocketName)) { DWORD pSessionId; BOOL haveSessionId = ProcessIdToSessionId(GetCurrentProcessId(), &pSessionId); if (haveSessionId) sessionId = QString::number(pSessionId); } #else #error "KDSingleApplication has not been ported to this platform" #endif if (options.testFlag(KDSingleApplication::Option::IncludeUsernameInSocketName) && !userName.isEmpty()) { m_socketName += QStringLiteral("-"); m_socketName += userName; } if (options.testFlag(KDSingleApplication::Option::IncludeSessionInSocketName) && !sessionId.isEmpty()) { m_socketName += QStringLiteral("-"); m_socketName += sessionId; } m_socketName += QStringLiteral("-"); m_socketName += name; int fullSocketNameLength = tempPathLength + m_socketName.length(); #if defined(Q_OS_LINUX) || defined(Q_OS_QNX) fullSocketNameLength += 1; // PlatformSupportsAbstractNamespace, see qlocalserver_unix.cpp #endif if (fullSocketNameLength > maxSocketNameLength) { qCDebug(kdsaLocalSocket) << "Chopping socket name because it is longer than" << maxSocketNameLength; m_socketName.chop(fullSocketNameLength - maxSocketNameLength); } const QString lockFilePath = QDir::tempPath() + QLatin1Char('/') + m_socketName + QLatin1String(".lock"); qCDebug(kdsaLocalSocket) << "Socket name is" << m_socketName; qCDebug(kdsaLocalSocket) << "Lock file path is" << lockFilePath; std::unique_ptr lockFile(new QLockFile(lockFilePath)); lockFile->setStaleLockTime(0); if (!lockFile->tryLock()) { // someone else has the lock => we're secondary qCDebug(kdsaLocalSocket) << "Secondary instance"; return; } qCDebug(kdsaLocalSocket) << "Primary instance"; std::unique_ptr server = std::make_unique(); if (!server->listen(m_socketName)) { // maybe the primary crashed, leaving a stale socket; delete it and try again QLocalServer::removeServer(m_socketName); if (!server->listen(m_socketName)) { // TODO: better error handling. qWarning("KDSingleApplication: unable to make the primary instance listen on %ls: %ls", qUtf16Printable(m_socketName), qUtf16Printable(server->errorString())); return; } } connect(server.get(), &QLocalServer::newConnection, this, &KDSingleApplicationLocalSocket::handleNewConnection); m_lockFile = std::move(lockFile); m_localServer = std::move(server); } KDSingleApplicationLocalSocket::~KDSingleApplicationLocalSocket() = default; bool KDSingleApplicationLocalSocket::isPrimaryInstance() const { return m_localServer != nullptr; } bool KDSingleApplicationLocalSocket::sendMessage(const QByteArray &message, int timeout) { Q_ASSERT(!isPrimaryInstance()); QLocalSocket socket; qCDebug(kdsaLocalSocket) << "Preparing to send message" << message << "with timeout" << timeout; QDeadlineTimer deadline(timeout); // There is an inherent race here with the setup of the server side. // Even if the socket lock is held by the server, the server may not // be listening yet. So this connection may fail; keep retrying // until we hit the timeout. do { socket.connectToServer(m_socketName); if (socket.waitForConnected(deadline.remainingTime())) break; } while (!deadline.hasExpired()); qCDebug(kdsaLocalSocket) << "Socket state:" << socket.state() << "Timer remaining" << deadline.remainingTime() << "Expired?" << deadline.hasExpired(); if (deadline.hasExpired()) { qCWarning(kdsaLocalSocket) << "Connection timed out"; return false; } socket.write(&LOCALSOCKET_PROTOCOL_VERSION, 1); { QByteArray encodedMessage; QDataStream ds(&encodedMessage, QIODevice::WriteOnly); ds << message; socket.write(encodedMessage); } qCDebug(kdsaLocalSocket) << "Wrote message in the socket" << "Timer remaining" << deadline.remainingTime() << "Expired?" << deadline.hasExpired(); // There is no acknowledgement mechanism here. // Should there be one? while (socket.bytesToWrite() > 0) { if (!socket.waitForBytesWritten(deadline.remainingTime())) { qCWarning(kdsaLocalSocket) << "Message to primary timed out"; return false; } } qCDebug(kdsaLocalSocket) << "Bytes written, now disconnecting" << "Timer remaining" << deadline.remainingTime() << "Expired?" << deadline.hasExpired(); socket.disconnectFromServer(); if (socket.state() == QLocalSocket::UnconnectedState) { qCDebug(kdsaLocalSocket) << "Disconnected -- success!"; return true; } if (!socket.waitForDisconnected(deadline.remainingTime())) { qCWarning(kdsaLocalSocket) << "Disconnection from primary timed out"; return false; } qCDebug(kdsaLocalSocket) << "Disconnected -- success!"; return true; } void KDSingleApplicationLocalSocket::handleNewConnection() { Q_ASSERT(m_localServer); QLocalSocket *socket; while ((socket = m_localServer->nextPendingConnection())) { qCDebug(kdsaLocalSocket) << "Got new connection on" << m_socketName << "state" << socket->state(); Connection c(socket); socket = c.socket.get(); c.readDataConnection = QObjectConnectionHolder( connect(socket, &QLocalSocket::readyRead, this, &KDSingleApplicationLocalSocket::readDataFromSecondary)); c.secondaryDisconnectedConnection = QObjectConnectionHolder( connect(socket, &QLocalSocket::disconnected, this, &KDSingleApplicationLocalSocket::secondaryDisconnected)); c.abortConnection = QObjectConnectionHolder( connect(c.timeoutTimer.get(), &QTimer::timeout, this, &KDSingleApplicationLocalSocket::abortConnectionToSecondary)); m_clients.push_back(std::move(c)); // Note that by the time we get here, the socket could've already been closed, // and no signals emitted (hello, Windows!). Read what's already in the socket. if (readDataFromSecondarySocket(socket)) return; if (socket->state() == QLocalSocket::UnconnectedState) secondarySocketDisconnected(socket); } } template static auto findConnectionBySocket(Container &container, QLocalSocket *socket) { auto i = std::find_if(container.begin(), container.end(), [socket](const auto &c) { return c.socket.get() == socket; }); Q_ASSERT(i != container.end()); return i; } template static auto findConnectionByTimer(Container &container, QTimer *timer) { auto i = std::find_if(container.begin(), container.end(), [timer](const auto &c) { return c.timeoutTimer.get() == timer; }); Q_ASSERT(i != container.end()); return i; } void KDSingleApplicationLocalSocket::readDataFromSecondary() { QLocalSocket *socket = static_cast(sender()); readDataFromSecondarySocket(socket); } bool KDSingleApplicationLocalSocket::readDataFromSecondarySocket(QLocalSocket *socket) { auto i = findConnectionBySocket(m_clients, socket); Connection &c = *i; c.readData.append(socket->readAll()); qCDebug(kdsaLocalSocket) << "Got more data from a secondary. Data read so far:" << c.readData; const QByteArray &data = c.readData; if (data.size() >= 1) { if (data[0] != LOCALSOCKET_PROTOCOL_VERSION) { qCDebug(kdsaLocalSocket) << "Got an invalid protocol version"; m_clients.erase(i); return true; } } QDataStream ds(data); ds.skipRawData(1); ds.startTransaction(); QByteArray message; ds >> message; if (ds.commitTransaction()) { qCDebug(kdsaLocalSocket) << "Got a complete message:" << message; Q_EMIT messageReceived(message); m_clients.erase(i); return true; } return false; } void KDSingleApplicationLocalSocket::secondaryDisconnected() { QLocalSocket *socket = static_cast(sender()); secondarySocketDisconnected(socket); } void KDSingleApplicationLocalSocket::secondarySocketDisconnected(QLocalSocket *socket) { auto i = findConnectionBySocket(m_clients, socket); Connection c = std::move(*i); m_clients.erase(i); qCDebug(kdsaLocalSocket) << "Secondary disconnected. Data read:" << c.readData; } void KDSingleApplicationLocalSocket::abortConnectionToSecondary() { QTimer *timer = static_cast(sender()); auto i = findConnectionByTimer(m_clients, timer); Connection c = std::move(*i); m_clients.erase(i); qCDebug(kdsaLocalSocket) << "Secondary timed out. Data read:" << c.readData; } KDSingleApplicationLocalSocket::Connection::Connection(QLocalSocket *_socket) : socket(_socket) , timeoutTimer(new QTimer) { timeoutTimer->start(LOCALSOCKET_CONNECTION_TIMEOUT); } gottcode-kapow-350ecea/src/3rdparty/kdsingleapplication/kdsingleapplication_localsocket_p.h000066400000000000000000000063331514263554100326250ustar00rootroot00000000000000/* This file is part of KDSingleApplication. SPDX-FileCopyrightText: 2019 Klarälvdalens Datakonsult AB, a KDAB Group company SPDX-License-Identifier: MIT Contact KDAB at for commercial licensing options. */ #ifndef KDSINGLEAPPLICATION_LOCALSOCKET_P_H #define KDSINGLEAPPLICATION_LOCALSOCKET_P_H #include #include #include QT_BEGIN_NAMESPACE class QLockFile; class QLocalServer; class QLocalSocket; class QTimer; QT_END_NAMESPACE #include #include #include "kdsingleapplication.h" struct QObjectDeleteLater { void operator()(QObject *o) { o->deleteLater(); } }; class QObjectConnectionHolder { Q_DISABLE_COPY(QObjectConnectionHolder) QMetaObject::Connection c; public: QObjectConnectionHolder() { } explicit QObjectConnectionHolder(QMetaObject::Connection _c) : c(std::move(_c)) { } ~QObjectConnectionHolder() { QObject::disconnect(c); } QObjectConnectionHolder(QObjectConnectionHolder &&other) noexcept : c(std::exchange(other.c, {})) { } QObjectConnectionHolder &operator=(QObjectConnectionHolder &&other) noexcept { QObjectConnectionHolder moved(std::move(other)); swap(moved); return *this; } void swap(QObjectConnectionHolder &other) noexcept { using std::swap; swap(c, other.c); } }; class KDSingleApplicationLocalSocket : public QObject { Q_OBJECT public: explicit KDSingleApplicationLocalSocket(const QString &name, KDSingleApplication::Options options, QObject *parent = nullptr); ~KDSingleApplicationLocalSocket(); bool isPrimaryInstance() const; public Q_SLOTS: bool sendMessage(const QByteArray &message, int timeout); Q_SIGNALS: void messageReceived(const QByteArray &message); private: void handleNewConnection(); void readDataFromSecondary(); bool readDataFromSecondarySocket(QLocalSocket *socket); void secondaryDisconnected(); void secondarySocketDisconnected(QLocalSocket *socket); void abortConnectionToSecondary(); QString m_socketName; std::unique_ptr m_lockFile; // protects m_localServer std::unique_ptr m_localServer; struct Connection { explicit Connection(QLocalSocket *s); std::unique_ptr socket; std::unique_ptr timeoutTimer; QByteArray readData; // socket/timeoutTimer are deleted via deleteLater (as we delete them // in slots connected to their signals). Before the deleteLater is acted upon, // they may emit further signals, triggering logic that it's not supposed // to be triggered (as the Connection has already been destroyed). // Use this Holder to break the connections. QObjectConnectionHolder readDataConnection; QObjectConnectionHolder secondaryDisconnectedConnection; QObjectConnectionHolder abortConnection; }; std::vector m_clients; }; #endif // KDSINGLEAPPLICATION_LOCALSOCKET_P_H gottcode-kapow-350ecea/src/contact.cpp000066400000000000000000000055651514263554100200770ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2012 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "contact.h" #include "settings.h" //----------------------------------------------------------------------------- Contact::Contact() { // Default to old settings values if they exist Settings settings; m_name = settings.value("Contact/Name").toString(); m_company = settings.value("Contact/Company").toString(); m_address = settings.value("Contact/Address").toString(); m_phone = settings.value("Contact/Phone").toString(); m_fax = settings.value("Contact/Fax").toString(); m_email = settings.value("Contact/Email").toString(); m_website = settings.value("Contact/Website").toString(); // Remove settings values settings.remove("Contact/Name"); settings.remove("Contact/Company"); settings.remove("Contact/Address"); settings.remove("Contact/Phone"); settings.remove("Contact/Fax"); settings.remove("Contact/Email"); settings.remove("Contact/Website"); } //----------------------------------------------------------------------------- void Contact::toXml(QXmlStreamWriter& xml) const { xml.writeStartElement(QLatin1String("contact")); if (!m_name.isEmpty()) { xml.writeTextElement(QLatin1String("name"), m_name); } if (!m_company.isEmpty()) { xml.writeTextElement(QLatin1String("company"), m_company); } if (!m_address.isEmpty()) { QString address = m_address; address.replace("\n", "\\n"); xml.writeTextElement(QLatin1String("address"), address); } if (!m_phone.isEmpty()) { xml.writeTextElement(QLatin1String("phone"), m_phone); } if (!m_fax.isEmpty()) { xml.writeTextElement(QLatin1String("fax"), m_fax); } if (!m_email.isEmpty()) { xml.writeTextElement(QLatin1String("email"), m_email); } if (!m_website.isEmpty()) { xml.writeTextElement(QLatin1String("website"), m_website); } xml.writeEndElement(); } //----------------------------------------------------------------------------- void Contact::fromXml(QXmlStreamReader& xml) { while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("name")) { m_name = xml.readElementText().simplified(); } else if (xml.name() == QLatin1String("company")) { m_company = xml.readElementText().simplified(); } else if (xml.name() == QLatin1String("address")) { m_address = xml.readElementText().simplified(); m_address.replace("\\n", "\n"); } else if (xml.name() == QLatin1String("phone")) { m_phone = xml.readElementText().simplified(); } else if (xml.name() == QLatin1String("fax")) { m_fax = xml.readElementText().simplified(); } else if (xml.name() == QLatin1String("email")) { m_email = xml.readElementText().simplified(); } else if (xml.name() == QLatin1String("website")) { m_website = xml.readElementText().simplified(); } else { xml.skipCurrentElement(); } } } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/contact.h000066400000000000000000000024231514263554100175320ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2012 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_CONTACT_H #define KAPOW_CONTACT_H #include #include class Contact { public: explicit Contact(); QString name() const { return m_name; } QString company() const { return m_company; } QString address() const { return m_address; } QString phone() const { return m_phone; } QString fax() const { return m_fax; } QString email() const { return m_email; } QString website() const { return m_website; } void setName(const QString& name) { m_name = name; } void setCompany(const QString& company) { m_company = company; } void setAddress(const QString& address) { m_address = address; } void setPhone(const QString& phone) { m_phone = phone; } void setFax(const QString& fax) { m_fax = fax; } void setEmail(const QString& email) { m_email = email; } void setWebsite(const QString& website) { m_website = website; } void toXml(QXmlStreamWriter& xml) const; void fromXml(QXmlStreamReader& xml); private: QString m_name; QString m_company; QString m_address; QString m_phone; QString m_fax; QString m_email; QString m_website; }; #endif // KAPOW_CONTACT_H gottcode-kapow-350ecea/src/date_editor.cpp000066400000000000000000000006111514263554100207120ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2008 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "date_editor.h" //----------------------------------------------------------------------------- DateEditor::DateEditor(QWidget* parent) : QDateEdit(parent) { setCalendarPopup(true); } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/date_editor.h000066400000000000000000000005161514263554100203630ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2008 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_DATE_EDITOR_H #define KAPOW_DATE_EDITOR_H #include class DateEditor : public QDateEdit { Q_OBJECT public: explicit DateEditor(QWidget* parent = nullptr); }; #endif // KAPOW_DATE_EDITOR_H gottcode-kapow-350ecea/src/filter_model.cpp000066400000000000000000000045561514263554100211100ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2010 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "filter_model.h" #include "session.h" #include "session_model.h" #include //----------------------------------------------------------------------------- FilterModel::FilterModel(SessionModel* model, QObject* parent) : QSortFilterProxyModel(parent) , m_model(model) , m_type(All) { setSourceModel(model); connect(model, &SessionModel::dataChanged, this, &FilterModel::invalidate); } //----------------------------------------------------------------------------- QModelIndex FilterModel::mapLastBilledToSource(const QModelIndex& proxy_index) const { QModelIndex index = mapToSource(proxy_index); if (m_model->isLastBilled(index.row())) { return index; } else { return QModelIndex(); } } //----------------------------------------------------------------------------- QModelIndex FilterModel::mapUnbilledToSource(const QModelIndex& proxy_index) const { QModelIndex index = mapToSource(proxy_index); if (!m_model->isBilled(index.row()) && (index.row() + 1 < m_model->rowCount())) { return index; } else { return QModelIndex(); } } //----------------------------------------------------------------------------- void FilterModel::setType(int type) { #if (QT_VERSION >= QT_VERSION_CHECK(6,10,0)) beginFilterChange(); m_type = type; endFilterChange(QSortFilterProxyModel::Direction::Rows); #else m_type = type; invalidateFilter(); #endif } //----------------------------------------------------------------------------- bool FilterModel::filterAcceptsRow(int row, const QModelIndex& parent) const { Q_UNUSED(parent); if (!parent.isValid() && (row < sourceModel()->rowCount() - 1)) { QDate current = QDate::currentDate(); QDate date = m_model->session(row).date(); int week1, year1, week2, year2; switch (m_type) { case All: return true; case Unbilled: return !m_model->isBilled(row); case ThisMonth: return (current.month() == date.month()) && (current.year() == date.year()); case ThisYear: return current.year() == date.year(); case ThisWeek: week1 = current.weekNumber(&year1); week2 = date.weekNumber(&year2); return (week1 == week2) && (year1 == year2); default: return false; } } else { return true; } } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/filter_model.h000066400000000000000000000014671514263554100205530ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2010 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_FILTER_MODEL_H #define KAPOW_FILTER_MODEL_H class SessionModel; #include class FilterModel : public QSortFilterProxyModel { public: explicit FilterModel(SessionModel* model, QObject* parent = nullptr); QModelIndex mapLastBilledToSource(const QModelIndex& proxy_index) const; QModelIndex mapUnbilledToSource(const QModelIndex& proxy_index) const; enum FilterType { All, Unbilled, ThisYear, ThisMonth, ThisWeek }; int type() const { return m_type; } void setType(int type); protected: bool filterAcceptsRow(int row, const QModelIndex& parent) const override; private: SessionModel* m_model; int m_type; }; #endif // KAPOW_FILTER_MODEL_H gottcode-kapow-350ecea/src/locale_dialog.cpp000066400000000000000000000111141514263554100212050ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2010 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "locale_dialog.h" #include "settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include //----------------------------------------------------------------------------- QString LocaleDialog::m_current; QString LocaleDialog::m_path; QString LocaleDialog::m_appname; //----------------------------------------------------------------------------- LocaleDialog::LocaleDialog(QWidget* parent) : QDialog(parent, Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint) { QString title = parent ? parent->window()->windowTitle() : QString(); setWindowTitle(!title.isEmpty() ? title : QCoreApplication::applicationName()); QLabel* text = new QLabel(tr("Select application language:"), this); m_translations = new QComboBox(this); m_translations->addItem(tr("")); const QStringList translations = findTranslations(); for (QString translation : translations) { if (translation.startsWith("qt")) { continue; } translation.remove(m_appname); m_translations->addItem(languageName(translation), translation); } int index = std::max(0, m_translations->findData(m_current)); m_translations->setCurrentIndex(index); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this); connect(buttons, &QDialogButtonBox::accepted, this, &LocaleDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &LocaleDialog::reject); QVBoxLayout* layout = new QVBoxLayout(this); layout->setSizeConstraint(QLayout::SetFixedSize); layout->addWidget(text); layout->addWidget(m_translations); layout->addWidget(buttons); } //----------------------------------------------------------------------------- void LocaleDialog::loadTranslator(const QString& name, const QString& datadir) { m_appname = name; // Find translator path m_path = datadir + "/translations/"; // Find current locale m_current = Settings().value("Locale/Language").toString(); if (!m_current.isEmpty()) { QLocale::setDefault(QLocale(m_current)); } const QString locale = QLocale().name(); // Load translators static QTranslator translator; if (translator.load(m_appname + locale, m_path)) { QCoreApplication::installTranslator(&translator); const QString path = QLibraryInfo::path(QLibraryInfo::TranslationsPath); static QTranslator qtbase_translator; if (qtbase_translator.load("qtbase_" + locale, m_path) || qtbase_translator.load("qtbase_" + locale, path)) { QCoreApplication::installTranslator(&qtbase_translator); } static QTranslator qt_translator; if (qt_translator.load("qt_" + locale, m_path) || qt_translator.load("qt_" + locale, path)) { QCoreApplication::installTranslator(&qt_translator); } } } //----------------------------------------------------------------------------- QString LocaleDialog::languageName(const QString& language) { QString name; const QLocale locale(language); if (language.contains('_')) { if (locale.name() == language) { name = locale.nativeLanguageName() + " (" + locale.nativeTerritoryName() + ")"; } else { name = locale.nativeLanguageName() + " (" + language + ")"; } } else { name = locale.nativeLanguageName(); } if (name.isEmpty() || name == "C") { if (language == "eo") { name = "Esperanto"; } else { name = language; } } if (locale.textDirection() == Qt::RightToLeft) { name.prepend(QChar(0x202b)); } return name; } //----------------------------------------------------------------------------- QStringList LocaleDialog::findTranslations() { QStringList result = QDir(m_path, "*.qm").entryList(QDir::Files); result.replaceInStrings(".qm", ""); return result; } //----------------------------------------------------------------------------- void LocaleDialog::accept() { int current = m_translations->findData(m_current); if (current == m_translations->currentIndex()) { return reject(); } QDialog::accept(); m_current = m_translations->itemData(m_translations->currentIndex()).toString(); Settings().setValue("Locale/Language", m_current); QMessageBox::information(this, tr("Note"), tr("Please restart this application for the change in language to take effect."), QMessageBox::Ok); } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/locale_dialog.h000066400000000000000000000033251514263554100206570ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2010 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_LOCALE_DIALOG_H #define KAPOW_LOCALE_DIALOG_H #include class QComboBox; /** * Dialog to set application language. * * This class handles setting the application language when the application is * launched, as well as allowing the user to choose a different language for * future launches. */ class LocaleDialog : public QDialog { Q_OBJECT public: /** * Construct a dialog to choose application language. * * @param parent the parent widget of the dialog */ explicit LocaleDialog(QWidget* parent = nullptr); /** * Load the stored language into the application; defaults to system language. * * @param appname application name to prepend to translation filenames * @param datadir location to search for translations */ static void loadTranslator(const QString& appname, const QString& datadir); /** * Fetch native language name for QLocale name. * * @param language QLocale name to look up * @return translated language name */ static QString languageName(const QString& language); public Q_SLOTS: /** Override parent function to store application language. */ void accept() override; private: /** * Fetch list of application translations. * * @return list of QLocale names */ static QStringList findTranslations(); private: QComboBox* m_translations; /**< list of found translations */ static QString m_current; /**< stored application language */ static QString m_path; /**< location of translations; found in loadTranslator() */ static QString m_appname; /**< application name passed to loadTranslator() */ }; #endif // KAPOW_LOCALE_DIALOG_H gottcode-kapow-350ecea/src/main.cpp000066400000000000000000000110071514263554100173540ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2008 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "locale_dialog.h" #include "paths.h" #include "settings.h" #include "window.h" #include #include #include #include #include int main(int argc, char** argv) { QApplication app(argc, argv); app.setApplicationName("Kapow"); app.setApplicationDisplayName(Window::tr("Kapow Punch Clock")); app.setApplicationVersion(VERSIONSTR); app.setOrganizationDomain("gottcode.org"); app.setOrganizationName("GottCode"); #if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) app.setWindowIcon(QIcon::fromTheme("kapow", QIcon(":/kapow.png"))); app.setDesktopFileName("kapow"); #endif KDSingleApplication kdsa("org.gottcode.Kapow"); if (!kdsa.isPrimaryInstance()) { kdsa.sendMessage("show"); return 0; } const QString appdir = app.applicationDirPath(); const QString datadir = QDir::cleanPath(appdir + "/" + KAPOW_DATADIR); QString path; bool backups_enabled = true; bool start_minimized = false; { // Handle portability #if defined(Q_OS_MAC) QFileInfo portable(appdir + "/../../../Data"); #else QFileInfo portable(appdir + "/Data"); #endif if (portable.exists() && portable.isWritable()) { path = portable.absoluteFilePath(); if (QFile::exists(path + "/Settings/GottCode/Kapow.ini") && !QFile::rename(path + "/Settings/GottCode/Kapow.ini", path + "/Settings/Kapow.ini")) { Settings::setPath(path + "/Settings/GottCode/Kapow.ini"); } else { Settings::setPath(path + "/Settings/Kapow.ini"); } } // Handle command-line options QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::translate("main", "Punch clock program")); parser.addHelpOption(); parser.addVersionOption(); parser.addOption(QCommandLineOption("ini", QCoreApplication::translate("main", "Store settings as INI format in specified file."), QCoreApplication::translate("main", "file"))); parser.addOption(QCommandLineOption("no-backups", QCoreApplication::translate("main", "Do not create automatic backups of time data."))); parser.addOption(QCommandLineOption("tray", QCoreApplication::translate("main", "Start minimized in system tray."))); parser.addPositionalArgument("file", QCoreApplication::translate("main", "The time data file to use."), "[file]"); parser.process(app); if (parser.isSet("ini")) { Settings::setPath(parser.value("ini")); } if (parser.isSet("no-backups")) { backups_enabled = false; } start_minimized = parser.isSet("tray"); QStringList files = parser.positionalArguments(); if (!files.isEmpty()) { QFileInfo override(files.back()); if (override.suffix().toLower() == "xml") { path = override.absoluteFilePath(); } } } // Load settings Settings settings; Q_UNUSED(settings); LocaleDialog::loadTranslator("kapow_", datadir); // Make sure data path exists if (path.isEmpty()) { path = Paths::dataPath(); if (!QFile::exists(path)) { // Create data location QDir dir(path); if (!dir.mkpath(dir.absolutePath())) { QMessageBox::critical(nullptr, Window::tr("Error"), Window::tr("Unable to create time data location.")); return 1; } // Move time data QString oldpath = Paths::oldDataPath(); if (!oldpath.isEmpty()) { QDir olddir(oldpath); const QStringList files = olddir.entryList(QDir::Files); bool success = true; for (const QString& file : files) { success &= QFile::rename(olddir.absoluteFilePath(file), dir.absoluteFilePath(file)); } dir.rmdir(oldpath); if (!success) { QMessageBox::warning(nullptr, Window::tr("Error"), Window::tr("Unable to move time data location.")); } } } // Make sure command-line data path exists } else if (!QFile::exists(path + "/../")) { QDir dir(path + "/../"); if (!dir.mkpath(dir.absolutePath())) { QMessageBox::critical(nullptr, Window::tr("Error"), Window::tr("Unable to create time data location.")); return 1; } } // Find data file if (!path.endsWith(".xml")) { if (QFile::exists(path + "/kapow.xml")) { path += "/kapow.xml"; } else if (QFile::exists(path + "/data.xml") && !QFile::rename(path + "/data.xml", path + "/kapow.xml")) { path += "/data.xml"; } else { path += "/kapow.xml"; } } // Create window Window window(path, backups_enabled, start_minimized); if (window.isValid()) { Window::connect(&kdsa, &KDSingleApplication::messageReceived, &window, &Window::raiseWindow); return app.exec(); } else { return 1; } } gottcode-kapow-350ecea/src/paths.cpp000066400000000000000000000030771514263554100175570ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2015 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "paths.h" #include #include #include #include //----------------------------------------------------------------------------- QString Paths::dataPath() { static QString path = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); return path; } //----------------------------------------------------------------------------- QString Paths::oldDataPath() { QStringList oldpaths; QString oldpath; #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) // Data path from Qt 4 version of 1.4 oldpaths.append(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/data/GottCode/Kapow"); #endif // Data path from 1.0 #if defined(Q_OS_MAC) oldpath = QDir::homePath() + "/Library/Application Support/GottCode/Kapow/"; #elif defined(Q_OS_UNIX) oldpath = QString::fromLocal8Bit(qgetenv("XDG_DATA_HOME")); if (oldpath.isEmpty()) { oldpath = QDir::homePath() + "/.local/share"; } oldpath += "/gottcode/kapow/"; #elif defined(Q_OS_WIN) oldpath = QDir::homePath() + "/Application Data/GottCode/Kapow/"; #endif if (!oldpaths.contains(oldpath)) { oldpaths.append(oldpath); } oldpaths.removeAll(dataPath() + "/"); // Check if an old data location exists oldpath.clear(); for (const QString& testpath : oldpaths) { if (QFile::exists(testpath)) { oldpath = testpath; break; } } return oldpath; } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/paths.h000066400000000000000000000004351514263554100172170ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2015 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_PATHS_H #define KAPOW_PATHS_H class QString; class Paths { public: static QString dataPath(); static QString oldDataPath(); }; #endif // KAPOW_PATHS_H gottcode-kapow-350ecea/src/project.cpp000066400000000000000000000114231514263554100201000ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "project.h" #include "filter_model.h" #include "session_model.h" #include #include #include //----------------------------------------------------------------------------- Project::Project(QTreeWidget* parent, const QString& project) : QTreeWidgetItem(parent, QStringList(project)) { init(); } //----------------------------------------------------------------------------- Project::Project(QTreeWidgetItem* parent, const QString& project) : QTreeWidgetItem(parent, QStringList(project)) { init(); } //----------------------------------------------------------------------------- bool Project::isActive() const { if (m_active) { return true; } int count = childCount(); for (int i = 0; i < count; ++i) { Project* project = dynamic_cast(child(i)); if (project && project->isActive()) { return true; } } return false; } //----------------------------------------------------------------------------- void Project::setDecimalTotals(bool decimals) { m_model->setDecimalTotals(decimals); int count = childCount(); for (int i = 0; i < count; ++i) { Project* project = dynamic_cast(child(i)); if (project) { project->setDecimalTotals(decimals); } } } //----------------------------------------------------------------------------- void Project::setScrollValue(int value) { m_scroll_value = value; } //----------------------------------------------------------------------------- QString Project::time() const { return text(1); } //----------------------------------------------------------------------------- void Project::toXml(QXmlStreamWriter& xml) const { xml.writeStartElement("project"); xml.writeAttribute("name", text(0)); if (isExpanded()) { xml.writeAttribute("expanded", "1"); } if (this == treeWidget()->currentItem()) { xml.writeAttribute("current", "1"); } xml.writeAttribute("filter", QString::number(m_filter_model->type())); if (m_active) { xml.writeEmptyElement("autosave"); xml.writeAttribute("start", m_start_time.toString(Qt::ISODate)); xml.writeAttribute("stop", QDateTime::currentDateTime().toString(Qt::ISODate)); xml.writeAttribute("note", m_task); } m_model->toXml(xml); int count = childCount(); for (int i = 0; i < count; ++i) { Project* project = dynamic_cast(child(i)); if (project) { project->toXml(xml); } } xml.writeEndElement(); } //----------------------------------------------------------------------------- bool Project::start(const QDateTime& current) { // Prevent starting timer inside of existing session if (m_model->hasConflict(current)) { return false; } m_start_time = current; m_active = true; m_model->setMaximumDateTime(m_start_time); setText(1, "00:00:00"); billedStatusChanged(false); return true; } //----------------------------------------------------------------------------- bool Project::stop(QDateTime current) { // Prevent ending timer inside of or after existing session if (current.isValid()) { m_model->fixConflict(m_start_time, current); } bool success = true; m_active = false; m_model->setMaximumDateTime(QDateTime()); if (current.isValid()) { success = m_model->add(m_start_time, current, m_task); } else { billedStatusChanged(m_model->isBilled(m_model->rowCount() - 2)); } setText(1, ""); return success; } //----------------------------------------------------------------------------- void Project::setTask(const QString& task) { m_task = task; } //----------------------------------------------------------------------------- void Project::updateTime(const QDateTime& current) { if (m_active) { QTime convert(0, 0, 0); convert = convert.addSecs(m_start_time.secsTo(current)); setText(1, convert.toString("hh:mm:ss")); } int count = childCount(); for (int i = 0; i < count; ++i) { Project* project = dynamic_cast(child(i)); if (project) { project->updateTime(current); } } } //----------------------------------------------------------------------------- void Project::billedStatusChanged(bool billed) { setForeground(0, QGuiApplication::palette().color((billed && !m_active) ? QPalette::Disabled : QPalette::Normal, QPalette::Text)); } //----------------------------------------------------------------------------- void Project::init() { setFlags(flags() | Qt::ItemIsEditable); setTextAlignment(1, Qt::AlignRight | Qt::AlignVCenter); m_model = new SessionModel(this); connect(m_model, &SessionModel::billedStatusChanged, this, &Project::billedStatusChanged); m_filter_model = new FilterModel(m_model, treeWidget()); m_active = false; m_scroll_value = -1; } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/project.h000066400000000000000000000023201514263554100175410ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_PROJECT_H #define KAPOW_PROJECT_H class FilterModel; class SessionModel; #include #include #include class Project : public QObject, public QTreeWidgetItem { Q_OBJECT public: Project(QTreeWidget* parent, const QString& project); Project(QTreeWidgetItem* parent, const QString& project); bool start(const QDateTime& current); bool stop(QDateTime current = QDateTime()); void updateTime(const QDateTime& current); void setTask(const QString& task); bool isActive() const; SessionModel* model() const { return m_model; } FilterModel* filterModel() const { return m_filter_model; } int scrollValue() const { return m_scroll_value; } void setDecimalTotals(bool decimals); void setScrollValue(int value); QString time() const; void toXml(QXmlStreamWriter& xml) const; private Q_SLOTS: void billedStatusChanged(bool billed); private: void init(); private: SessionModel* m_model; FilterModel* m_filter_model; QDateTime m_start_time; QString m_task; bool m_active; int m_scroll_value; }; #endif // KAPOW_PROJECT_H gottcode-kapow-350ecea/src/project_delegate.cpp000066400000000000000000000020651514263554100217340ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "project_delegate.h" #include //----------------------------------------------------------------------------- ProjectDelegate::ProjectDelegate(QObject* parent) : QStyledItemDelegate(parent) { m_height = QLineEdit().sizeHint().height(); } //----------------------------------------------------------------------------- QWidget* ProjectDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { if (index.column() == 0) { return QStyledItemDelegate::createEditor(parent, option, index); } else { return 0; } } //----------------------------------------------------------------------------- QSize ProjectDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { QSize size = QStyledItemDelegate::sizeHint(option, index); size.setHeight(m_height); return size; } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/project_delegate.h000066400000000000000000000011361514263554100213770ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_PROJECT_DELEGATE_H #define KAPOW_PROJECT_DELEGATE_H #include class ProjectDelegate : public QStyledItemDelegate { public: explicit ProjectDelegate(QObject* parent = nullptr); QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override; private: int m_height; }; #endif // KAPOW_PROJECT_DELEGATE_H gottcode-kapow-350ecea/src/rates.cpp000066400000000000000000000045561514263554100175610ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2012 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "rates.h" #include "settings.h" #include //----------------------------------------------------------------------------- Rates::Rates() { // Use currency symbol of locale QLocale locale; m_currency_symbol = locale.currencySymbol(); m_prepend_symbol = locale.toCurrencyString(1, m_currency_symbol).at(0) != '1'; // Default to old settings values if they exist Settings settings; m_hourly = settings.value("ReportDialog/HourlyRate").toDouble(); m_tax = settings.value("ReportDialog/TaxRate").toDouble(); m_currency_symbol = settings.value("ReportDialog/Currency", m_currency_symbol).toString(); m_prepend_symbol = settings.value("ReportDialog/PrependCurrency", m_prepend_symbol).toBool(); // Remove settings values settings.remove("ReportDialog/HourlyRate"); settings.remove("ReportDialog/TaxRate"); settings.remove("ReportDialog/Currency"); settings.remove("ReportDialog/PrependCurrency"); } //----------------------------------------------------------------------------- void Rates::toXml(QXmlStreamWriter& xml) const { xml.writeStartElement(QLatin1String("rates")); if (!qFuzzyIsNull(m_hourly)) { xml.writeTextElement(QLatin1String("hourly"), QString::number(m_hourly, 'f', 2)); } if (!qFuzzyIsNull(m_tax)) { xml.writeTextElement(QLatin1String("tax"), QString::number(m_tax, 'f', 2)); } if (!m_currency_symbol.isEmpty()) { xml.writeStartElement(QLatin1String("currency")); xml.writeAttribute(QLatin1String("prepend"), QString::number(m_prepend_symbol)); xml.writeCharacters(m_currency_symbol); xml.writeEndElement(); } xml.writeEndElement(); } //----------------------------------------------------------------------------- void Rates::fromXml(QXmlStreamReader& xml) { while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("hourly")) { m_hourly = xml.readElementText().toDouble(); } else if (xml.name() == QLatin1String("tax")) { m_tax = xml.readElementText().toDouble(); } else if (xml.name() == QLatin1String("currency")) { m_prepend_symbol = xml.attributes().value(QLatin1String("prepend")).toString().toInt(); m_currency_symbol = xml.readElementText().simplified(); } else { xml.skipCurrentElement(); } } } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/rates.h000066400000000000000000000017511514263554100172200ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2012 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_RATES_H #define KAPOW_RATES_H #include #include #include class Rates { Q_DECLARE_TR_FUNCTIONS(Rates) public: explicit Rates(); double hourly() const { return m_hourly; } double tax() const { return m_tax; } QString currencySymbol() const { return m_currency_symbol; } bool prependSymbol() const { return m_prepend_symbol; } void setHourly(double hourly) { m_hourly = hourly; } void setTax(double tax) { m_tax = tax; } void setCurrencySymbol(const QString& symbol) { m_currency_symbol = symbol; } void setPrependSymbol(bool prepend) { m_prepend_symbol = prepend; } void toXml(QXmlStreamWriter& xml) const; void fromXml(QXmlStreamReader& xml); private: double m_hourly; double m_tax; QString m_currency_symbol; bool m_prepend_symbol; }; #endif // KAPOW_RATES_H gottcode-kapow-350ecea/src/report.cpp000066400000000000000000000476101514263554100177540ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "report.h" #include "contact.h" #include "rates.h" #include "settings.h" #include "session_model.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //----------------------------------------------------------------------------- Report::Report(SessionModel* sessions, int current, Contact* contact, Rates* rates, QWidget* parent) : QDialog(parent) , m_data(sessions) , m_current_row(current) , m_contact(contact) , m_rates(rates) , m_delete_button(nullptr) { // Create contact information widgets QWidget* contact_info_tab = new QWidget(this); m_name = new QLineEdit(contact_info_tab); connect(m_name, &QLineEdit::textChanged, this, &Report::generateText); m_company = new QLineEdit(contact_info_tab); connect(m_company, &QLineEdit::textChanged, this, &Report::generateText); m_address = new QTextEdit(contact_info_tab); connect(m_address, &QTextEdit::textChanged, this, &Report::generateText); m_phone = new QLineEdit(contact_info_tab); connect(m_phone, &QLineEdit::textChanged, this, &Report::generateText); m_fax = new QLineEdit(contact_info_tab); connect(m_fax, &QLineEdit::textChanged, this, &Report::generateText); m_email = new QLineEdit(contact_info_tab); connect(m_email, &QLineEdit::textChanged, this, &Report::generateText); m_website = new QLineEdit(contact_info_tab); connect(m_website, &QLineEdit::textChanged, this, &Report::generateText); QFormLayout* contact_info_layout = new QFormLayout(contact_info_tab); contact_info_layout->addRow(tr("Name:"), m_name); contact_info_layout->addRow(tr("Company:"), m_company); contact_info_layout->addRow(tr("Address:"), m_address); contact_info_layout->addRow(tr("Phone:"), m_phone); contact_info_layout->addRow(tr("Fax:"), m_fax); contact_info_layout->addRow(tr("Email:"), m_email); contact_info_layout->addRow(tr("Website:"), m_website); // Create data widgets QWidget* data_tab = new QWidget(this); m_groups = new QComboBox(data_tab); connect(m_groups, &QComboBox::currentIndexChanged, this, &Report::groupSelected); m_details = new QTreeView(data_tab); m_details->setEditTriggers(QAbstractItemView::NoEditTriggers); m_details->setRootIsDecorated(false); m_details->setItemsExpandable(false); m_details->setSelectionMode(QAbstractItemView::SingleSelection); m_details->setSelectionBehavior(QAbstractItemView::SelectRows); m_details->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); m_details->header()->setSectionsClickable(false); m_details->header()->setSectionsMovable(false); m_details->header()->setSectionResizeMode(QHeaderView::ResizeToContents); m_details->setModel(m_data); m_details->header()->setSectionResizeMode(3, QHeaderView::Stretch); m_details->header()->setStretchLastSection(false); for (int i = 5; i < 10; ++i) { m_details->setColumnHidden(i, true); } m_hourly_rate = new QDoubleSpinBox(data_tab); m_hourly_rate->setRange(0.0, 10000000.0); m_hourly_rate->setSpecialValueText(tr("N/A")); connect(m_hourly_rate, &QDoubleSpinBox::valueChanged, this, &Report::generateText); m_tax_rate = new QDoubleSpinBox(data_tab); m_tax_rate->setRange(0.0, 100.0); m_tax_rate->setSuffix(QLocale().percent()); m_tax_rate->setSpecialValueText(tr("N/A")); connect(m_tax_rate, &QDoubleSpinBox::valueChanged, this, &Report::generateText); m_currency_symbol = new QLineEdit(data_tab); connect(m_currency_symbol, &QLineEdit::textChanged, this, &Report::currencyChanged); m_prepend_symbol = new QCheckBox(tr("Prepend currency symbol"), data_tab); connect(m_prepend_symbol, &QCheckBox::toggled, this, &Report::currencyChanged); QFormLayout* data_rates_layout = new QFormLayout; data_rates_layout->setFormAlignment(Qt::AlignCenter | Qt::AlignTop); data_rates_layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); data_rates_layout->setContentsMargins(0, 0, 0, 0); data_rates_layout->addRow(tr("Hourly rate:"), m_hourly_rate); data_rates_layout->addRow(tr("Tax rate:"), m_tax_rate); data_rates_layout->addRow(tr("Currency symbol:"), m_currency_symbol); data_rates_layout->addRow("", m_prepend_symbol); QVBoxLayout* data_layout = new QVBoxLayout(data_tab); data_layout->addWidget(m_groups); data_layout->addWidget(m_details); data_layout->addLayout(data_rates_layout); // Create preview widget m_preview = new QTextEdit(this); m_preview->setReadOnly(true); m_preview->document()->setDefaultStyleSheet("td { padding: 0 5px; } th { padding: 0 5px; }"); // Create tabs QTabWidget* tabs = new QTabWidget(this); tabs->addTab(contact_info_tab, tr("Contact Information")); tabs->addTab(data_tab, tr("Data")); tabs->addTab(m_preview, tr("Preview")); tabs->setCurrentIndex(1); // Create dialog actions QDialogButtonBox* buttons = new QDialogButtonBox(this); QPushButton* reset_button = buttons->addButton(QDialogButtonBox::Reset); QPushButton* export_button = buttons->addButton(tr("Export"), QDialogButtonBox::ActionRole); QPushButton* print_button = buttons->addButton(tr("Print"), QDialogButtonBox::ActionRole); if (m_data->isBilled(m_current_row)) { m_delete_button = buttons->addButton(tr("Remove"), QDialogButtonBox::ActionRole); connect(m_delete_button, &QPushButton::clicked, this, &Report::unbill); buttons->addButton(QDialogButtonBox::Close); } else { buttons->addButton(QDialogButtonBox::Cancel); QPushButton* ok_button = buttons->addButton(QDialogButtonBox::Ok); connect(ok_button, &QPushButton::clicked, this, &Report::bill); } if (style()->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons)) { export_button->setIcon(QIcon::fromTheme("document-export")); print_button->setIcon(QIcon::fromTheme("document-print")); if (m_delete_button) { m_delete_button->setIcon(QIcon::fromTheme("user-trash")); } } connect(buttons, &QDialogButtonBox::rejected, this, &Report::reject); connect(reset_button, &QPushButton::clicked, this, &Report::reset); connect(export_button, &QPushButton::clicked, this, &Report::save); connect(print_button, &QPushButton::clicked, this, &Report::print); // Lay out dialog QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(tabs, 1); layout->addWidget(buttons); resize(Settings().value("ReportDialog/Size", QSize(700, 500)).toSize()); // Load data findGroups(); reset(); } //----------------------------------------------------------------------------- void Report::hideEvent(QHideEvent* event) { m_contact->setName(m_name->text()); m_contact->setCompany(m_company->text()); m_contact->setAddress(m_address->toPlainText()); m_contact->setPhone(m_phone->text()); m_contact->setFax(m_fax->text()); m_contact->setEmail(m_email->text()); m_contact->setWebsite(m_website->text()); m_rates->setHourly(m_hourly_rate->value()); m_rates->setTax(m_tax_rate->value()); m_rates->setCurrencySymbol(m_currency_symbol->text().simplified()); m_rates->setPrependSymbol(m_prepend_symbol->isChecked()); Settings().setValue("ReportDialog/Size", size()); QDialog::hideEvent(event); } //----------------------------------------------------------------------------- void Report::currencyChanged() { QString symbol = m_currency_symbol->text().simplified(); if (m_prepend_symbol->isChecked()) { m_hourly_rate->setSuffix(""); m_hourly_rate->setPrefix(symbol); } else { m_hourly_rate->setPrefix(""); m_hourly_rate->setSuffix(symbol); } generateText(); } //----------------------------------------------------------------------------- void Report::generateText() { m_preview->setHtml(generateHtml()); } //----------------------------------------------------------------------------- void Report::groupSelected(int group) { if (group == -1) { return; } if (m_delete_button) { m_delete_button->setEnabled(group == 0); } for (int i = 0; i < m_data->rowCount(); ++i) { m_details->setRowHidden(i, QModelIndex(), true); } const QList rows = m_groups->itemData(group).toList(); for (const QVariant& row : rows) { m_details->setRowHidden(row.toInt(), QModelIndex(), false); } generateText(); } //----------------------------------------------------------------------------- void Report::print() { QPrinter printer; QPrintDialog dialog(&printer, this); if (dialog.exec() != QDialog::Accepted) { return; } m_preview->print(&printer); } //----------------------------------------------------------------------------- void Report::reset() { m_name->setText(m_contact->name()); m_company->setText(m_contact->company()); m_address->setPlainText(m_contact->address()); m_phone->setText(m_contact->phone()); m_fax->setText(m_contact->fax()); m_email->setText(m_contact->email()); m_website->setText(m_contact->website()); m_hourly_rate->setValue(m_rates->hourly()); m_tax_rate->setValue(m_rates->tax()); m_currency_symbol->setText(m_rates->currencySymbol()); m_prepend_symbol->setChecked(m_rates->prependSymbol()); } //----------------------------------------------------------------------------- void Report::save() { Settings settings; QString filter = settings.value("ReportDialog/Filter").toString(); QString html_filter = tr("Web Page (*.html *.htm)"); QString ical_filter = tr("iCalendar (*.ics)"); QString outlook_filter = tr("Outlook CSV (*.csv)"); if ("iCalendar" == filter) { filter = ical_filter + ";;" + html_filter + ";;" + outlook_filter; } else if ("Outlook" == filter) { filter = outlook_filter + ";;" + html_filter + ";;" + ical_filter; } else { filter = html_filter + ";;" + ical_filter + ";;" + outlook_filter; } QString selected_filter; QString filename = QFileDialog::getSaveFileName(this, tr("Export Report"), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), filter, &selected_filter); if (!filename.isEmpty()) { if (selected_filter == html_filter) { settings.remove("ReportDialog/Filter"); writeHtml(filename); } else if (selected_filter == ical_filter) { settings.setValue("ReportDialog/Filter", "iCalendar"); writeICalendar(filename); } else if (selected_filter == outlook_filter) { settings.setValue("ReportDialog/Filter", "Outlook"); writeOutlookCsv(filename); } } } //----------------------------------------------------------------------------- void Report::bill() { m_data->setBilled(m_current_row, true); QDialog::accept(); } //----------------------------------------------------------------------------- void Report::unbill() { if (QMessageBox::question(this, tr("Question"), tr("Remove newest report?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) { return; } // Remove report m_data->setBilled(m_groups->currentData().toList().last().toInt(), false); m_groups->removeItem(m_groups->currentIndex()); // Hide dialog if last report removed if (m_groups->count() == 0) { reject(); } } //----------------------------------------------------------------------------- void Report::findGroups() { int current_group = -1; int count = m_data->rowCount(); QList billed = m_data->billedRows(); QList rows; if (m_data->isBilled(m_current_row)) { setWindowTitle(tr("View Reports")); // Find groups of billed sessions for (int i = 0; i < count; ++i) { rows.append(i); if (billed.contains(i)) { QString from = m_data->data(m_data->index(rows.first().toInt(), 0)).toString(); QString to = m_data->data(m_data->index(rows.last().toInt(), 0)).toString(); m_groups->insertItem(0, QString("%1 - %2").arg(from, to), rows); if ((i >= m_current_row) && (m_current_row >= rows.first().toInt())) { current_group = m_groups->count(); } rows.clear(); } } } else { setWindowTitle(tr("Create Report")); // Find unbilled data through current row for (int i = !billed.isEmpty() ? (billed.last() + 1) : 0; i <= m_current_row; ++i) { rows.append(i); } m_groups->addItem(QString(), rows); m_groups->hide(); rows.clear(); } // Select group of sessions with current row if (current_group != -1) { current_group = m_groups->count() - current_group; } else { current_group = 0; } m_groups->setCurrentIndex(current_group); } //----------------------------------------------------------------------------- QString Report::generateHtml() const { if (!m_data->rowCount()) { m_preview->clear(); return QString(); } QString title = tr("Time Sheet Report"); QString html = "\n" "\n" "\n" "" + title + "\n" "\n" "\n" "\n" "\n" "

" + title + "
\n" + m_groups->currentText() + "
\n"; // Add contact information QString info = m_name->text().simplified(); if (!info.isEmpty()) { html += "
\n" + info; } info = m_company->text().simplified(); if (!info.isEmpty()) { html += "
\n" + info; } info = m_address->toPlainText().simplified(); if (!info.isEmpty()) { info.replace("\n", "
\n"); html += "
\n" + info; } info = m_phone->text().simplified(); if (!info.isEmpty()) { html += "
\n" + tr("Phone: %1").arg(info); } info = m_fax->text().simplified(); if (!info.isEmpty()) { html += "
\n" + tr("Fax: %1").arg(info); } info = m_email->text().simplified(); if (!info.isEmpty()) { html += "
\n" + info; } info = m_website->text().simplified(); if (!info.isEmpty()) { html += "
\n" + info; } // Finish header html += "
\n

\n"; // Add data html += "\n"; QString header("" "" "" "" "" "" "\n"); for (int column = 0; column < 5; ++column) { header = header.arg(m_data->headerData(column, Qt::Horizontal).toString()); } html += header; int last = 0; int rows = m_data->rowCount(); for (int row = 0; row < rows; ++row) { if (m_details->isRowHidden(row, QModelIndex())) { continue; } last = row; QStringList columns; for (int column = 0; column < 5; ++column) { QModelIndex index = m_data->index(row, column); columns.append(m_data->data(index).toString().simplified()); } html += QString("" "" "" "" "" "" "\n").arg(columns[0], columns[1], columns[2], columns[3], columns[4]); } // Add total hours if (!Settings().value("DecimalTotals", true).toBool()) { const QString total = m_data->session(last).total(Session::Total, false); html += "\n"; } html += "\n"; const QString hours = m_data->session(last).total(Session::Total, true); html += "\n"; // Add billing information const double hourly_rate = m_hourly_rate->value(); if (!qFuzzyIsNull(hourly_rate)) { const QString currency(m_hourly_rate->prefix() + "%L1" + m_hourly_rate->suffix()); double value = m_data->session(last).total() * hourly_rate; const double tax_rate = m_tax_rate->value() * 0.01; if (!qFuzzyIsNull(tax_rate)) { html += "\n"; const double tax = tax_rate * value; html += "\n"; value += tax; } html += "\n"; } html += "
%1%2%3%4%5
%1%2%3%4%5
" + total + "

" + tr("Hours") + "" + hours + "
" + tr("Subtotal") + "" + QString(currency).arg(value, 0, 'f', 2) + "
" + tr("Taxes") + "" + QString(currency).arg(tax, 0, 'f', 2) + "
" + tr("Total") + "" + QString(currency).arg(value, 0, 'f', 2) + "
\n\n\n"; return html; } //----------------------------------------------------------------------------- void Report::writeHtml(QString filename) const { if (!filename.endsWith(".html") && !filename.endsWith(".htm")) { filename.append(".html"); } QFile file(filename); if (file.open(QFile::WriteOnly | QFile::Text)) { QTextStream stream(&file); stream << generateHtml(); file.close(); } } //----------------------------------------------------------------------------- static void writeWrappedLine(const QByteArray& line, QIODevice* device) { int end = line.length(); int start = 0; int pos = 0; Q_FOREVER { pos = start + 74; if (pos >= end) { // Write unwrapped line or end of wrapped line device->write(&line.constData()[start], end - start); device->write("\r\n"); break; } else { // Don't split UTF-8 characters while ((line[pos] & 0x80) && !(line[pos] & 0x40)) { pos--; } // Write wrapped text device->write(&line.constData()[start], pos - start); device->write("\r\n "); start = pos; } } } void Report::writeICalendar(QString filename) const { if (!filename.endsWith(".ics")) { filename.append(".ics"); } QFile file(filename); if (file.open(QFile::WriteOnly)) { file.write("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//GottCode//Kapow//EN\r\n"); QByteArray uid_suffix; uid_suffix += '-'; uid_suffix += QByteArray::number(QCoreApplication::applicationPid()); uid_suffix += '@'; uid_suffix += QHostInfo::localHostName().toUtf8(); QString current; int dup = 0; int rows = m_data->rowCount(); for (int row = 0; row < rows; ++row) { if (m_details->isRowHidden(row, QModelIndex())) { continue; } QString now = QDateTime::currentDateTimeUtc().toString("yyyyMMddThhmmssZ"); if (current == now) { dup++; } else { current = now; dup = 0; } Session session = m_data->session(row); file.write("BEGIN:VEVENT\r\n"); QByteArray uid("UID:Kapow-"); uid += current.toUtf8(); uid += QByteArray::number(dup); uid += uid_suffix; writeWrappedLine(uid, &file); QDateTime start(session.date(), session.start()); file.write(QByteArray("DTSTART:") + start.toUTC().toString("yyyyMMddThhmmssZ").toUtf8() + QByteArray("\r\n")); QDateTime stop(session.date(), session.stop()); file.write(QByteArray("DTEND:") + stop.toUTC().toString("yyyyMMddThhmmssZ").toUtf8() + QByteArray("\r\n")); if (!session.task().isEmpty()) { writeWrappedLine(QByteArray("SUMMARY:") + session.task().toUtf8(), &file); } file.write("END:VEVENT\r\n"); } file.write("END:VCALENDAR\r\n"); file.close(); } } //----------------------------------------------------------------------------- void Report::writeOutlookCsv(QString filename) const { if (!filename.endsWith(".csv")) { filename.append(".csv"); } QFile file(filename); if (file.open(QFile::WriteOnly)) { QTextStream stream(&file); stream << QLatin1String("\"Title\",\"Start Date\",\"Start Time\",\"End Date\",\"End Time\"\r\n"); int rows = m_data->rowCount(); for (int row = 0; row < rows; ++row) { if (m_details->isRowHidden(row, QModelIndex())) { continue; } Session session = m_data->session(row); stream << '"' << session.task() << QLatin1String("\",\"") << session.date().toString("MM/dd/yy") << QLatin1String("\",\"") << session.start().toString("hh:mm:ss AP") << QLatin1String("\",\"") << session.date().toString("MM/dd/yy") << QLatin1String("\",\"") << session.stop().toString("hh:mm:ss AP") << QLatin1String("\"\r\n"); } file.close(); } } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/report.h000066400000000000000000000026271514263554100174200ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_REPORT_H #define KAPOW_REPORT_H class Contact; class Rates; class SessionModel; #include class QCheckBox; class QComboBox; class QDoubleSpinBox; class QLineEdit; class QPushButton; class QTextEdit; class QTreeView; class Report : public QDialog { Q_OBJECT public: Report(SessionModel* sessions, int current, Contact* contact, Rates* rates, QWidget* parent = nullptr); protected: void hideEvent(QHideEvent* event) override; private Q_SLOTS: void currencyChanged(); void generateText(); void groupSelected(int group); void print(); void reset(); void save(); void bill(); void unbill(); private: void findGroups(); QString generateHtml() const; void writeHtml(QString filename) const; void writeICalendar(QString filename) const; void writeOutlookCsv(QString filename) const; private: QTextEdit* m_preview; QComboBox* m_groups; QTreeView* m_details; SessionModel* m_data; int m_current_row; QDoubleSpinBox* m_hourly_rate; QDoubleSpinBox* m_tax_rate; QLineEdit* m_currency_symbol; QCheckBox* m_prepend_symbol; QLineEdit* m_name; QLineEdit* m_company; QTextEdit* m_address; QLineEdit* m_phone; QLineEdit* m_fax; QLineEdit* m_email; QLineEdit* m_website; Contact* m_contact; Rates* m_rates; QPushButton* m_delete_button; }; #endif // KAPOW_REPORT_H gottcode-kapow-350ecea/src/session.cpp000066400000000000000000000060451514263554100201210ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "session.h" #include #include //----------------------------------------------------------------------------- Session::Session() { d = new SessionData(QDate(), QTime(), QTime(), QString(), false); } //----------------------------------------------------------------------------- Session::Session(const QDate& date, const QTime& start, const QTime& stop, const QString& task, bool billed) { d = new SessionData(date, start, stop, task, billed); updateTotals(); } //----------------------------------------------------------------------------- double Session::total() const { return d->m_totals[Total] / 3600.0; } //----------------------------------------------------------------------------- QString Session::total(Time time, bool decimals, bool unit) const { QString result; int seconds = d->m_totals[time]; if (decimals) { double hours = d->m_totals[time] / 3600.0; if (!unit) { result = QLocale().toString(hours, 'f', 2); } else { if (hours == std::floor(hours)) { result = tr("%n hour(s)", "", hours); } else { result = tr("%L1 hours").arg(hours, 0, 'f', 2); } } } else { int hours = std::floor(seconds / 3600.f); seconds -= (hours * 3600); int minutes = std::floor(seconds / 60.f); seconds -= (minutes * 60); result = QString("%1:%2:%3").arg(hours).arg(minutes, 2, 10, QLatin1Char('0')).arg(seconds, 2, 10, QLatin1Char('0')); } return result; } //----------------------------------------------------------------------------- void Session::updateTotals(const Session& previous) { int duration = d->m_start.secsTo(d->m_stop); for (int i = Duration; i <= Total; ++i) { d->m_totals[i] = duration; } if (!previous.isValid() || previous.d->m_billed) { return; } if (previous.date() == date()) { d->m_totals[Daily] += previous.d->m_totals[Daily]; } if (previous.date().weekNumber() == date().weekNumber()) { d->m_totals[Weekly] += previous.d->m_totals[Weekly]; } if (previous.date().month() == date().month()) { d->m_totals[Monthly] += previous.d->m_totals[Monthly]; } d->m_totals[Total] += previous.d->m_totals[Total]; } //----------------------------------------------------------------------------- void Session::toXml(QXmlStreamWriter& xml) const { xml.writeEmptyElement("session"); xml.writeAttribute("date", d->m_date.toString(Qt::ISODate)); xml.writeAttribute("start", d->m_start.toString(Qt::ISODate)); xml.writeAttribute("stop", d->m_stop.toString(Qt::ISODate)); xml.writeAttribute("billed", QString::number(d->m_billed)); xml.writeAttribute("note", d->m_task); } //----------------------------------------------------------------------------- bool operator==(const Session& lhs, const Session &rhs) { return (lhs.date() == rhs.date()) && (lhs.start() == rhs.start()) && (lhs.stop() == rhs.stop()) && (lhs.task() == rhs.task()) && (lhs.isBilled() == rhs.isBilled()); } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/session.h000066400000000000000000000032521514263554100175630ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_SESSION_H #define KAPOW_SESSION_H #include #include #include #include class Session { Q_DECLARE_TR_FUNCTIONS(Session) public: explicit Session(); Session(const QDate& date, const QTime& start, const QTime& stop, const QString& task, bool billed); bool isValid() const { return d->m_date.isValid() && (d->m_start <= d->m_stop); } QDate date() const { return d->m_date; } QTime start() const { return d->m_start; } QTime stop() const { return d->m_stop; } QString task() const { return d->m_task; } bool isBilled() const { return d->m_billed; } void setBilled(bool billed) { d->m_billed = billed; } enum Time { Duration = 0, Daily, Weekly, Monthly, Total }; double total() const; QString total(Time time, bool decimals, bool unit = false) const; void updateTotals(const Session& previous = Session()); void toXml(QXmlStreamWriter& xml) const; private: class SessionData: public QSharedData { public: SessionData(const QDate& date, const QTime& start, const QTime& stop, const QString& task, bool billed) : m_date(date) , m_start(start.addMSecs(-start.msec())) , m_stop(stop.addMSecs(-stop.msec())) , m_task(task) , m_billed(billed) , m_totals(Total + 1) { } QDate m_date; QTime m_start; QTime m_stop; QString m_task; bool m_billed; QList m_totals; }; QExplicitlySharedDataPointer d; }; bool operator==(const Session& lhs, const Session &rhs); #endif // KAPOW_SESSION_H gottcode-kapow-350ecea/src/session_delegate.cpp000066400000000000000000000072201514263554100217470ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2012 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "session_delegate.h" #include #include #include #include #include #include #include #include //----------------------------------------------------------------------------- SessionDelegate::SessionDelegate(QObject* parent) : QStyledItemDelegate(parent) , m_ratio(1) { m_height = std::max(QDateEdit().sizeHint().height(), QLineEdit().sizeHint().height()); } //----------------------------------------------------------------------------- void SessionDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); if (!index.parent().isValid()) { if ((index.model()->rowCount() - 1) > index.row()) { // Set up drawing of billed rows if (index.data(Qt::UserRole).toBool()) { opt.palette.setBrush(QPalette::Text, opt.palette.brush(QPalette::Disabled, QPalette::Text)); } } else { // Set up drawing of unbilled totals row opt.features |= QStyleOptionViewItem::Alternate; opt.font.setWeight(QFont::Bold); opt.state &= ~QStyle::State_HasFocus; } // Draw text QStyledItemDelegate::paint(painter, opt, index); } else { // Set up drawing of totals row opt.features |= QStyleOptionViewItem::Alternate; opt.font.setWeight(QFont::Bold); opt.palette.setBrush(QPalette::Text, opt.palette.brush(QPalette::Disabled, QPalette::Text)); opt.palette.setBrush(QPalette::AlternateBase, opt.palette.brush(QPalette::Disabled, QPalette::AlternateBase)); opt.state &= ~QStyle::State_HasFocus; // Draw text QStyledItemDelegate::paint(painter, opt, index); // Draw drop shadow below totals row painter->save(); painter->translate(0, opt.rect.bottom() + 1); painter->scale(1.0, 1.0 / m_ratio); int y = 0; QColor color(0,0,0); for (int i = 0, end = m_alphas.size(); i < end; ++i) { color.setAlpha(m_alphas[i]); painter->setPen(color); painter->drawLine(opt.rect.left(), y, opt.rect.right(), y); --y; } painter->restore(); } } //----------------------------------------------------------------------------- void SessionDelegate::setDevicePixelRatio(int ratio) { m_ratio = ratio; const int count = m_ratio * 5; m_alphas.resize(count); const qreal delta = 1.0 / m_ratio; for (int i = 0; i < count; ++i) { const qreal x = i * delta; qreal y = (-0.75 * x * x * x) + (11.875 * x * x) + (-60.0 * x) + 99; m_alphas[i] = std::lround(y); } } //----------------------------------------------------------------------------- void SessionDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { QByteArray prop = editor->metaObject()->userProperty().name(); if (!model->setData(index, editor->property(prop), Qt::EditRole)) { QMessageBox::warning(nullptr, tr("Error"), tr("Session conflicts with other sessions.")); } } //----------------------------------------------------------------------------- QSize SessionDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { QSize size; if (index.parent().isValid() || (index.model()->rowCount() - 1) == index.row()) { QStyleOptionViewItem opt = option; opt.font.setWeight(QFont::Bold); size = QStyledItemDelegate::sizeHint(opt, index); size.setHeight(size.height() + (3 * m_ratio)); } else { size.setWidth(QStyledItemDelegate::sizeHint(option, index).width()); size.setHeight(m_height); } return size; } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/session_delegate.h000066400000000000000000000014101514263554100214070ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2012 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_SESSION_DELEGATE_H #define KAPOW_SESSION_DELEGATE_H #include class SessionDelegate : public QStyledItemDelegate { public: explicit SessionDelegate(QObject* parent = nullptr); void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; void setDevicePixelRatio(int ratio); void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override; private: int m_height; int m_ratio; QList m_alphas; }; #endif // KAPOW_SESSION_DELEGATE_H gottcode-kapow-350ecea/src/session_dialog.cpp000066400000000000000000000046231514263554100214400ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2008 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "session_dialog.h" #include "session.h" #include "settings.h" #include #include #include //----------------------------------------------------------------------------- SessionDialog::SessionDialog(QWidget* parent) : QDialog(parent) { setWindowTitle(tr("Add Session")); m_date = new QDateEdit(QDate::currentDate(), this); m_date->setCalendarPopup(true); QString format = QLocale().timeFormat(QLocale::LongFormat).contains("AP", Qt::CaseInsensitive) ? "h:mm:ss AP" : "HH:mm:ss"; m_start = new QTimeEdit(QTime::currentTime(), this); m_start->setDisplayFormat(format); m_stop = new QTimeEdit(QTime::currentTime(), this); m_stop->setDisplayFormat(format); m_task = new QLineEdit(this); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this); connect(buttons, &QDialogButtonBox::accepted, this, &SessionDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &SessionDialog::reject); QFormLayout* item_layout = new QFormLayout; item_layout->setContentsMargins(0, 0, 0, 0); item_layout->addRow(tr("Date:"), m_date); item_layout->addRow(tr("Start:"), m_start); item_layout->addRow(tr("Stop:"), m_stop); item_layout->addRow(tr("Task:"), m_task); QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(item_layout); layout->addStretch(); layout->addWidget(buttons); resize(Settings().value("SessionDialog/Size").toSize()); } //----------------------------------------------------------------------------- void SessionDialog::setSession(const Session& session) { setWindowTitle(tr("Edit Session")); m_date->setDate(session.date()); m_start->setTime(session.start()); m_stop->setTime(session.stop()); m_task->setText(session.task()); } //----------------------------------------------------------------------------- void SessionDialog::accept() { m_session = Session(m_date->date(), m_start->time(), m_stop->time(), m_task->text(), false); QDialog::accept(); } //----------------------------------------------------------------------------- void SessionDialog::hideEvent(QHideEvent* event) { Settings().setValue("SessionDialog/Size", size()); QDialog::hideEvent(event); } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/session_dialog.h000066400000000000000000000013271514263554100211030ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2008 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_SESSION_DIALOG_H #define KAPOW_SESSION_DIALOG_H #include "session.h" #include #include #include #include class SessionDialog : public QDialog { Q_OBJECT public: explicit SessionDialog(QWidget* parent = nullptr); Session session() const { return m_session; } void setSession(const Session& session); public: void accept() override; protected: void hideEvent(QHideEvent* event) override; private: Session m_session; QDateEdit* m_date; QTimeEdit* m_start; QTimeEdit* m_stop; QLineEdit* m_task; }; #endif // KAPOW_SESSION_DIALOG_H gottcode-kapow-350ecea/src/session_model.cpp000066400000000000000000000405201514263554100212750ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2008 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "session_model.h" #include "session.h" #include #include #include //----------------------------------------------------------------------------- static void sortNewestToOldest(QList& rows) { std::sort(rows.begin(), rows.end(), std::greater()); } //----------------------------------------------------------------------------- SessionModel::SessionModel(QObject* parent) : QAbstractItemModel(parent) , m_decimals(true) , m_loaded(true) { } //----------------------------------------------------------------------------- bool SessionModel::isLastBilled(int pos) const { if (m_billed.isEmpty() || pos > m_billed.last()) { return false; } const int size = m_billed.size(); if ((size > 1) && (pos <= m_billed[size - 2])) { return false; } else { return true; } } //----------------------------------------------------------------------------- void SessionModel::fixConflict(const QDateTime& current_start, QDateTime& current_stop) const { for (int pos = m_data.count(); pos > 0; --pos) { const Session& session = m_data.at(pos - 1); const QDateTime start(session.date(), session.start()); if ((current_start < start) && (current_stop >= start)) { current_stop = start.addSecs(-1); } else { break; } } } //----------------------------------------------------------------------------- bool SessionModel::hasConflict(const QDateTime& current) const { for (int pos = m_data.count(); pos > 0; --pos) { const Session& session = m_data.at(pos - 1); if (session.date() == current.date()) { if ((session.stop() >= current.time()) && (session.start() <= current.time())) { return true; } else if (session.stop() < current.time()) { break; } } else if (session.date() < current.date()) { break; } } return false; } //----------------------------------------------------------------------------- void SessionModel::beginLoad() { m_loaded = false; } //----------------------------------------------------------------------------- void SessionModel::endLoad() { m_loaded = true; // Store billed status for (int pos = 0, count = m_data.count(); pos < count; ++pos) { const Session& session = m_data.at(pos); if (session.isBilled()) { m_billed.append(pos); } } // Find totals for sessions updateTotals(); } //----------------------------------------------------------------------------- bool SessionModel::add(const QDateTime& start, const QDateTime& stop, const QString& task) { // Prevent adding invalid sessions if (stop < start) { return false; } // Add single session if it does not cross midnight if (start.date() == stop.date()) { return add(Session(start.date(), start.time(), stop.time(), task, false)); } QList sessions; // Split session at first midnight sessions.append(Session(start.date(), start.time(), QTime(23, 59, 59), task, false)); if (findPosition(sessions.last()) == -1) { return false; } // Split full days between start date and stop date QDate date = start.date(); while ((date = date.addDays(1)) != stop.date()) { sessions.append(Session(date, QTime(0, 0, 0), QTime(23, 59, 59), task, false)); if (findPosition(sessions.last()) == -1) { return false; } } // Split session from last midnight sessions.append(Session(stop.date(), QTime(0, 0, 0), stop.time(), task, false)); if (findPosition(sessions.last()) == -1) { return false; } // Add the split sessions for (const Session& session : std::as_const(sessions)) { add(session); } return true; } //----------------------------------------------------------------------------- bool SessionModel::add(const Session& session) { // Find position of session const int pos = findPosition(session); if (pos == -1) { return false; } // Insert session if (!m_loaded) { m_data.insert(pos, session); return true; } beginInsertRows(QModelIndex(), pos, pos); m_data.insert(pos, session); endInsertRows(); // Set billed status if (session.isBilled()) { setBilled(pos, true); } // Increase totals for sessions updateTotals(); return true; } //----------------------------------------------------------------------------- bool SessionModel::edit(int pos, const Session& session) { if (!session.isValid() || isBilled(pos)) { return false; } Q_ASSERT(pos < m_data.count()); Session current = m_data.at(pos); // Replace session remove(pos); if (add(Session(session.date(), session.start(), session.stop(), session.task(), current.isBilled())) == false) { const QDateTime temp = m_max_datetime; m_max_datetime = QDateTime(); add(current); m_max_datetime = temp; return false; } else { return true; } } //----------------------------------------------------------------------------- bool SessionModel::remove(int pos) { if (!canRemove(pos)) { return false; } // Remove session beginRemoveRows(QModelIndex(), pos, pos); m_data.removeAt(pos); endRemoveRows(); // Increase totals for sessions updateTotals(); return true; } //----------------------------------------------------------------------------- int SessionModel::remove(QList rows) { sortNewestToOldest(rows); int result = 0; for (int row : std::as_const(rows)) { result += remove(row); } return result; } //----------------------------------------------------------------------------- bool SessionModel::take(SessionModel* model, int pos) { if (!model || !model->canRemove(pos)) { return false; } // Attempt to add session if (!add(model->session(pos))) { return false; } // Remove session from source model->remove(pos); return true; } //----------------------------------------------------------------------------- bool SessionModel::take(SessionModel* model, QList rows) { if (!model) { return false; } sortNewestToOldest(rows); // Fetch sessions from source if they can be moved QList sessions; for (int pos : std::as_const(rows)) { if (!model->canRemove(pos)) { return false; } sessions.append(model->session(pos)); if (findPosition(sessions.last()) == -1) { return false; } } // Add sessions for (const Session& session : std::as_const(sessions)) { add(session); } // Remove sessions from source for (int pos : std::as_const(rows)) { model->remove(pos); } return true; } //----------------------------------------------------------------------------- void SessionModel::setBilled(int pos, bool billed) { Q_ASSERT(pos < m_data.count()); if (!billed) { m_billed.removeAll(pos); } else { Q_ASSERT(!m_billed.contains(pos)); m_billed.append(pos); std::sort(m_billed.begin(), m_billed.end()); } m_data[pos].setBilled(billed); updateTotals(); } //----------------------------------------------------------------------------- void SessionModel::setDecimalTotals(bool decimals) { m_decimals = decimals; Q_EMIT dataChanged(index(0, 0), index(rowCount(), columnCount())); } //----------------------------------------------------------------------------- void SessionModel::setMaximumDateTime(const QDateTime& max) { m_max_datetime = max; } //----------------------------------------------------------------------------- void SessionModel::toXml(QXmlStreamWriter& xml) const { for (const Session& session : m_data) { session.toXml(xml); } } //----------------------------------------------------------------------------- int SessionModel::rowCount(const QModelIndex& parent) const { if (!parent.isValid()) { return m_data.count() + 1; } else if ((parent.internalId() == UINT_MAX) && m_billed.contains(parent.row())) { return 1; } else { return 0; } } //----------------------------------------------------------------------------- int SessionModel::columnCount(const QModelIndex&) const { return 10; } //----------------------------------------------------------------------------- QVariant SessionModel::data(const QModelIndex& index, int role) const { Q_ASSERT(index.isValid()); QVariant result; int pos = index.row(); if (index.parent().isValid() || (pos == m_data.count())) { Session session; if (!index.parent().isValid()) { --pos; session = m_data.value(pos); if (session.isBilled()) { session = Session(); } } else { session = m_data.value(index.parent().row()); } switch (role) { case Qt::DisplayRole: switch(index.column()) { case 0: result = tr("Total"); break; case 1: case 2: case 3: result = QString(); break; case 4: result = session.total(Session::Total, m_decimals); break; case 5: result = session.total(Session::Daily, m_decimals); break; case 6: result = session.total(Session::Weekly, m_decimals); break; case 7: result = session.total(Session::Monthly, m_decimals); break; case 8: result = session.total(Session::Total, m_decimals); break; default: break; } break; case Qt::ToolTipRole: switch(index.column()) { case 4: result = session.total(Session::Total, !m_decimals, true); break; case 5: result = session.total(Session::Daily, !m_decimals, true); break; case 6: result = session.total(Session::Weekly, !m_decimals, true); break; case 7: result = session.total(Session::Monthly, !m_decimals, true); break; case 8: result = session.total(Session::Total, !m_decimals, true); break; default: break; } break; case Qt::TextAlignmentRole: if (index.column() == 0) { result = static_cast(Qt::AlignLeft | Qt::AlignVCenter); } else if (index.column() != 3) { result = static_cast(Qt::AlignRight | Qt::AlignVCenter); } break; default: break; } return result; } QLocale locale; Session session = m_data.value(pos); switch (role) { case Qt::DisplayRole: switch (index.column()) { case 0: result = locale.toString(session.date(), QLocale::ShortFormat); break; case 1: result = locale.toString(session.start(), QLocale::ShortFormat); break; case 2: result = locale.toString(session.stop(), QLocale::ShortFormat); break; case 3: result = session.task(); break; case 4: result = session.total(Session::Duration, m_decimals); break; case 5: result = session.total(Session::Daily, m_decimals); break; case 6: result = session.total(Session::Weekly, m_decimals); break; case 7: result = session.total(Session::Monthly, m_decimals); break; case 8: result = session.total(Session::Total, m_decimals); break; default: break; } break; case Qt::ToolTipRole: switch (index.column()) { case 3: result = session.task(); break; case 4: result = session.total(Session::Duration, !m_decimals, true); break; case 5: result = session.total(Session::Daily, !m_decimals, true); break; case 6: result = session.total(Session::Weekly, !m_decimals, true); break; case 7: result = session.total(Session::Monthly, !m_decimals, true); break; case 8: result = session.total(Session::Total, !m_decimals, true); break; default: break; } break; case Qt::TextAlignmentRole: if (index.column() != 3) { result = static_cast(Qt::AlignRight | Qt::AlignVCenter); } else { result = static_cast(Qt::AlignLeft | Qt::AlignVCenter); } break; case Qt::CheckStateRole: if (index.column() == 9) { result = m_data.at(index.row()).isBilled() ? Qt::Checked : Qt::Unchecked; } break; case Qt::EditRole: Q_ASSERT(!isBilled(index.row())); switch (index.column()) { case 0: result = session.date(); break; case 1: result = session.start(); break; case 2: result = session.stop(); break; case 3: result = session.task(); break; default: break; } break; case Qt::UserRole: result = isBilled(index.row()); break; default: break; } return result; } //----------------------------------------------------------------------------- Qt::ItemFlags SessionModel::flags(const QModelIndex& index) const { Qt::ItemFlags result = QAbstractItemModel::flags(index); if (index.parent().isValid() || (index.row() == m_data.count())) { result = Qt::ItemIsEnabled; } else if (index.column() == 9) { if (!isBilled(index.row()) || (index.row() == m_billed.last())) { result |= Qt::ItemIsUserCheckable; } } else if (!isBilled(index.row()) && (index.column() <= 3)) { result |= Qt::ItemIsEditable; } return result; } //----------------------------------------------------------------------------- QVariant SessionModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation != Qt::Horizontal) { return QVariant(); } if (role == Qt::DisplayRole) { switch (section) { case 0: return tr("Date"); case 1: return tr("Start"); case 2: return tr("Stop"); case 3: return tr("Task"); case 4: return tr("Hours"); case 5: return tr("Daily"); case 6: return tr("Weekly"); case 7: return tr("Monthly"); case 8: return tr("Total"); case 9: return tr("Report"); default: return QVariant(); } } else if (role == Qt::TextAlignmentRole) { return Qt::AlignCenter; } else { return QVariant(); } } //----------------------------------------------------------------------------- QModelIndex SessionModel::index(int row, int column, const QModelIndex& parent) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); } if (!parent.isValid()) { return createIndex(row, column, UINT_MAX); } else { return createIndex(row, column, parent.row()); } } //----------------------------------------------------------------------------- QModelIndex SessionModel::parent(const QModelIndex& child) const { if (!child.isValid()) { return QModelIndex(); } quintptr row = child.internalId(); if (row == UINT_MAX) { return QModelIndex(); } else { return createIndex(row, 0, UINT_MAX); } } //----------------------------------------------------------------------------- bool SessionModel::setData(const QModelIndex& index, const QVariant& value, int role) { if (!isBilled(index.row()) && role == Qt::EditRole) { Session session = m_data.at(index.row()); QDate date = session.date(); QTime start = session.start(); QTime stop = session.stop(); QString task = session.task(); switch (index.column()) { case 0: date = value.toDate(); break; case 1: start = value.toTime(); break; case 2: stop = value.toTime(); break; case 3: task = value.toString(); break; default: break; } if (edit(index.row(), Session(date, start, stop, task, false))) { return true; } else { return false; } } else if (index.column() == 9 && role == Qt::CheckStateRole) { setBilled(index.row(), value.toInt() == Qt::Checked); return true; } else { return QAbstractItemModel::setData(index, value, role); } } //----------------------------------------------------------------------------- int SessionModel::findPosition(const Session& session) const { if (!session.isValid()) { return -1; } // Prevent intersecting current running timer if (m_max_datetime.isValid()) { if ((QDateTime(session.date(), session.start()) >= m_max_datetime) || (QDateTime(session.date(), session.stop()) >= m_max_datetime)) { return -1; } } // Find session position int pos = 0; for (pos = m_data.count(); pos > 0; --pos) { const Session& current = m_data.at(pos - 1); if (session.date() > current.date() || (session.date() == current.date() && session.stop() > current.stop())) { break; } } pos = std::max(pos, 0); // Prevent intersecting sessions if (pos > 0) { const Session& current = m_data.at(pos - 1); if (QDateTime(session.date(), session.start()) < QDateTime(current.date(), current.stop())) { return -1; } } if (pos < m_data.count()) { const Session& current = m_data.at(pos); if (QDateTime(session.date(), session.stop()) > QDateTime(current.date(), current.start())) { return -1; } } // Prevent adding to billed if (isBilled(pos)) { return -1; } return pos; } //----------------------------------------------------------------------------- void SessionModel::updateTotals() { Session current, previous; for (int i = 0; i < m_data.count(); ++i) { current = m_data.at(i); current.updateTotals(previous); previous = current; } Q_EMIT dataChanged(index(0, 0), index(rowCount(), columnCount())); Q_EMIT billedStatusChanged(current.isBilled()); } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/session_model.h000066400000000000000000000045441514263554100207500ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2008 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_SESSION_MODEL_H #define KAPOW_SESSION_MODEL_H #include "session.h" #include #include class SessionModel : public QAbstractItemModel { Q_OBJECT public: explicit SessionModel(QObject* parent = nullptr); QList billedRows() const { return m_billed; } bool canBill() const { return !m_data.isEmpty() && !isBilled(m_data.size() - 1); } bool isBilled(int pos) const { return (!m_billed.isEmpty() && pos <= m_billed.last()); } bool isLastBilled(int pos) const; void fixConflict(const QDateTime& current_start, QDateTime& current_stop) const; bool hasConflict(const QDateTime& current) const; Session session(int pos) const { return m_data.value(pos); } void beginLoad(); void endLoad(); bool add(const QDateTime& start, const QDateTime& stop, const QString& task); bool add(const Session& session); bool edit(int row, const Session& session); bool remove(int row); int remove(QList rows); bool take(SessionModel* model, int row); bool take(SessionModel* model, QList rows); void setBilled(int row, bool billed); void setDecimalTotals(bool decimals); void setMaximumDateTime(const QDateTime& max); void toXml(QXmlStreamWriter& xml) const; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; Qt::ItemFlags flags(const QModelIndex& index) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex& child) const override; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; Q_SIGNALS: void billedStatusChanged(bool billed); private: bool canRemove(int pos) const { return (pos < m_data.count()) && !isBilled(pos); } int findPosition(const Session& session) const; void updateTotals(); private: QList m_data; QList m_billed; QDateTime m_max_datetime; bool m_decimals; bool m_loaded; }; #endif // KAPOW_SESSION_MODEL_H gottcode-kapow-350ecea/src/settings.cpp000066400000000000000000000020661514263554100202750ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2012 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "settings.h" #include //----------------------------------------------------------------------------- static QString f_path; static QWeakPointer f_settings; //----------------------------------------------------------------------------- Settings::Settings() { if (f_settings) { m_settings = f_settings; } else if (f_path.isEmpty()) { f_settings = m_settings = QSharedPointer(new QSettings); } else { f_settings = m_settings = QSharedPointer(new QSettings(f_path, QSettings::IniFormat)); } } //----------------------------------------------------------------------------- void Settings::setPath(const QString& path) { // Set path f_path = path; if (f_path.isEmpty()) { return; } // Make sure location of INI file exists QDir dir(f_path + "/../"); if (!dir.exists()) { dir.mkpath(dir.absolutePath()); } } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/settings.h000066400000000000000000000012641514263554100177410ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2012 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_SETTINGS_H #define KAPOW_SETTINGS_H #include #include class Settings { public: explicit Settings(); void remove(const QString& key) { m_settings->remove(key); } void setValue(const QString& key, const QVariant& value) { m_settings->setValue(key, value); } QVariant value(const QString& key, const QVariant& defaultValue = QVariant()) const { return m_settings->value(key, defaultValue); } static void setPath(const QString& path); private: QSharedPointer m_settings; }; #endif // KAPOW_SETTINGS_H gottcode-kapow-350ecea/src/time_editor.cpp000066400000000000000000000007561514263554100207450ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2008 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "time_editor.h" //----------------------------------------------------------------------------- TimeEditor::TimeEditor(QWidget* parent) : QTimeEdit(parent) { setDisplayFormat(QLocale().timeFormat(QLocale::LongFormat).contains("AP", Qt::CaseInsensitive) ? "h:mm:ss AP" : "HH:mm:ss"); } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/time_editor.h000066400000000000000000000005161514263554100204040ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2008 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_TIME_EDITOR_H #define KAPOW_TIME_EDITOR_H #include class TimeEditor : public QTimeEdit { Q_OBJECT public: explicit TimeEditor(QWidget* parent = nullptr); }; #endif // KAPOW_TIME_EDITOR_H gottcode-kapow-350ecea/src/window.cpp000066400000000000000000001342711514263554100177500ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2008 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "window.h" #include "contact.h" #include "date_editor.h" #include "filter_model.h" #include "locale_dialog.h" #include "project.h" #include "project_delegate.h" #include "report.h" #include "session.h" #include "session_delegate.h" #include "session_dialog.h" #include "session_model.h" #include "settings.h" #include "time_editor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //----------------------------------------------------------------------------- Window::Window(const QString& filename, bool backups_enabled, bool start_minimized_flag, QWidget* parent) : QMainWindow(parent) , m_filename(filename) , m_valid(true) , m_blocked(false) , m_backups_enabled(backups_enabled) , m_decimals(true) , m_inline(true) , m_closetotray(false) , m_start_minimized(false) , m_active_project(nullptr) , m_active_model(nullptr) { QWidget* contents = new QWidget(this); setCentralWidget(contents); m_display = new QLabel(tr("00:00:00"), contents); QFont font = m_display->font(); font.setPointSize(32); m_display->setFont(font); m_current_time = QDateTime::currentDateTime(); m_timer = new QTimer(this); m_timer->setInterval(1000); connect(m_timer, &QTimer::timeout, this, &Window::updateTime); m_timer->start(); m_save_timer = new QTimer(this); m_save_timer->setInterval(30000); connect(m_save_timer, &QTimer::timeout, this, &Window::save); m_task = new QLineEdit(contents); m_task->setPlaceholderText(SessionModel::tr("Task")); m_task->setFocus(); connect(m_task, &QLineEdit::textChanged, this, &Window::taskChanged); connect(m_task, &QLineEdit::returnPressed, this, &Window::taskStart); m_start = new QPushButton(tr("Start"), contents); m_start->setAutoDefault(true); connect(m_start, &QPushButton::clicked, this, &Window::start); int button_width = m_start->sizeHint().width(); m_start_session = new QAction(tr("Start"), this); m_start_session->setEnabled(true); connect(m_start_session, &QAction::triggered, this, &Window::start); m_stop = new QPushButton(tr("Stop"), contents); m_stop->setAutoDefault(true); m_stop->hide(); connect(m_stop, &QPushButton::clicked, this, &Window::stop); button_width = std::max(m_stop->sizeHint().width(), button_width); m_stop_session = new QAction(tr("Stop"), this); m_stop_session->setEnabled(false); connect(m_stop_session, &QAction::triggered, this, &Window::stop); m_cancel = new QPushButton(tr("Cancel"), contents); m_cancel->setAutoDefault(true); m_cancel->setEnabled(false); connect(m_cancel, &QPushButton::clicked, this, &Window::cancel); button_width = std::max(m_cancel->sizeHint().width(), button_width); m_cancel_session = new QAction(tr("Cancel"), this); m_cancel_session->setEnabled(false); connect(m_cancel_session, &QAction::triggered, this, &Window::cancel); m_start->setMinimumWidth(button_width); m_stop->setMinimumWidth(button_width); m_cancel->setMinimumWidth(button_width); m_tray_start_session = new QAction(tr("Start"), this); m_tray_start_session->setEnabled(true); connect(m_tray_start_session, &QAction::triggered, this, &Window::start); m_tray_stop_session = new QAction(tr("Stop"), this); m_tray_stop_session->setEnabled(false); m_tray_stop_session->setVisible(false); connect(m_tray_stop_session, &QAction::triggered, this, &Window::stopRunningProject); m_tray_stop_all_session = new QAction(tr("Stop All"), this); m_tray_stop_all_session->setEnabled(false); m_tray_stop_all_session->setVisible(false); connect(m_tray_stop_all_session, &QAction::triggered, this, &Window::stopAll); m_tray_cancel_session = new QAction(tr("Cancel"), this); m_tray_cancel_session->setEnabled(false); m_tray_cancel_session->setVisible(false); connect(m_tray_cancel_session, &QAction::triggered, this, &Window::cancelRunningProject); m_toggle_visibility = new QAction(tr("&Minimize"), this); connect(m_toggle_visibility, &QAction::triggered, this, &Window::toggleVisible); // Load settings Settings settings; m_decimals = settings.value("DecimalTotals", true).toBool(); m_inline = settings.value("InlineEditing", true).toBool(); m_closetotray = settings.value("CloseToTray", false).toBool(); m_start_minimized = settings.value("StartMinimized", false).toBool(); // Create menus QMenu* menu = menuBar()->addMenu(tr("&Project")); m_add_project = menu->addAction(tr("&Add"), this, qOverload<>(&Window::addProject)); m_add_project->setShortcut(tr("Ctrl+Shift+N")); m_remove_project = menu->addAction(tr("&Remove"), this, qOverload<>(&Window::removeProject)); m_remove_project->setShortcut(tr("Ctrl+Shift+Delete")); m_remove_project->setEnabled(false); menu->addSeparator(); m_create_report = menu->addAction(tr("&Create Report..."), this, &Window::createReport); m_create_report->setEnabled(false); m_remove_report = menu->addAction(tr("Re&move Report"), this, &Window::removeReport); m_remove_report->setEnabled(false); m_view_reports = menu->addAction(tr("View R&eports"), this, &Window::viewReports); m_view_reports->setEnabled(false); menu->addSeparator(); QAction* quit_action = menu->addAction(tr("&Quit"), this, &Window::quit); quit_action->setShortcut(tr("Ctrl+Q")); quit_action->setMenuRole(QAction::QuitRole); menu = menuBar()->addMenu(tr("&Session")); m_add_session = menu->addAction(tr("&Add"), this, &Window::addSession); m_add_session->setShortcut(QKeySequence::New); m_edit_session = menu->addAction(tr("&Edit"), this, &Window::editSession); m_edit_session->setEnabled(false); m_remove_session = menu->addAction(tr("&Remove"), this, &Window::removeSessions); m_remove_session->setShortcut(tr("Ctrl+Delete")); m_remove_session->setEnabled(false); m_move_session = menu->addAction(tr("&Move To..."), this, &Window::moveSessions); m_move_session->setEnabled(false); menu = menuBar()->addMenu(tr("S&ettings")); QMenu* column_menu = menu->addMenu(tr("Columns")); QAction* action = menu->addAction(tr("&Decimal Totals")); action->setCheckable(true); action->setChecked(m_decimals); connect(action, &QAction::toggled, this, &Window::setDecimalTotals); action = menu->addAction(tr("&Inline Editing")); action->setCheckable(true); action->setChecked(m_inline); connect(action, &QAction::toggled, this, &Window::setInlineEditing); action = menu->addAction(tr("&Close to Tray")); action->setCheckable(true); action->setChecked(m_closetotray); connect(action, &QAction::toggled, this, &Window::setCloseToTray); action = menu->addAction(tr("&Start Minimized")); action->setCheckable(true); action->setChecked(m_start_minimized); connect(action, &QAction::toggled, this, &Window::setStartMinimized); menu->addSeparator(); menu->addAction(tr("Application &Language..."), this, &Window::setLocaleClicked); menu = menuBar()->addMenu(tr("&Help")); action = menu->addAction(tr("&About"), this, &Window::about); action->setMenuRole(QAction::AboutRole); action = menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); action->setMenuRole(QAction::AboutQtRole); QAction* actions_separator = new QAction(this); actions_separator->setSeparator(true); QMenu* context_menu = new QMenu(this); context_menu->addAction(m_tray_start_session); context_menu->addAction(m_tray_stop_session); context_menu->addAction(m_tray_stop_all_session); context_menu->addAction(m_tray_cancel_session); context_menu->addSeparator(); context_menu->addAction(m_toggle_visibility); context_menu->addAction(quit_action); // Create projects m_projects = new QTreeWidget(contents); m_projects->setAutoExpandDelay(500); m_projects->setDragEnabled(true); m_projects->setDragDropMode(QAbstractItemView::InternalMove); m_projects->setHeaderLabels(QStringList() << tr("Project") << tr("Timer")); m_projects->setItemDelegate(new ProjectDelegate(m_projects)); m_projects->setSelectionMode(QAbstractItemView::SingleSelection); m_projects->setSelectionBehavior(QAbstractItemView::SelectRows); m_projects->setSortingEnabled(true); m_projects->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); m_projects->sortByColumn(0, Qt::AscendingOrder); m_projects->header()->setSortIndicatorShown(false); m_projects->header()->setStretchLastSection(false); m_projects->header()->setSectionsClickable(false); m_projects->header()->setSectionsMovable(false); m_projects->header()->setSectionResizeMode(0, QHeaderView::Stretch); m_projects->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); m_projects->addAction(m_add_project); m_projects->addAction(m_remove_project); m_projects->addAction(actions_separator); m_projects->addAction(m_start_session); m_projects->addAction(m_stop_session); m_projects->addAction(m_cancel_session); m_projects->setContextMenuPolicy(Qt::ActionsContextMenu); connect(m_projects, &QTreeWidget::currentItemChanged, this, &Window::projectActivated); connect(m_projects, &QTreeWidget::itemChanged, this, &Window::projectChanged); // Create details QItemEditorFactory* factory = new QItemEditorFactory; factory->registerEditor(QMetaType::QDate, new QStandardItemEditorCreator()); factory->registerEditor(QMetaType::QTime, new QStandardItemEditorCreator()); factory->registerEditor(QMetaType::QString, new QStandardItemEditorCreator()); QItemEditorFactory::setDefaultFactory(factory); QWidget* details = new QWidget(contents); m_filter = new QComboBox(details); m_filter->addItem(tr("Show all"), FilterModel::All); m_filter->addItem(tr("Show only unbilled"), FilterModel::Unbilled); m_filter->addItem(tr("Show only this year"), FilterModel::ThisYear); m_filter->addItem(tr("Show only this month"), FilterModel::ThisMonth); m_filter->addItem(tr("Show only this week"), FilterModel::ThisWeek); connect(m_filter, &QComboBox::activated, this, &Window::filterChanged); m_details = new QTreeView(details); m_details->setUniformRowHeights(true); m_details->setRootIsDecorated(false); m_details->setItemsExpandable(false); m_details->setIndentation(0); m_details->setSelectionMode(QAbstractItemView::ExtendedSelection); m_details->setSelectionBehavior(QAbstractItemView::SelectRows); m_details->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); m_details->header()->setSectionsClickable(false); m_details->header()->setSectionsMovable(false); m_details->addAction(m_add_session); m_details->addAction(m_edit_session); m_details->addAction(m_remove_session); m_details->addAction(m_move_session); m_details->addAction(actions_separator); m_details->setContextMenuPolicy(Qt::ActionsContextMenu); connect(m_details, &QTreeView::activated, this, &Window::editSession); connect(m_details, &QTreeView::pressed, this, &Window::sessionPressed); connect(m_details->verticalScrollBar(), &QScrollBar::valueChanged, this, &Window::sessionsScrolled); m_details->setEditTriggers(QAbstractItemView::NoEditTriggers); SessionDelegate* delegate = new SessionDelegate(m_details); delegate->setDevicePixelRatio(devicePixelRatio()); m_details->setItemDelegate(delegate); QVBoxLayout* details_layout = new QVBoxLayout(details); details_layout->setContentsMargins(0, 0, 0, 0); details_layout->addWidget(m_filter); details_layout->addWidget(m_details); // Create contents splitter m_contents = new QSplitter(contents); m_contents->addWidget(m_projects); m_contents->addWidget(details); m_contents->setStretchFactor(0, 0); m_contents->setStretchFactor(1, 1); // Add tray icon m_active_icon = QIcon(":/kapow.png"); const QList sizes = m_active_icon.availableSizes(); for (const QSize& size : sizes) { m_inactive_icon.addPixmap(m_active_icon.pixmap(size, QIcon::Disabled)); } m_tray_icon = new QSystemTrayIcon(m_inactive_icon, this); m_tray_icon->setContextMenu(context_menu); updateTrayIcon(); connect(m_tray_icon, &QSystemTrayIcon::activated, this, &Window::trayIconActivated); m_tray_icon->show(); // Lay out window QHBoxLayout* session_buttons = new QHBoxLayout; session_buttons->setContentsMargins(0, 0, 0, 0); session_buttons->setSpacing(0); session_buttons->addStretch(1); session_buttons->addWidget(m_task, 2); session_buttons->addSpacing(12); session_buttons->addWidget(m_start); session_buttons->addWidget(m_stop); session_buttons->addSpacing(6); session_buttons->addWidget(m_cancel); session_buttons->addStretch(1); QVBoxLayout* session_layout = new QVBoxLayout; session_layout->setContentsMargins(0, 0, 0, 0); session_layout->setSpacing(0); session_layout->addWidget(m_display, 0, Qt::AlignCenter); session_layout->addLayout(session_buttons); QVBoxLayout* layout = new QVBoxLayout(contents); layout->setContentsMargins(0, 0, 0, 0); layout->addLayout(session_layout, 0); layout->addSpacing(6); layout->addWidget(m_contents, 1); // Restore window geometry resize(800, 600); restoreGeometry(settings.value("WindowGeometry").toByteArray()); m_contents->restoreState(settings.value("SplitterSizes").toByteArray()); // Start in tray if requested if (start_minimized_flag || m_start_minimized) { minimizeToTray(); } else { show(); } // Load details of all projects loadData(); if (!m_valid) { return; } // Add column actions QList column_actions; for (int i = 3; i < 10; ++i) { action = column_menu->addAction(m_active_model->headerData(i, Qt::Horizontal).toString()); action->setCheckable(true); action->setChecked(true); connect(action, &QAction::triggered, this, [this, i] { toggleColumnHidden(i); }); column_actions.append(action); } m_details->header()->addActions(column_actions); m_details->header()->setContextMenuPolicy(Qt::ActionsContextMenu); m_details->header()->setSectionResizeMode(QHeaderView::ResizeToContents); m_details->header()->setSectionResizeMode(3, QHeaderView::Stretch); m_details->header()->setStretchLastSection(false); // Restore hidden columns const QStringList hidden = settings.value("HiddenColumns", QStringList() << "5" << "6" << "7" << "8" << "9").toStringList(); for (const QString& column : hidden) { int i = column.toInt(); m_details->setColumnHidden(i, true); column_actions[i - 3]->setChecked(false); } } //----------------------------------------------------------------------------- bool Window::isValid() const { return m_valid; } //----------------------------------------------------------------------------- void Window::raiseWindow() { show(); activateWindow(); raise(); } //----------------------------------------------------------------------------- bool Window::event(QEvent* event) { if (event->type() == QEvent::WindowBlocked) { m_blocked = true; updateTrayActions(); } else if (event->type() == QEvent::WindowUnblocked) { m_blocked = false; updateTrayActions(); } return QMainWindow::event(event); } //----------------------------------------------------------------------------- void Window::closeEvent(QCloseEvent* event) { Settings settings; settings.setValue("WindowGeometry", saveGeometry()); settings.setValue("SplitterSizes", m_contents->saveState()); bool visible = isVisible(); if (visible && m_closetotray) { event->ignore(); minimizeToTray(); return; } if (!m_active_timers.isEmpty()) { // Show window if (!visible) { show(); } raise(); activateWindow(); // Prompt user about running timers if (QMessageBox::question(this, tr("Question"), tr("There are timers running. Stop timers and quit?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { for (Project* project : std::as_const(m_active_timers)) { project->stop(m_current_time); } m_active_timers.clear(); } else { event->ignore(); if (!visible) { hide(); } return; } } m_save_timer->stop(); save(); event->accept(); // Remove tray icon so that app will quit delete m_tray_icon; m_tray_icon = nullptr; } //----------------------------------------------------------------------------- void Window::showEvent(QShowEvent* event) { QMainWindow::showEvent(event); m_task->setFocus(); } //----------------------------------------------------------------------------- void Window::about() { QMessageBox::about(this, tr("About"), QString("

%1 %2
%3
%4
%5

") .arg(tr("Kapow Punch Clock"), QCoreApplication::applicationVersion(), tr("A program to help track spent time"), tr("Copyright © 2008-%1 Graeme Gott").arg("2026"), tr("Released under the
GPL 3 license").arg("\"http://www.gnu.org/licenses/gpl.html\"")) ); } //----------------------------------------------------------------------------- void Window::quit() { const bool closetotray = m_closetotray; m_closetotray = false; if (close()) { QCoreApplication::quit(); } else { m_closetotray = closetotray; } } //----------------------------------------------------------------------------- void Window::setDecimalTotals(bool decimals) { m_decimals = decimals; int count = m_projects->topLevelItemCount(); for (int i = 0; i < count; ++i) { Project* project = dynamic_cast(m_projects->topLevelItem(i)); if (project) { project->setDecimalTotals(m_decimals); } } Settings().setValue("DecimalTotals", m_decimals); } //----------------------------------------------------------------------------- void Window::setInlineEditing(bool edit) { m_inline = edit; if (!edit) { m_details->closePersistentEditor(m_details->currentIndex()); } sessionPressed(m_details->currentIndex()); Settings().setValue("InlineEditing", edit); } //----------------------------------------------------------------------------- void Window::setCloseToTray(bool closetotray) { m_closetotray = closetotray; Settings().setValue("CloseToTray", closetotray); } //----------------------------------------------------------------------------- void Window::setStartMinimized(bool minimized) { m_start_minimized = minimized; Settings().setValue("StartMinimized", minimized); } //----------------------------------------------------------------------------- void Window::setLocaleClicked() { LocaleDialog dialog(this); dialog.exec(); } //----------------------------------------------------------------------------- void Window::start() { if (!m_active_project->start(m_current_time)) { QMessageBox::warning(this, tr("Error"), tr("Session conflicts with other sessions.")); return; } m_active_timers += m_active_project; m_remove_project->setEnabled(false); updateDetails(); m_stop->setFocus(); m_start_session->setEnabled(false); m_stop_session->setEnabled(true); m_cancel_session->setEnabled(true); updateTrayActions(); if (!m_save_timer->isActive()) { m_save_timer->start(); } } //----------------------------------------------------------------------------- void Window::stop() { if (!m_active_project->stop(m_current_time)) { QMessageBox::warning(this, tr("Error"), tr("Session conflicts with other sessions.")); } m_active_timers.removeAll(m_active_project); m_remove_project->setEnabled(true); updateDetails(); m_task->clear(); m_task->setFocus(); m_start_session->setEnabled(true); m_stop_session->setEnabled(false); m_cancel_session->setEnabled(false); updateTrayActions(); if (m_active_timers.isEmpty()) { m_save_timer->stop(); save(); } } //----------------------------------------------------------------------------- void Window::stopRunningProject() { if (showRunningProject()) { stop(); } } //----------------------------------------------------------------------------- void Window::stopAll() { const bool visible = isVisible(); if (!visible) { show(); } if (QMessageBox::question(this, tr("Question"), tr("Stop all timers?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { for (Project* project : std::as_const(m_active_timers)) { project->stop(m_current_time); } m_active_timers.clear(); m_remove_project->setEnabled(true); updateDetails(); m_task->clear(); m_task->setFocus(); m_start_session->setEnabled(true); m_stop_session->setEnabled(false); m_cancel_session->setEnabled(false); updateTrayActions(); m_save_timer->stop(); save(); } if (!visible) { hide(); } } //----------------------------------------------------------------------------- void Window::cancel() { if (QMessageBox::question(this, tr("Question"), tr("Cancel this session?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { m_active_project->stop(); m_active_timers.removeAll(m_active_project); m_remove_project->setEnabled(true); updateDetails(); m_task->clear(); m_task->setFocus(); m_start_session->setEnabled(true); m_stop_session->setEnabled(false); m_cancel_session->setEnabled(false); updateTrayActions(); if (m_active_timers.isEmpty()) { m_save_timer->stop(); save(); } } } //----------------------------------------------------------------------------- void Window::cancelRunningProject() { if (showRunningProject()) { const bool visible = isVisible(); if (!visible) { show(); } cancel(); if (!visible) { hide(); } } } //----------------------------------------------------------------------------- void Window::taskChanged(const QString& task) { m_active_project->setTask(task); } //----------------------------------------------------------------------------- void Window::taskStart() { if (m_start->isVisible()) { start(); } } //----------------------------------------------------------------------------- void Window::updateTime() { m_current_time = QDateTime::currentDateTime(); int count = m_projects->topLevelItemCount(); for (int i = 0; i < count; ++i) { Project* project = dynamic_cast(m_projects->topLevelItem(i)); if (project) { project->updateTime(m_current_time); } } if (m_active_project) { updateDisplay(); } if (m_active_timers.count() == 1) { m_tray_icon->setToolTip(m_active_timers.first()->time()); } } //----------------------------------------------------------------------------- void Window::addProject() { bool ok; QString name; Q_FOREVER { name = QInputDialog::getText(this, tr("Add Project"), tr("Enter project name:"), QLineEdit::Normal, name, &ok); if (ok && !name.isEmpty()) { if (m_projects->findItems(name, Qt::MatchExactly).isEmpty()) { addProject(name); break; } else { QMessageBox::warning(this, tr("Error"), tr("A project with that name already exists.")); } } else { break; } } } //----------------------------------------------------------------------------- void Window::editProject() { m_projects->edit(m_projects->currentIndex()); } //----------------------------------------------------------------------------- void Window::removeProject() { if (QMessageBox::question(this, tr("Question"), tr("Remove selected project?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { m_remove_project->setEnabled(false); m_remove_session->setEnabled(false); m_move_session->setEnabled(false); removeProject(m_projects->currentItem()); } } //----------------------------------------------------------------------------- void Window::createReport() { const int last = m_active_model->rowCount() - 2; if (last < 0) { return; } int current = currentRow(); if ((current == -1) || m_active_model->isBilled(current) || (current > last)) { current = last; } Report report(m_active_model, current, &m_contact, &m_rates, this); report.exec(); } //----------------------------------------------------------------------------- void Window::removeReport() { const auto billed = m_active_model->billedRows(); if (billed.isEmpty()) { return; } if (QMessageBox::question(this, tr("Question"), Report::tr("Remove newest report?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) { return; } m_active_model->setBilled(billed.last(), false); } //----------------------------------------------------------------------------- void Window::viewReports() { int current = currentRow(); if ((current == (m_active_model->rowCount() - 1)) || !m_active_model->isBilled(current)) { current = -1; } Report report(m_active_model, current, &m_contact, &m_rates, this); report.exec(); } //----------------------------------------------------------------------------- void Window::projectActivated(QTreeWidgetItem* item) { Project* project = dynamic_cast(item); if (!project) { addProject(tr("Untitled")); return; } if (m_active_model) { disconnect(m_active_model, &SessionModel::billedStatusChanged, this, &Window::modelBilledStatusChanged); disconnect(m_active_model, &SessionModel::rowsInserted, this, &Window::sessionsInserted); } m_active_project = project; m_active_model = m_active_project->model(); connect(m_active_model, &SessionModel::billedStatusChanged, this, &Window::modelBilledStatusChanged); connect(m_active_model, &SessionModel::rowsInserted, this, &Window::sessionsInserted); m_details->setModel(m_active_project->filterModel()); m_details->expandAll(); m_filter->setCurrentIndex(m_filter->findData(m_active_project->filterModel()->type())); updateDisplay(); updateSessionButtons(); m_remove_project->setEnabled(!m_active_project->isActive()); if (!m_active_project->time().isEmpty()) { m_start_session->setEnabled(false); m_stop_session->setEnabled(true); m_cancel_session->setEnabled(true); } else { m_start_session->setEnabled(true); m_stop_session->setEnabled(false); m_cancel_session->setEnabled(false); } m_view_reports->setEnabled(m_active_model->isBilled(0)); m_edit_session->setEnabled(false); m_remove_session->setEnabled(false); m_move_session->setEnabled(false); QCoreApplication::processEvents(); int value = m_active_project->scrollValue(); if (value != -1) { m_details->verticalScrollBar()->setValue(value); } else { m_details->scrollToBottom(); } updateWindowTitle(item->text(0)); } //----------------------------------------------------------------------------- void Window::projectChanged(QTreeWidgetItem* item, int column) { if (column == 0) { updateWindowTitle(item->text(0)); } } //----------------------------------------------------------------------------- void Window::filterChanged(int index) { m_active_project->filterModel()->setType(m_filter->itemData(index).toInt()); m_details->expandAll(); m_details->scrollToBottom(); updateReportActions(); } //----------------------------------------------------------------------------- void Window::modelBilledStatusChanged() { sessionPressed(m_details->currentIndex()); m_view_reports->setEnabled(m_active_model->isBilled(0)); m_details->expandAll(); } //----------------------------------------------------------------------------- void Window::sessionPressed(const QModelIndex& index) { const int rows = selectedUnbilledRows().size(); QModelIndex session = m_active_project->filterModel()->mapUnbilledToSource(index); const bool enabled = session.isValid() && rows; m_edit_session->setEnabled(enabled && (!m_inline || session.column() < 4) && (rows == 1)); m_remove_session->setEnabled(enabled); m_move_session->setEnabled(enabled); updateReportActions(); m_details->removeAction(m_create_report); m_details->removeAction(m_remove_report); if (!m_active_model->isBilled(m_active_project->filterModel()->mapToSource(index).row())) { m_details->addAction(m_create_report); } else if (m_active_project->filterModel()->mapLastBilledToSource(index).isValid()) { m_details->addAction(m_remove_report); } } //----------------------------------------------------------------------------- void Window::sessionsInserted(const QModelIndex&, int, int end) { m_details->setCurrentIndex(m_active_project->filterModel()->mapFromSource(m_active_model->index(end, 0))); } //----------------------------------------------------------------------------- void Window::sessionsScrolled(int value) { if (m_active_project) { m_active_project->setScrollValue(value); } } //----------------------------------------------------------------------------- void Window::addSession() { Q_ASSERT(m_active_model); SessionDialog dialog(this); Q_FOREVER { if (dialog.exec() == QDialog::Accepted) { if (m_active_model->add(dialog.session())) { m_edit_session->setEnabled(true); m_remove_session->setEnabled(true); m_move_session->setEnabled(true); save(); break; } else { QMessageBox::warning(this, tr("Error"), tr("Session conflicts with other sessions.")); } } else { break; } } } //----------------------------------------------------------------------------- void Window::editSession() { Q_ASSERT(m_active_model); QModelIndex index = m_active_project->filterModel()->mapUnbilledToSource(m_details->currentIndex()); if (!index.isValid()) { return; } if (!m_inline) { int pos = index.row(); SessionDialog dialog(this); dialog.setSession(m_active_model->session(pos)); Q_FOREVER { if (dialog.exec() == QDialog::Accepted) { if (m_active_model->edit(pos, dialog.session())) { save(); return; } else { QMessageBox::warning(this, tr("Error"), tr("Session conflicts with other sessions.")); } } else { break; } } } else if (m_active_model->flags(index) & Qt::ItemIsEditable) { m_details->edit(m_details->currentIndex()); } } //----------------------------------------------------------------------------- void Window::removeSessions() { Q_ASSERT(m_active_model); const QList rows = selectedUnbilledRows(); if (QMessageBox::question(this, tr("Question"), tr("Remove selected session(s)?", "", rows.size()), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { m_edit_session->setEnabled(false); m_remove_session->setEnabled(false); m_move_session->setEnabled(false); m_active_model->remove(rows); } } //----------------------------------------------------------------------------- void Window::moveSessions() { // Fetch selected sessions const QList rows = selectedUnbilledRows(); // Prompt for destination project QDialog dialog(this); dialog.setWindowTitle(tr("Move Session(s)", "", rows.size())); QTreeView* view = new QTreeView(&dialog); view->setSelectionMode(QAbstractItemView::SingleSelection); view->setSelectionBehavior(QAbstractItemView::SelectRows); view->setEditTriggers(QAbstractItemView::NoEditTriggers); view->setModel(m_projects->model()); view->setColumnHidden(1, true); view->setHeaderHidden(true); view->expandAll(); view->setCurrentIndex(m_projects->currentIndex()); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog); connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); QVBoxLayout* layout = new QVBoxLayout(&dialog); layout->addWidget(view); layout->addWidget(buttons); // Disable OK button if current project is selected QPushButton* button = buttons->button(QDialogButtonBox::Ok); button->setText(tr("Move")); button->setEnabled(false); connect(view->selectionModel(), &QItemSelectionModel::currentChanged, this, [button, this](const QModelIndex& index) { Project* project = dynamic_cast(m_projects->itemFromIndex(index)); button->setEnabled(project != m_active_project); }); if (dialog.exec() == QDialog::Rejected) { return; } // Fetch model of destination project const QModelIndex current = view->currentIndex(); Project* project = dynamic_cast(m_projects->itemFromIndex(current)); if (!project || (project == m_active_project)) { return; } // Move sessions if (project->model()->take(m_active_model, rows)) { // Switch to destination project m_projects->setCurrentItem(project); } else { QMessageBox::warning(this, tr("Error"), tr("Could not move session(s) because of conflicts.", "", rows.size())); } } //----------------------------------------------------------------------------- void Window::toggleColumnHidden(int column) { m_details->setColumnHidden(column, !m_details->isColumnHidden(column)); QStringList hidden; for (int i = 3; i < 10; ++i) { if (m_details->isColumnHidden(i)) { hidden.append(QString::number(i)); } } Settings().setValue("HiddenColumns", hidden); } //----------------------------------------------------------------------------- void Window::save() { if (!m_valid) { return; } // Create temporary backup of time data if (m_backups_enabled) { QFile::remove(m_filename + ".bak"); QFile::copy(m_filename, m_filename + ".bak"); } // Open file for writing QSaveFile file(m_filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { QMessageBox::critical(this, tr("Error"), tr("Unable to write time data.")); return; } // Write time data QXmlStreamWriter xml(&file); xml.setAutoFormatting(true); xml.writeStartDocument(); xml.writeStartElement("kapow"); m_contact.toXml(xml); m_rates.toXml(xml); int count = m_projects->topLevelItemCount(); for (int i = 0; i < count; ++i) { Project* project = dynamic_cast(m_projects->topLevelItem(i)); if (project) { project->toXml(xml); } } xml.writeEndDocument(); // Force time data to disk bool saved = file.commit(); if (!saved) { QMessageBox::critical(this, tr("Error"), tr("Unable to write time data.")); } } //----------------------------------------------------------------------------- void Window::trayIconActivated(QSystemTrayIcon::ActivationReason reason) { if (reason == QSystemTrayIcon::Trigger) { toggleVisible(); } } //----------------------------------------------------------------------------- void Window::toggleVisible() { if (isVisible() && !m_blocked) { minimizeToTray(); } else { restoreFromTray(); } } //----------------------------------------------------------------------------- int Window::currentRow() { QModelIndex session = m_details->currentIndex(); if (session.parent().isValid()) { session = session.parent(); } session = m_active_project->filterModel()->mapToSource(session); return session.isValid() ? session.row() : -1; } //----------------------------------------------------------------------------- QList Window::selectedUnbilledRows() const { QList rows; const QModelIndexList selected = m_details->selectionModel()->selectedIndexes(); for (const QModelIndex& index : selected) { const QModelIndex session = m_active_project->filterModel()->mapUnbilledToSource(index); // Don't list any sessions at all if even one of them is billed if (!session.isValid()) { rows.clear(); break; } // Add to list of selected rows only once const int row = session.row(); if (!rows.contains(row)) { rows.append(row); } } return rows; } //----------------------------------------------------------------------------- void Window::loadData() { // Try to load time data loadData(m_filename); if (m_valid) { if (m_backups_enabled) { createDataBackup(); } return; } if (m_backups_enabled) { // Try to load time data from temporary backup if (QFile::exists(m_filename + ".bak")) { m_valid = true; loadData(m_filename + ".bak"); if (m_valid) { return; } } // Try to load time data from any backup const QStringList backups = QFileInfo(m_filename).dir().entryList(QStringList(m_filename + ".bak-"), QDir::Files, QDir::Name | QDir::IgnoreCase | QDir::Reversed); for (const QString& backup : backups) { m_valid = true; loadData(backup); if (m_valid) { return; } } } // Try to start with empty time data m_valid = true; loadData(m_filename); } //----------------------------------------------------------------------------- void Window::loadData(const QString& filename) { // Open data file; create default project if it doesn't exist QFile file(filename); if (!file.exists()) { addProject(tr("Untitled")); m_projects->setCurrentItem(m_projects->topLevelItem(0)); return; } // Abort if data is not writable if (m_valid && file.exists() && !QFileInfo(file).isWritable()) { m_valid = false; QMessageBox::critical(this, tr("Error"), tr("Unable to write time data.")); return; } // Abort if data is unreadable if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { m_valid = false; QMessageBox::critical(this, tr("Error"), tr("Unable to read time data.")); return; } // Parse data file QStack projects; SessionModel* model = nullptr; int filter = 0; QTreeWidgetItem* item = m_projects->invisibleRootItem(); QTreeWidgetItem* current = nullptr; QXmlStreamReader xml(&file); while (!xml.atEnd()) { xml.readNext(); if (xml.isStartElement()) { QXmlStreamAttributes attributes = xml.attributes(); // Add session if ((xml.name() == QLatin1String("session")) && model) { QDate date = QDate::fromString(attributes.value(QLatin1String("date")).toString(), Qt::ISODate); QTime start = QTime::fromString(attributes.value(QLatin1String("start")).toString(), Qt::ISODate); QTime stop = QTime::fromString(attributes.value(QLatin1String("stop")).toString(), Qt::ISODate); QString task = attributes.value(QLatin1String("note")).toString(); bool billed = attributes.value(QLatin1String("billed")).toString().toInt(); if (!model->add(Session(date, start, stop, task, billed))) { xml.raiseError(tr("Session conflicts with other sessions.")); } // Start adding project } else if (xml.name() == QLatin1String("project")) { m_projects->blockSignals(true); projects.push(new Project(item, attributes.value(QLatin1String("name")).toString())); item = projects.top(); item->setExpanded(attributes.value(QLatin1String("expanded")) == QLatin1String("1")); current = (attributes.value(QLatin1String("current")) == QLatin1String("1")) ? projects.top() : current; filter = attributes.value(QLatin1String("filter")).toString().toInt(); model = projects.top()->model(); model->setDecimalTotals(m_decimals); model->beginLoad(); m_projects->blockSignals(false); // Read contact information } else if (xml.name() == QLatin1String("contact")) { m_contact.fromXml(xml); // Read rates } else if (xml.name() == QLatin1String("rates")) { m_rates.fromXml(xml); // Add autosaved time as new session to current project } else if ((xml.name() == QLatin1String("autosave")) && model) { QDateTime start = QDateTime::fromString(attributes.value(QLatin1String("start")).toString(), Qt::ISODate); QDateTime stop = QDateTime::fromString(attributes.value(QLatin1String("stop")).toString(), Qt::ISODate); QString task = attributes.value(QLatin1String("note")).toString(); if (!model->add(start, stop, task)) { xml.raiseError(tr("Session conflicts with other sessions.")); } } // Finish adding project } else if (xml.isEndElement() && xml.name() == QLatin1String("project")) { model->endLoad(); projects.top()->filterModel()->setType(filter); projects.pop(); if (!projects.isEmpty()) { model = projects.top()->model(); item = projects.top(); } else { model = nullptr; item = m_projects->invisibleRootItem(); } } } // Abort if data is corrupt if (xml.hasError()) { m_valid = false; // Move aside invalid data QString path = QFileInfo(file).canonicalFilePath(); QFile::rename(filename, filename + ".invalid-" + QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz")); // Clear invalid data m_contact = Contact(); m_rates = Rates(); m_projects->clear(); // Warn user that data is invalid QMessageBox message(QMessageBox::Critical, tr("Error"), tr("Unable to read time data."), QMessageBox::Ok, this); message.setInformativeText(QString("%1:%2:%3: %4") .arg(path) .arg(xml.lineNumber()) .arg(xml.columnNumber()) .arg(xml.errorString().toHtmlEscaped()) ); message.exec(); return; } file.close(); // Create default project if data file has none if (m_projects->topLevelItemCount() == 0) { addProject(tr("Untitled")); current = nullptr; } // Select last used project if (!current) { current = m_projects->topLevelItem(0); } m_projects->setCurrentItem(current); } //----------------------------------------------------------------------------- void Window::createDataBackup() { // Create daily backup QDate date = QDate::currentDate(); QString path = m_filename + ".bak-" + date.toString("yyyyMMdd"); if (QFile::exists(path)) { return; } QFile::copy(m_filename, path); // Create list of daily and weekly backups QStringList days; for (int i = 0; i < 7; ++i) { QDate d = date.addDays(-i); days.append(m_filename + ".bak-" + d.toString("yyyyMMdd")); } QStringList weeks; for (int i = 1; i < 5; ++i) { QDate d = date.addDays(-i * 7); int year; int week = d.weekNumber(&year); weeks.prepend(QString("%1-%2").arg(year).arg(week)); } // Reduce previous backups QString current_month = date.addMonths(-1).addYears(-1).toString("yyyyMM"); int current_year = 0; QDir dir = QFileInfo(m_filename).dir(); const QStringList backups = dir.entryList(QStringList(m_filename + ".bak-"), QDir::Files, QDir::Name | QDir::IgnoreCase); for (const QString& backup : backups) { // Keep one backup a day for the last 7 days if (days.contains(backup)) { continue; } QDate d = QDate::fromString(backup.right(8), "yyyyMMdd"); if (!d.isValid()) { continue; } // Keep one backup a week for the last 4 weeks int year; int week = d.weekNumber(&year); QString week_string = QString("%1-%2").arg(year).arg(week); if (weeks.first() == week_string) { weeks.removeFirst(); continue; } // Keep one backup a month for the the last 12 months QString month = d.toString("yyyyMM"); if (month > current_month) { current_month = month; if (d.year() > current_year) { current_year = d.year(); } continue; } // Keep one backup a year from the beginning if (d.year() > current_year) { current_year = d.year(); continue; } // Remove extra backup dir.remove(backup); } } //----------------------------------------------------------------------------- void Window::addProject(const QString& name) { Project* project = new Project(m_projects, name); project->model()->setDecimalTotals(m_decimals); m_projects->setCurrentItem(project); } //----------------------------------------------------------------------------- void Window::removeProject(QTreeWidgetItem* item) { if (!item) { return; } // Recursively remove subprojects for (int i = item->childCount() - 1; i >= 0; i--) { removeProject(item->child(i)); } // Unset active model before removing project Project* project = dynamic_cast(item); if (project && project->model() == m_active_model) { m_active_model = nullptr; } delete item; item = nullptr; } //----------------------------------------------------------------------------- void Window::minimizeToTray() { m_toggle_visibility->setText(tr("&Restore")); hide(); } //----------------------------------------------------------------------------- void Window::restoreFromTray() { m_toggle_visibility->setText(tr("&Minimize")); show(); raise(); activateWindow(); } //----------------------------------------------------------------------------- bool Window::showRunningProject() { if (m_active_timers.size() != 1) { return false; } m_projects->setCurrentItem(m_active_timers.first()); return true; } //----------------------------------------------------------------------------- void Window::updateDetails() { Q_ASSERT(m_active_project); updateDisplay(); updateSessionButtons(); updateTrayIcon(); m_projects->resizeColumnToContents(1); } //----------------------------------------------------------------------------- void Window::updateDisplay() { QString time = m_active_project->time(); m_display->setText(!time.isEmpty() ? time : "00:00:00"); } //----------------------------------------------------------------------------- void Window::updateReportActions() { m_create_report->setEnabled(m_active_model->canBill()); m_remove_report->setEnabled(!m_active_model->billedRows().isEmpty()); } //----------------------------------------------------------------------------- void Window::updateSessionButtons() { updateReportActions(); if (!m_active_project->time().isEmpty()) { m_start->hide(); m_stop->show(); m_cancel->setEnabled(true); m_create_report->setEnabled(false); } else { m_stop->hide(); m_start->show(); m_cancel->setEnabled(false); } } //----------------------------------------------------------------------------- void Window::updateTrayActions() { // Disable actions m_tray_start_session->setEnabled(false); m_tray_stop_session->setEnabled(false); m_tray_stop_all_session->setEnabled(false); m_tray_cancel_session->setEnabled(false); m_toggle_visibility->setEnabled(false); // Don't allow interaction if dialog is open if (m_blocked) { return; } // Hide disabled actions m_tray_start_session->setVisible(false); m_tray_stop_session->setVisible(false); m_tray_stop_all_session->setVisible(false); m_tray_cancel_session->setVisible(false); // Enable and show actions based on timers if (m_active_timers.isEmpty()) { m_tray_start_session->setEnabled(true); m_tray_start_session->setVisible(true); } else if (m_active_timers.size() == 1) { m_tray_stop_session->setEnabled(true); m_tray_stop_session->setVisible(true); m_tray_cancel_session->setEnabled(true); m_tray_cancel_session->setVisible(true); } else { m_tray_stop_all_session->setEnabled(true); m_tray_stop_all_session->setVisible(true); } m_toggle_visibility->setEnabled(true); } //----------------------------------------------------------------------------- void Window::updateTrayIcon() { int count = m_active_timers.count(); if (count == 1) { m_tray_icon->setIcon(m_active_icon); m_tray_icon->setToolTip(m_active_timers.first()->time()); } else if (count == 0) { m_tray_icon->setIcon(m_inactive_icon); m_tray_icon->setToolTip(tr("Kapow Punch Clock")); } else { m_tray_icon->setIcon(m_active_icon); m_tray_icon->setToolTip(tr("%n timer(s) running", "", count)); } } //----------------------------------------------------------------------------- void Window::updateWindowTitle(const QString& project) { setWindowFilePath(project); } //----------------------------------------------------------------------------- gottcode-kapow-350ecea/src/window.h000066400000000000000000000070761514263554100174170ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2008 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_WINDOW_H #define KAPOW_WINDOW_H #include "contact.h" #include "rates.h" class Project; class SessionModel; #include #include #include class QComboBox; class QLabel; class QLineEdit; class QModelIndex; class QPushButton; class QSplitter; class QTimer; class QTreeView; class QTreeWidget; class QTreeWidgetItem; class Window : public QMainWindow { Q_OBJECT public: Window(const QString& filename, bool backups_enabled, bool start_in_tray = false, QWidget* parent = nullptr); bool isValid() const; public Q_SLOTS: void raiseWindow(); protected: bool event(QEvent* event) override; void closeEvent(QCloseEvent* event) override; void showEvent(QShowEvent* event) override; private Q_SLOTS: void about(); void quit(); void setDecimalTotals(bool decimals); void setInlineEditing(bool edit); void setCloseToTray(bool closetotray); void setStartMinimized(bool minimized); void setLocaleClicked(); void start(); void stop(); void stopRunningProject(); void stopAll(); void cancel(); void cancelRunningProject(); void taskChanged(const QString& task); void taskStart(); void updateTime(); void addProject(); void editProject(); void removeProject(); void createReport(); void removeReport(); void viewReports(); void projectActivated(QTreeWidgetItem* item); void projectChanged(QTreeWidgetItem* item, int column); void filterChanged(int index); void modelBilledStatusChanged(); void sessionPressed(const QModelIndex& index); void sessionsInserted(const QModelIndex& parent, int start, int end); void sessionsScrolled(int value); void addSession(); void editSession(); void removeSessions(); void moveSessions(); void toggleColumnHidden(int column); void save(); void trayIconActivated(QSystemTrayIcon::ActivationReason reason); void toggleVisible(); private: int currentRow(); QList selectedUnbilledRows() const; void loadData(); void loadData(const QString& filename); void createDataBackup(); void addProject(const QString& name); void removeProject(QTreeWidgetItem* item); void minimizeToTray(); void restoreFromTray(); bool showRunningProject(); void updateDetails(); void updateDisplay(); void updateReportActions(); void updateSessionButtons(); void updateTrayActions(); void updateTrayIcon(); void updateWindowTitle(const QString& project); private: QString m_filename; bool m_valid; bool m_blocked; bool m_backups_enabled; bool m_decimals; bool m_inline; bool m_closetotray; bool m_start_minimized; QSplitter* m_contents; QTreeWidget* m_projects; QLabel* m_display; QLineEdit* m_task; QPushButton* m_start; QPushButton* m_stop; QPushButton* m_cancel; QComboBox* m_filter; QTreeView* m_details; Contact m_contact; Rates m_rates; QTimer* m_timer; QTimer* m_save_timer; QDateTime m_current_time; Project* m_active_project; SessionModel* m_active_model; QList m_active_timers; QAction* m_add_project; QAction* m_remove_project; QAction* m_create_report; QAction* m_remove_report; QAction* m_view_reports; QAction* m_add_session; QAction* m_edit_session; QAction* m_remove_session; QAction* m_move_session; QAction* m_start_session; QAction* m_stop_session; QAction* m_cancel_session; QAction* m_tray_start_session; QAction* m_tray_stop_session; QAction* m_tray_stop_all_session; QAction* m_tray_cancel_session; QAction* m_toggle_visibility; QSystemTrayIcon* m_tray_icon; QIcon m_active_icon; QIcon m_inactive_icon; }; #endif // KAPOW_WINDOW_H gottcode-kapow-350ecea/tests/000077500000000000000000000000001514263554100163005ustar00rootroot00000000000000gottcode-kapow-350ecea/tests/CMakeLists.txt000066400000000000000000000010341514263554100210360ustar00rootroot00000000000000include_directories(../src) # Test filters qt6_add_executable(test_filters test_filters/test_filters.cpp ../src/filter_model.cpp ../src/session.cpp ../src/session_model.cpp ) target_link_libraries(test_filters PRIVATE Qt6::Core Qt6::Test) add_test(NAME test_filters COMMAND test_filters) # Test sessions qt6_add_executable(test_sessions test_sessions/test_sessions.cpp ../src/session.cpp ../src/session_model.cpp ) target_link_libraries(test_sessions PRIVATE Qt6::Core Qt6::Test) add_test(NAME test_sessions COMMAND test_sessions) gottcode-kapow-350ecea/tests/test_filters/000077500000000000000000000000001514263554100210075ustar00rootroot00000000000000gottcode-kapow-350ecea/tests/test_filters/test_filters.cpp000066400000000000000000000606701514263554100242330ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2013 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "test_filters.h" #include "filter_model.h" #include "session.h" #include "session_model.h" Q_DECLARE_METATYPE(Session) #include //----------------------------------------------------------------------------- void TestFilters::checkFilters_data() { QTest::addColumn>("sessions"); QTest::addColumn("type"); QTest::addColumn>("result"); QDate today = QDate::currentDate(); QTest::newRow("Filter for billed") << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::Unbilled) << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QDate before = today.addYears(-1); QTest::newRow("Filter for this year") << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisYear) << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; before = today.addMonths(-1); QTest::newRow("Filter for this month") << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisMonth) << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; before = today.addDays(-8); QTest::newRow("Filter for this week") << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisWeek) << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; } void TestFilters::checkFilters() { SessionModel session_model; QFETCH(QList, sessions); for (const Session& session : sessions) { session_model.add(session); } FilterModel model(&session_model); QFETCH(int, type); model.setType(type); QFETCH(QList, result); QCOMPARE(model.rowCount() - 1, result.count()); for (int i = 0; i < result.count(); ++i) { int row = model.mapToSource(model.index(i, 0)).row(); QCOMPARE(session_model.session(row), result.at(i)); } } //----------------------------------------------------------------------------- void TestFilters::addSessions_data() { QTest::addColumn>("start_sessions"); QTest::addColumn("type"); QTest::addColumn>("add_sessions"); QTest::addColumn>("result"); QDate today = QDate::currentDate(); QTest::newRow("Filtered by billed") << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::Unbilled) << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true) } << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QTest::newRow("Unfiltered by billed") << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true) } << int(FilterModel::Unbilled) << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QDate before = today.addYears(-1); QTest::newRow("Filtered by this year") << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisYear) << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false) } << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QTest::newRow("Unfiltered by this year") << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisYear) << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false) } << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; before = today.addMonths(-1); QTest::newRow("Filtered by this month") << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisMonth) << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false) } << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QTest::newRow("Unfiltered by this month") << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisMonth) << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false) } << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; before = today.addDays(-8); QTest::newRow("Filtered by this week") << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisWeek) << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false) } << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QTest::newRow("Unfiltered by this week") << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisWeek) << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false) } << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; } void TestFilters::addSessions() { SessionModel session_model; QFETCH(QList, start_sessions); for (const Session& session : start_sessions) { session_model.add(session); } FilterModel model(&session_model); QFETCH(int, type); model.setType(type); QFETCH(QList, add_sessions); for (const Session& session : add_sessions) { session_model.add(session); } QFETCH(QList, result); QCOMPARE(model.rowCount() - 1, result.count()); for (int i = 0; i < result.count(); ++i) { int row = model.mapToSource(model.index(i, 0)).row(); QCOMPARE(session_model.session(row), result.at(i)); } } //----------------------------------------------------------------------------- void TestFilters::editSessions_data() { QTest::addColumn>("sessions"); QTest::addColumn("type"); QTest::addColumn("position"); QTest::addColumn("replacement"); QTest::addColumn>("result"); QDate today = QDate::currentDate(); QTest::newRow("Unfiltered by billed") << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << int(FilterModel::Unbilled) << 2 << Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) << QList{ Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QDate before = today.addYears(-1); QTest::newRow("Filtered by this year") << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisYear) << 1 << Session(before, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Unfiltered by this year") << QList{ Session(before, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << int(FilterModel::ThisYear) << 0 << Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; before = today.addMonths(-1); QTest::newRow("Filtered by this month") << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisMonth) << 1 << Session(before, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Unfiltered by this month") << QList{ Session(before, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << int(FilterModel::ThisMonth) << 0 << Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; before = today.addDays(-8); QTest::newRow("Filtered by this week") << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisWeek) << 1 << Session(before, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Unfiltered by this week") << QList{ Session(before, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << int(FilterModel::ThisWeek) << 0 << Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; } void TestFilters::editSessions() { SessionModel session_model; QFETCH(QList, sessions); for (const Session& session : sessions) { session_model.add(session); } FilterModel model(&session_model); QFETCH(int, type); model.setType(type); QFETCH(int, position); QFETCH(Session, replacement); session_model.edit(position, replacement); QFETCH(QList, result); QCOMPARE(model.rowCount() - 1, result.count()); for (int i = 0; i < result.count(); ++i) { int row = model.mapToSource(model.index(i, 0)).row(); QCOMPARE(session_model.session(row), result.at(i)); } } //----------------------------------------------------------------------------- void TestFilters::removeSessions_data() { QTest::addColumn>("sessions"); QTest::addColumn("type"); QTest::addColumn("position"); QTest::addColumn>("result"); QDate today = QDate::currentDate(); QTest::newRow("Unfiltered by billed") << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::Unbilled) << 2 << QList{ Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QDate before = today.addYears(-1); QTest::newRow("Filtered by this year") << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisYear) << 1 << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QTest::newRow("Unfiltered by this year") << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisYear) << 2 << QList{ Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; before = today.addMonths(-1); QTest::newRow("Filtered by this month") << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisMonth) << 1 << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QTest::newRow("Unfiltered by this month") << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisMonth) << 2 << QList{ Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; before = today.addDays(-8); QTest::newRow("Filtered by this week") << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisWeek) << 1 << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QTest::newRow("Unfiltered by this week") << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisWeek) << 2 << QList{ Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; } void TestFilters::removeSessions() { SessionModel session_model; QFETCH(QList, sessions); for (const Session& session : sessions) { session_model.add(session); } FilterModel model(&session_model); QFETCH(int, type); model.setType(type); QFETCH(int, position); session_model.remove(position); QFETCH(QList, result); QCOMPARE(model.rowCount() - 1, result.count()); for (int i = 0; i < result.count(); ++i) { int row = model.mapToSource(model.index(i, 0)).row(); QCOMPARE(session_model.session(row), result.at(i)); } } //----------------------------------------------------------------------------- void TestFilters::unbilledFilter_data() { QTest::addColumn>("sessions"); QTest::addColumn("position"); QTest::addColumn("billed"); QTest::addColumn>("result"); QDate today = QDate::currentDate(); QTest::newRow("Bill sessions") << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << 1 << true << QList{ Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QTest::newRow("Unbill sessions") << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << 1 << false << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; } void TestFilters::unbilledFilter() { SessionModel session_model; QFETCH(QList, sessions); for (const Session& session : sessions) { session_model.add(session); } FilterModel model(&session_model); model.setType(FilterModel::Unbilled); QFETCH(int, position); QFETCH(bool, billed); session_model.setBilled(position, billed); QFETCH(QList, result); QCOMPARE(model.rowCount() - 1, result.count()); for (int i = 0; i < result.count(); ++i) { int row = model.mapToSource(model.index(i, 0)).row(); QCOMPARE(session_model.session(row), result.at(i)); } } //----------------------------------------------------------------------------- void TestFilters::mapUnbilled_data() { QTest::addColumn>("sessions"); QTest::addColumn("type"); QTest::addColumn("first_unbilled_row"); QTest::addColumn>("mapped_rows"); QDate today = QDate::currentDate(); QTest::newRow("Filter for billed") << QList{ Session(today, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(today, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::Unbilled) << 0 << QList{ 2, 3 }; QDate before = today.addYears(-1); QTest::newRow("Filter for this year") << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(15, 0, 0), QTime(16, 0, 0), "Test session.", true), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisYear) << 1 << QList{ 3, 4 }; before = today.addMonths(-1); QTest::newRow("Filter for this month") << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(15, 0, 0), QTime(16, 0, 0), "Test session.", true), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisMonth) << 1 << QList{ 3, 4 }; before = today.addDays(-8); QTest::newRow("Filter for this week") << QList{ Session(before, QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(before, QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(today, QTime(15, 0, 0), QTime(16, 0, 0), "Test session.", true), Session(today, QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(today, QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << int(FilterModel::ThisWeek) << 1 << QList{ 3, 4 }; } void TestFilters::mapUnbilled() { SessionModel session_model; QFETCH(QList, sessions); for (const Session& session : sessions) { session_model.add(session); } FilterModel model(&session_model); QFETCH(int, type); model.setType(type); int unbilled_row = -1; QList unbilled; for (int i = 0; i < model.rowCount() - 1; ++i) { int row = model.mapToSource(model.index(i, 0)).row(); if (!session_model.isBilled(row)) { unbilled_row = i; break; } } QFETCH(int, first_unbilled_row); QCOMPARE(unbilled_row, first_unbilled_row); QFETCH(QList, mapped_rows); QCOMPARE(model.rowCount() - 1, first_unbilled_row + mapped_rows.count()); for (int i = 0; i < mapped_rows.count(); ++i) { int proxy_row = i + first_unbilled_row; int row = model.mapUnbilledToSource(model.index(proxy_row, 0)).row(); QCOMPARE(row, mapped_rows.at(i)); } } //----------------------------------------------------------------------------- QTEST_MAIN(TestFilters) gottcode-kapow-350ecea/tests/test_filters/test_filters.h000066400000000000000000000011451514263554100236700ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2013 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_TEST_FILTERS_H #define KAPOW_TEST_FILTERS_H class SessionModel; #include class TestFilters : public QObject { Q_OBJECT private Q_SLOTS: void checkFilters_data(); void checkFilters(); void addSessions_data(); void addSessions(); void editSessions_data(); void editSessions(); void removeSessions_data(); void removeSessions(); void unbilledFilter_data(); void unbilledFilter(); void mapUnbilled_data(); void mapUnbilled(); }; #endif // KAPOW_TEST_FILTERS_H gottcode-kapow-350ecea/tests/test_sessions/000077500000000000000000000000001514263554100212055ustar00rootroot00000000000000gottcode-kapow-350ecea/tests/test_sessions/test_sessions.cpp000066400000000000000000001566621514263554100246360ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2013 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #include "test_sessions.h" #include "session.h" #include "session_model.h" Q_DECLARE_METATYPE(Session) #include //----------------------------------------------------------------------------- void TestSessions::addSessions_data() { QTest::addColumn("start"); QTest::addColumn("stop"); QTest::addColumn("task"); QTest::addColumn("row_count"); QTest::newRow("Simple session") << QDateTime(QDate(2013, 2, 18), QTime(12, 30, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 45, 0)) << QString("Test session.") << 1; QTest::newRow("Session across midnight") << QDateTime(QDate(2013, 2, 18), QTime(22, 30, 0)) << QDateTime(QDate(2013, 2, 19), QTime(2, 45, 0)) << QString("Test session.") << 2; QTest::newRow("Two day session") << QDateTime(QDate(2013, 2, 18), QTime(22, 30, 0)) << QDateTime(QDate(2013, 2, 20), QTime(2, 45, 0)) << QString("Test session.") << 3; } void TestSessions::addSessions() { SessionModel model; QFETCH(QDateTime, start); QFETCH(QDateTime, stop); QFETCH(QString, task); model.add(start, stop, task); QFETCH(int, row_count); QCOMPARE(model.rowCount() - 1, row_count); Session session = model.session(0); QCOMPARE(session.date(), start.date()); QCOMPARE(session.start(), start.time()); if (row_count > 1) { QCOMPARE(session.stop(), QTime(23, 59, 59)); session = model.session(row_count - 1); QCOMPARE(session.date(), stop.date()); QCOMPARE(session.start(), QTime(0, 0, 0)); } QCOMPARE(session.stop(), stop.time()); QCOMPARE(session.task(), task); QCOMPARE(session.isBilled(), false); } //----------------------------------------------------------------------------- void TestSessions::addConflictingSessions_data() { QTest::addColumn("start"); QTest::addColumn("stop"); QTest::addColumn("task"); QTest::addColumn("conflict_start"); QTest::addColumn("conflict_stop"); QTest::addColumn("conflict_task"); QTest::newRow("Prevent duplicate sessions") << QDateTime(QDate(2013, 2, 18), QTime(12, 30, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 45, 0)) << QString("Test session.") << QDateTime(QDate(2013, 2, 18), QTime(12, 30, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 45, 0)) << QString("Conflict session."); QTest::newRow("Prevent overlap session start") << QDateTime(QDate(2013, 2, 18), QTime(12, 30, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 45, 0)) << QString("Test session.") << QDateTime(QDate(2013, 2, 18), QTime(11, 0, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 0, 0)) << QString("Conflict session."); QTest::newRow("Prevent overlap session end") << QDateTime(QDate(2013, 2, 18), QTime(12, 30, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 45, 0)) << QString("Test session.") << QDateTime(QDate(2013, 2, 18), QTime(13, 0, 0)) << QDateTime(QDate(2013, 2, 18), QTime(14, 0, 0)) << QString("Conflict session."); QTest::newRow("Prevent overlap entire session") << QDateTime(QDate(2013, 2, 18), QTime(12, 30, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 45, 0)) << QString("Test session.") << QDateTime(QDate(2013, 2, 18), QTime(11, 0, 0)) << QDateTime(QDate(2013, 2, 18), QTime(14, 0, 0)) << QString("Conflict session."); QTest::newRow("Prevent overlap inside session") << QDateTime(QDate(2013, 2, 18), QTime(12, 30, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 45, 0)) << QString("Test session.") << QDateTime(QDate(2013, 2, 18), QTime(13, 0, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 30, 0)) << QString("Conflict session."); QTest::newRow("Prevent overlap session start from previous day") << QDateTime(QDate(2013, 2, 18), QTime(12, 30, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 45, 0)) << QString("Test session.") << QDateTime(QDate(2013, 2, 17), QTime(11, 0, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 0, 0)) << QString("Conflict session."); QTest::newRow("Prevent overlap session end into next day") << QDateTime(QDate(2013, 2, 18), QTime(12, 30, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 45, 0)) << QString("Test session.") << QDateTime(QDate(2013, 2, 18), QTime(13, 0, 0)) << QDateTime(QDate(2013, 2, 19), QTime(14, 0, 0)) << QString("Conflict session."); QTest::newRow("Prevent overlap entire session from previous day") << QDateTime(QDate(2013, 2, 18), QTime(12, 30, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 45, 0)) << QString("Test session.") << QDateTime(QDate(2013, 2, 17), QTime(11, 0, 0)) << QDateTime(QDate(2013, 2, 18), QTime(14, 0, 0)) << QString("Conflict session."); QTest::newRow("Prevent overlap entire session into next day") << QDateTime(QDate(2013, 2, 18), QTime(12, 30, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 45, 0)) << QString("Test session.") << QDateTime(QDate(2013, 2, 18), QTime(11, 0, 0)) << QDateTime(QDate(2013, 2, 19), QTime(14, 0, 0)) << QString("Conflict session."); QTest::newRow("Prevent overlap entire session across multiple days") << QDateTime(QDate(2013, 2, 18), QTime(12, 30, 0)) << QDateTime(QDate(2013, 2, 18), QTime(13, 45, 0)) << QString("Test session.") << QDateTime(QDate(2013, 2, 17), QTime(11, 0, 0)) << QDateTime(QDate(2013, 2, 19), QTime(14, 0, 0)) << QString("Conflict session."); } void TestSessions::addConflictingSessions() { SessionModel model; QFETCH(QDateTime, start); QFETCH(QDateTime, stop); QFETCH(QString, task); model.add(start, stop, task); QFETCH(QDateTime, conflict_start); QFETCH(QDateTime, conflict_stop); QFETCH(QString, conflict_task); model.add(conflict_start, conflict_stop, conflict_task); QCOMPARE(model.rowCount() - 1, 1); } //----------------------------------------------------------------------------- void TestSessions::addMultipleSessions_data() { QTest::addColumn>("sessions"); QTest::addColumn>("result"); QTest::newRow("Sorted") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Sorted reverse") << QList{ Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false) } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Unsorted") << QList{ Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Sessions with some billed") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Prevent adding to billed") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(10, 0, 0), QTime(11, 0, 0), "Test session.", false) } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; } void TestSessions::addMultipleSessions() { SessionModel model; QFETCH(QList, sessions); for (const Session& session : sessions) { model.add(session); } QFETCH(QList, result); QCOMPARE(model.rowCount() - 1, result.count()); for (int i = 0; i < result.count(); ++i) { QCOMPARE(model.session(i), result.at(i)); } } //----------------------------------------------------------------------------- void TestSessions::addSessionsFixConflict_data() { QTest::addColumn>("sessions"); QTest::addColumn("start"); QTest::addColumn("stop"); QTest::addColumn("task"); QTest::addColumn>("result"); QTest::newRow("No sessions") << QList() << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 18), QTime(15, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 18), QTime(14, 30, 0), QTime(15, 45, 0), "New session.", false) }; QTest::newRow("Session before") << QList{ Session(QDate(2020, 12, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 18), QTime(15, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2020, 12, 18), QTime(14, 30, 0), QTime(15, 45, 0), "New session.", false) }; QTest::newRow("Session after") << QList{ Session(QDate(2020, 12, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 18), QTime(15, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 18), QTime(14, 30, 0), QTime(15, 45, 0), "New session.", false), Session(QDate(2020, 12, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Intersect end") << QList{ Session(QDate(2020, 12, 18), QTime(15, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 18), QTime(15, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 18), QTime(14, 30, 0), QTime(15, 29, 59), "New session.", false), Session(QDate(2020, 12, 18), QTime(15, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Intersect end next day") << QList{ Session(QDate(2020, 12, 19), QTime(15, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 19), QTime(15, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 18), QTime(14, 30, 0), QTime(23, 59, 59), "New session.", false), Session(QDate(2020, 12, 19), QTime(0, 0, 0), QTime(15, 29, 59), "New session.", false), Session(QDate(2020, 12, 19), QTime(15, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Intersect start") << QList{ Session(QDate(2020, 12, 18), QTime(12, 30, 0), QTime(15, 45, 0), "Test session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 18), QTime(15, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 18), QTime(12, 30, 0), QTime(15, 45, 0), "Test session.", false) }; QTest::newRow("Intersect start previous day") << QList{ Session(QDate(2020, 12, 17), QTime(12, 30, 0), QTime(15, 45, 0), "Test session.", false) } << QDateTime(QDate(2020, 12, 17), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 18), QTime(15, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 17), QTime(12, 30, 0), QTime(15, 45, 0), "Test session.", false) }; QTest::newRow("Overlap single") << QList{ Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(15, 15, 0), "Test session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 18), QTime(17, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 18), QTime(14, 30, 0), QTime(14, 59, 59), "New session.", false), Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(15, 15, 0), "Test session.", false) }; QTest::newRow("Overlap single next day") << QList{ Session(QDate(2020, 12, 19), QTime(15, 0, 0), QTime(15, 15, 0), "Test session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 19), QTime(17, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 18), QTime(14, 30, 0), QTime(23, 59, 59), "New session.", false), Session(QDate(2020, 12, 19), QTime(0, 0, 0), QTime(14, 59, 59), "New session.", false), Session(QDate(2020, 12, 19), QTime(15, 0, 0), QTime(15, 15, 0), "Test session.", false) }; QTest::newRow("Overlap single previous day") << QList{ Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(15, 15, 0), "Test session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 19), QTime(17, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 18), QTime(14, 30, 0), QTime(14, 59, 59), "New session.", false), Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(15, 15, 0), "Test session.", false) }; QTest::newRow("Overlap multiple") << QList{ Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(15, 15, 0), "First session.", false), Session(QDate(2020, 12, 18), QTime(16, 0, 0), QTime(16, 15, 0), "Second session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 18), QTime(17, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 18), QTime(14, 30, 0), QTime(14, 59, 59), "New session.", false), Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(15, 15, 0), "First session.", false), Session(QDate(2020, 12, 18), QTime(16, 0, 0), QTime(16, 15, 0), "Second session.", false) }; QTest::newRow("Overlap multiple next day") << QList{ Session(QDate(2020, 12, 19), QTime(15, 0, 0), QTime(15, 15, 0), "First session.", false), Session(QDate(2020, 12, 19), QTime(16, 0, 0), QTime(16, 15, 0), "Second session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 19), QTime(17, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 18), QTime(14, 30, 0), QTime(23, 59, 59), "New session.", false), Session(QDate(2020, 12, 19), QTime(0, 0, 0), QTime(14, 59, 59), "New session.", false), Session(QDate(2020, 12, 19), QTime(15, 0, 0), QTime(15, 15, 0), "First session.", false), Session(QDate(2020, 12, 19), QTime(16, 0, 0), QTime(16, 15, 0), "Second session.", false) }; QTest::newRow("Overlap multiple previous day") << QList{ Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(15, 15, 0), "First session.", false), Session(QDate(2020, 12, 18), QTime(16, 0, 0), QTime(16, 15, 0), "Second session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 19), QTime(17, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 18), QTime(14, 30, 0), QTime(14, 59, 59), "New session.", false), Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(15, 15, 0), "First session.", false), Session(QDate(2020, 12, 18), QTime(16, 0, 0), QTime(16, 15, 0), "Second session.", false) }; } void TestSessions::addSessionsFixConflict() { SessionModel model; QFETCH(QList, sessions); for (const Session& session : sessions) { model.add(session); } QFETCH(QDateTime, start); QFETCH(QDateTime, stop); QFETCH(QString, task); model.fixConflict(start, stop); model.add(start, stop, task); QFETCH(QList, result); QCOMPARE(model.rowCount() - 1, result.count()); for (int i = 0; i < result.count(); ++i) { QCOMPARE(model.session(i), result.at(i)); } } //----------------------------------------------------------------------------- void TestSessions::addSessionsHasConflict_data() { QTest::addColumn>("sessions"); QTest::addColumn("test"); QTest::addColumn("result"); QTest::newRow("No sessions") << QList() << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << false; QTest::newRow("Session before") << QList{ Session(QDate(2020, 12, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << false; QTest::newRow("Session after") << QList{ Session(QDate(2020, 12, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << false; QTest::newRow("Between sessions") << QList{ Session(QDate(2020, 12, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2020, 12, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << false; QTest::newRow("Inside session") << QList{ Session(QDate(2020, 12, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false) } << QDateTime(QDate(2020, 12, 18), QTime(13, 0, 0)) << true; } void TestSessions::addSessionsHasConflict() { SessionModel model; QFETCH(QList, sessions); for (const Session& session : sessions) { model.add(session); } QFETCH(QDateTime, test); QFETCH(bool, result); QCOMPARE(model.hasConflict(test), result); } //----------------------------------------------------------------------------- void TestSessions::addSessionsMaximumDateTime_data() { QTest::addColumn("maximum"); QTest::addColumn("start"); QTest::addColumn("stop"); QTest::addColumn("task"); QTest::addColumn>("result"); QTest::newRow("Add before max") << QDateTime(QDate(2020, 12, 18), QTime(16, 0, 0)) << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 18), QTime(15, 45, 0)) << QString("New session.") << QList{ Session(QDate(2020, 12, 18), QTime(14, 30, 0), QTime(15, 45, 0), "New session.", false) }; QTest::newRow("Prevent add across max") << QDateTime(QDate(2020, 12, 18), QTime(15, 0, 0)) << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 18), QTime(15, 45, 0)) << QString("New session.") << QList(); QTest::newRow("Prevent add after max") << QDateTime(QDate(2020, 12, 18), QTime(14, 0, 0)) << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << QDateTime(QDate(2020, 12, 18), QTime(15, 45, 0)) << QString("New session.") << QList(); } void TestSessions::addSessionsMaximumDateTime() { SessionModel model; QFETCH(QDateTime, maximum); model.setMaximumDateTime(maximum); QFETCH(QDateTime, start); QFETCH(QDateTime, stop); QFETCH(QString, task); model.add(start, stop, task); QFETCH(QList, result); QCOMPARE(model.rowCount() - 1, result.count()); for (int i = 0; i < result.count(); ++i) { QCOMPARE(model.session(i), result.at(i)); } } //----------------------------------------------------------------------------- void TestSessions::billSessions_data() { QTest::addColumn>("sessions"); QTest::addColumn>("toggle"); QTest::addColumn>("result"); QTest::newRow("Check unbilled status") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << QList() << QList{ false, false, false, false }; QTest::newRow("Check billed status") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << QList() << QList{ true, true, true, false }; QTest::newRow("Bill session") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << QList{ 1 } << QList{ true, true, false, false }; QTest::newRow("Bill second session") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << QList{ 2 } << QList{ true, true, true, false }; QTest::newRow("Unbill session") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << QList{ 2 } << QList{ true, false, false, false }; QTest::newRow("Unbill all sessions") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << QList{ 0, 2 } << QList{ false, false, false, false, }; QTest::newRow("Toggle billed session") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << QList{ 2, 2 } << QList{ true, true, true, false }; QTest::newRow("Toggle unbilled session") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << QList{ 2, 2 } << QList{ false, false, false, false }; } void TestSessions::billSessions() { SessionModel model; QFETCH(QList, sessions); for (const Session& session : sessions) { model.add(session); } QFETCH(QList, toggle); for (int pos : toggle) { model.setBilled(pos, !model.session(pos).isBilled()); } QFETCH(QList, result); QCOMPARE(model.rowCount() - 1, result.count()); for (int i = 0; i < result.count(); ++i) { QCOMPARE(model.isBilled(i), result.at(i)); } } //----------------------------------------------------------------------------- void TestSessions::editSessions_data() { QTest::addColumn>("sessions"); QTest::addColumn("position"); QTest::addColumn("replacement"); QTest::addColumn>("result"); QTest::newRow("Simple edit") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << 1 << Session(QDate(2013, 2, 18), QTime(15, 0, 0), QTime(15, 45, 0), "New session.", false) << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(15, 0, 0), QTime(15, 45, 0), "New session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Prevent editing into conflict") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << 1 << Session(QDate(2013, 2, 18), QTime(13, 0, 0), QTime(14, 45, 0), "New session.", false) << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Prevent editing into overlap") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << 1 << Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "New session.", false) << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Prevent editing in billed") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << 0 << Session(QDate(2013, 2, 18), QTime(15, 0, 0), QTime(15, 45, 0), "New session.", false) << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Prevent editing into billed") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << 2 << Session(QDate(2013, 2, 18), QTime(10, 0, 0), QTime(11, 0, 0), "New session.", false) << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Prevent editing billed session") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << 1 << Session(QDate(2013, 2, 18), QTime(15, 0, 0), QTime(15, 45, 0), "New session.", false) << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; } void TestSessions::editSessions() { SessionModel model; QFETCH(QList, sessions); for (const Session& session : sessions) { model.add(session); } QFETCH(int, position); QFETCH(Session, replacement); model.edit(position, replacement); QFETCH(QList, result); QCOMPARE(model.rowCount() - 1, result.count()); for (int i = 0; i < result.count(); ++i) { QCOMPARE(model.session(i), result.at(i)); } } //----------------------------------------------------------------------------- void TestSessions::editSessionsMaximumDateTime_data() { QTest::addColumn("session"); QTest::addColumn("maximum"); QTest::addColumn("replacement"); QTest::addColumn("result"); QTest::newRow("Before to before max") << Session(QDate(2020, 12, 18), QTime(12, 0, 0), QTime(13, 45, 0), "Test session.", false) << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << Session(QDate(2020, 12, 18), QTime(11, 0, 0), QTime(12, 45, 0), "New session.", false) << Session(QDate(2020, 12, 18), QTime(11, 0, 0), QTime(12, 45, 0), "New session.", false); QTest::newRow("After to before max") << Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(16, 45, 0), "Test session.", false) << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << Session(QDate(2020, 12, 18), QTime(11, 0, 0), QTime(12, 45, 0), "New session.", false) << Session(QDate(2020, 12, 18), QTime(11, 0, 0), QTime(12, 45, 0), "New session.", false); QTest::newRow("Across to before max") << Session(QDate(2020, 12, 18), QTime(12, 0, 0), QTime(17, 45, 0), "Test session.", false) << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << Session(QDate(2020, 12, 18), QTime(11, 0, 0), QTime(12, 45, 0), "New session.", false) << Session(QDate(2020, 12, 18), QTime(11, 0, 0), QTime(12, 45, 0), "New session.", false); QTest::newRow("Prevent before to after max") << Session(QDate(2020, 12, 18), QTime(12, 0, 0), QTime(13, 45, 0), "Test session.", false) << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(16, 45, 0), "New session.", false) << Session(QDate(2020, 12, 18), QTime(12, 0, 0), QTime(13, 45, 0), "Test session.", false); QTest::newRow("Prevent before to across max") << Session(QDate(2020, 12, 18), QTime(12, 0, 0), QTime(13, 45, 0), "Test session.", false) << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << Session(QDate(2020, 12, 18), QTime(12, 0, 0), QTime(16, 45, 0), "New session.", false) << Session(QDate(2020, 12, 18), QTime(12, 0, 0), QTime(13, 45, 0), "Test session.", false); QTest::newRow("Prevent after to after max") << Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(16, 45, 0), "Test session.", false) << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << Session(QDate(2020, 12, 18), QTime(17, 0, 0), QTime(18, 45, 0), "New session.", false) << Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(16, 45, 0), "Test session.", false); QTest::newRow("Prevent after to across max") << Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(16, 45, 0), "Test session.", false) << QDateTime(QDate(2020, 12, 18), QTime(14, 30, 0)) << Session(QDate(2020, 12, 18), QTime(12, 0, 0), QTime(16, 45, 0), "New session.", false) << Session(QDate(2020, 12, 18), QTime(15, 0, 0), QTime(16, 45, 0), "Test session.", false); } void TestSessions::editSessionsMaximumDateTime() { SessionModel model; QFETCH(Session, session); model.add(session); QFETCH(QDateTime, maximum); model.setMaximumDateTime(maximum); QFETCH(Session, replacement); model.edit(0, replacement); QFETCH(Session, result); QCOMPARE(model.session(0), result); } //----------------------------------------------------------------------------- void TestSessions::removeSessions_data() { QTest::addColumn>("sessions"); QTest::addColumn>("remove"); QTest::addColumn>("result"); QTest::newRow("Remove one session") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QList{ 1 } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Remove two sessions in a row") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << QList{ 1, 1 } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QTest::newRow("Prevent removing from billed") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QList{ 0 } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Prevent removing billed session") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QList{ 1 } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; } void TestSessions::removeSessions() { SessionModel model; QFETCH(QList, sessions); for (const Session& session : sessions) { model.add(session); } QFETCH(QList, remove); for (int row : remove) { model.remove(row); } QFETCH(QList, result); QCOMPARE(model.rowCount() - 1, result.count()); for (int i = 0; i < result.count(); ++i) { QCOMPARE(model.session(i), result.at(i)); } } //----------------------------------------------------------------------------- void TestSessions::removeMultipleSessions_data() { QTest::addColumn>("sessions"); QTest::addColumn>("rows"); QTest::addColumn>("result"); QTest::newRow("Remove one session") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QList{ 1 } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Remove two sessions in a row") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << QList{ 1, 2 } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) }; QTest::newRow("Remove two sessions") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false) } << QList{ 1, 3 } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Remove three sessions") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(18, 0, 0), QTime(20, 15, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(21, 0, 0), QTime(22, 15, 0), "Test session.", false) } << QList{ 3, 1, 4 } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Prevent removing from billed") << QList{ Session(QDate(2013, 2, 18), QTime(11, 30, 0), QTime(11, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QList{ 0, 1 } << QList{ Session(QDate(2013, 2, 18), QTime(11, 30, 0), QTime(11, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; QTest::newRow("Prevent removing billed session") << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) } << QList{ 0, 1 } << QList{ Session(QDate(2013, 2, 18), QTime(12, 30, 0), QTime(13, 45, 0), "Test session.", false), Session(QDate(2013, 2, 18), QTime(14, 0, 0), QTime(14, 45, 0), "Test session.", true), Session(QDate(2013, 2, 18), QTime(16, 30, 0), QTime(17, 45, 0), "Test session.", false) }; } void TestSessions::removeMultipleSessions() { SessionModel model; QFETCH(QList, sessions); for (const Session& session : sessions) { model.add(session); } QFETCH(QList, rows); model.remove(rows); QFETCH(QList, result); QCOMPARE(model.rowCount() - 1, result.count()); for (int i = 0; i < result.count(); ++i) { QCOMPARE(model.session(i), result.at(i)); } } //----------------------------------------------------------------------------- void TestSessions::takeSessions_data() { QTest::addColumn>("source"); QTest::addColumn>("dest"); QTest::addColumn>("take"); QTest::addColumn>("source_result"); QTest::addColumn>("dest_result"); QTest::newRow("Move to empty model") << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Source session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false) } << QList{} << QList{ 1 } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Source session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false) }; QTest::newRow("Move after") << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Source session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Taken session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Dest session.", false) } << QList{ 1 } << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Source session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Taken session.", false) }; QTest::newRow("Move before") << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Source session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false), } << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) } << QList{ 1 } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Source session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) }; QTest::newRow("Move between") << QList{ Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Source session.", false), Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Taken session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) } << QList{ 1 } << QList{ Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Source session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) }; QTest::newRow("Prevent moving into billed") << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Source session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Dest session.", true), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) } << QList{ 1 } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Source session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Dest session.", true), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) }; QTest::newRow("Prevent taking billed session") << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Source session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", true) } << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) } << QList{ 1 } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Source session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", true) } << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) }; } void TestSessions::takeSessions() { SessionModel source_model, dest_model; QFETCH(QList, source); for (const Session& session : source) { source_model.add(session); } QFETCH(QList, dest); for (const Session& session : dest) { dest_model.add(session); } QFETCH(QList, take); for (int row : take) { dest_model.take(&source_model, row); } QFETCH(QList, source_result); QCOMPARE(source_model.rowCount() - 1, source_result.count()); for (int i = 0; i < source_result.count(); ++i) { QCOMPARE(source_model.session(i), source_result.at(i)); } QFETCH(QList, dest_result); QCOMPARE(dest_model.rowCount() - 1, dest_result.count()); for (int i = 0; i < dest_result.count(); ++i) { QCOMPARE(dest_model.session(i), dest_result.at(i)); } } //----------------------------------------------------------------------------- void TestSessions::takeMultipleSessions_data() { QTest::addColumn>("source"); QTest::addColumn>("dest"); QTest::addColumn>("take"); QTest::addColumn>("source_result"); QTest::addColumn>("dest_result"); QTest::newRow("Move to empty model") << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Source session.", false) } << QList{} << QList{ 0, 1, 2 } << QList{ Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Source session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Taken session.", false) }; QTest::newRow("Move unsorted to empty model") << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Source session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Taken session.", false) } << QList{} << QList{ 3, 1, 2 } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Source session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Taken session.", false) }; QTest::newRow("Move after") << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Source session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(21, 0, 0), QTime(22, 15, 0), "Taken session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Dest session.", false) } << QList{ 1, 2 } << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Source session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(21, 0, 0), QTime(22, 15, 0), "Taken session.", false) }; QTest::newRow("Move before") << QList{ Session(QDate(2025, 4, 20), QTime(10, 30, 0), QTime(11, 45, 0), "Source session.", false), Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false), } << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) } << QList{ 1, 2 } << QList{ Session(QDate(2025, 4, 20), QTime(10, 30, 0), QTime(11, 45, 0), "Source session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) }; QTest::newRow("Move between") << QList{ Session(QDate(2025, 4, 20), QTime(10, 30, 0), QTime(11, 45, 0), "Source session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Taken session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) } << QList{ 1, 2 } << QList{ Session(QDate(2025, 4, 20), QTime(10, 30, 0), QTime(11, 45, 0), "Source session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) }; QTest::newRow("Prevent taking billed session") << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", true), Session(QDate(2025, 4, 20), QTime(21, 30, 0), QTime(21, 45, 0), "Taken session.", false), } << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) } << QList{ 0, 1, 2 } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", true), Session(QDate(2025, 4, 20), QTime(21, 30, 0), QTime(21, 45, 0), "Taken session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", false) }; QTest::newRow("Prevent moving into billed") << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(21, 30, 0), QTime(21, 45, 0), "Source session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", true) } << QList{ 0, 1 } << QList{ Session(QDate(2025, 4, 20), QTime(12, 30, 0), QTime(13, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(14, 0, 0), QTime(14, 45, 0), "Taken session.", false), Session(QDate(2025, 4, 20), QTime(21, 30, 0), QTime(21, 45, 0), "Source session.", false) } << QList{ Session(QDate(2025, 4, 20), QTime(16, 30, 0), QTime(17, 45, 0), "Dest session.", false), Session(QDate(2025, 4, 20), QTime(18, 0, 0), QTime(20, 15, 0), "Dest session.", true) }; } void TestSessions::takeMultipleSessions() { SessionModel source_model, dest_model; QFETCH(QList, source); for (const Session& session : source) { source_model.add(session); } QFETCH(QList, dest); for (const Session& session : dest) { dest_model.add(session); } QFETCH(QList, take); dest_model.take(&source_model, take); QFETCH(QList, source_result); QCOMPARE(source_model.rowCount() - 1, source_result.count()); for (int i = 0; i < source_result.count(); ++i) { QCOMPARE(source_model.session(i), source_result.at(i)); } QFETCH(QList, dest_result); QCOMPARE(dest_model.rowCount() - 1, dest_result.count()); for (int i = 0; i < dest_result.count(); ++i) { QCOMPARE(dest_model.session(i), dest_result.at(i)); } } //----------------------------------------------------------------------------- QTEST_MAIN(TestSessions) gottcode-kapow-350ecea/tests/test_sessions/test_sessions.h000066400000000000000000000021211514263554100242570ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2013 Graeme Gott SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef KAPOW_TEST_SESSIONS_H #define KAPOW_TEST_SESSIONS_H #include class TestSessions : public QObject { Q_OBJECT private Q_SLOTS: void addSessions_data(); void addSessions(); void addConflictingSessions_data(); void addConflictingSessions(); void addMultipleSessions_data(); void addMultipleSessions(); void addSessionsFixConflict_data(); void addSessionsFixConflict(); void addSessionsHasConflict_data(); void addSessionsHasConflict(); void addSessionsMaximumDateTime_data(); void addSessionsMaximumDateTime(); void billSessions_data(); void billSessions(); void editSessions_data(); void editSessions(); void editSessionsMaximumDateTime_data(); void editSessionsMaximumDateTime(); void removeSessions_data(); void removeSessions(); void removeMultipleSessions_data(); void removeMultipleSessions(); void takeSessions_data(); void takeSessions(); void takeMultipleSessions_data(); void takeMultipleSessions(); }; #endif // KAPOW_TEST_SESSIONS_H gottcode-kapow-350ecea/translations/000077500000000000000000000000001514263554100176575ustar00rootroot00000000000000gottcode-kapow-350ecea/translations/kapow_ar.ts000066400000000000000000000434061514263554100220410ustar00rootroot00000000000000 LocaleDialog Select application language: تحديد لغة التطبيق: <System Language> <لغة النظام> Note ملاحظة Please restart this application for the change in language to take effect. قم بإعادة تشغيل التطبيق من أجل تطبيق لغة الواجهة. Report Time Sheet Report التقرير الزمني Name: الاسم: Company: الشركة: Address: العنوان: Phone: الهاتف: Fax: الفاكس: Email: البريد الالكتروني: Website: موقع الانترنت: N/A غير متوفر Prepend currency symbol رمز العملة في أول السطر Hourly rate: معدل الساعات: Tax rate: معدل الضريبة: Currency symbol: رمز العملة: Contact Information معلومات الاتصال Data بيانات Preview معاينة Export تصدير Print طباعة Web Page (*.html *.htm) Web Page (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report تصدير تقرير View Reports عرض التقارير Create Report إنشاء تقرير Phone: %1 الهاتف:%1 Fax: %1 الفاكس%1 Hours ساعة Subtotal مجموع جزئي Taxes ضرائب Total المجموع Remove Question سؤال Remove newest report? Session %n hour(s) %n ساعة %n ساعة %L1 hours %L1 ساعة SessionDelegate Error خطأ Session conflicts with other sessions. SessionDialog Add Session اضافة جلسة Date: التاريخ: Start: بدء: Stop: توقف: Task: المهمة: Edit Session تحرير الجلسة SessionModel Total المجموع Date Start بدء Stop توقف Task Hours ساعة Daily Weekly Monthly Report Window 00:00:00 00:00:00 Start بدء Stop توقف Cancel إلغاء الأمر &Minimize &Project &مشروع &Add &اضافة Ctrl+Shift+N Ctrl+Shift+N &Remove &ازالة Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &خروج Ctrl+Q Ctrl+Q &Session &جلسة &Edit &تحرير Ctrl+Delete Ctrl+Delete S&ettings ا&عدادات Columns أعمدة &Decimal Totals &مجموع عشري &Inline Editing تحرير &ضمني Application &Language... &لغة التطبيق &Help &مساعدة &About &حول About &Qt حول &كيوت Project مشروع Timer مؤقت Show all عرض الكل Show only unbilled عرض غير المدفوع Show only this year عرض هذا العام فقط Show only this month عرض هذا الشهر فقط Show only this week عرض هذا الأسبوع فقط Copyright &copy; 2008-%1 Graeme Gott جميع الحقوق محقوظة &copy; Graeme Gott 2008-%1 <br/>تعريب:<br/>محمد بشير النعيمي: mbnoimi@gmail.com Released under the <a href=%1>GPL 3</a> license أُصدر برخصة <a href=%1>GPL 3</a> Session conflicts with other sessions. &Restore Unable to read time data. غير قادر على قراءة بيانات الوقت. Untitled غير مسمى Unable to write time data. غير قادر على كتابة بيانات الوقت. There are timers running. Stop timers and quit? بعض العدّادات ماتزال تعمل. هل أنت متأكد من رغبتك بالخروج؟ About حول A program to help track spent time برنامج بسيط لادارة و تتبع دوام الموظفين Question سؤال &Create Report... &إنشاء تقرير... View R&eports &عرض التقارير Cancel this session? هل تريد إلغاء هذه الجلسة؟ Add Project اضافة مشروع Enter project name: أدخل اسم المشروع: Error خطأ Unable to create time data location. غير قادر على إنشاء مكان بيانات الوقت. Unable to move time data location. غير قادر على نقل مكان بيانات الوقت. A project with that name already exists. هذا الاسم موجود مسبقاً. Remove selected project? هل تريد إزالة المشروع المحدد؟ %n timer(s) running %n مؤقت يعمل %n مؤقت يعمل Kapow Punch Clock كابو برنامج إدارة الوقت &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Store settings as INI format in specified file. file Do not create automatic backups of time data. The time data file to use. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_bg.ts000066400000000000000000000416321514263554100220260ustar00rootroot00000000000000 LocaleDialog Select application language: Изберете език за програмата: <System Language> <Системен език> Note Бележка Please restart this application for the change in language to take effect. Моля, рестартирайте програмата за да влезе в сила избраният език. Report Time Sheet Report Доклад Name: Име: Company: Фирма: Address: Адрес: Phone: Телефон: Fax: Факс: Email: E-Mail: Website: Интернет страница: N/A - Prepend currency symbol Добавяне валутата в началото Hourly rate: Чесова тарифа: Tax rate: Тарифа: Currency symbol: Валута: Contact Information Информация за контакти Data Данни Preview Предварителен преглед Export Print Печат Web Page (*.html *.htm) iCalendar (*.ics) Outlook CSV (*.csv) Export Report View Reports Create Report Phone: %1 Телефон: %1 Fax: %1 Факс: %1 Hours Часове Subtotal Междинна сума Taxes Такси Total Общо Remove Question Въпрос Remove newest report? Session %n hour(s) %n час %n часа %L1 hours %L1 часа SessionDelegate Error Грешка Session conflicts with other sessions. SessionDialog Add Session Добавяне на сесия Date: Дата: Start: Начало: Stop: Край: Task: Задача: Edit Session Редактиране на сесията SessionModel Total Общо Date Start Начало Stop Край Task Hours Часове Daily Weekly Monthly Report Window 00:00:00 00:00:00 Start Начало Stop Край Cancel Прекъсване &Minimize &Project &Проект &Add &Добавяне Ctrl+Shift+N &Remove &Премахване Ctrl+Shift+Delete &Quit &Изход Ctrl+Q Ctrl+Q &Session &Сесия &Edit &Редактиране Ctrl+Delete S&ettings &Настройки Columns Колони &Decimal Totals &Времена с десетична точка &Inline Editing &Директно редактиране Application &Language... Език на &програмата... &Help &Помощ &About &Относно About &Qt Относно &Qt Project Проект Timer Таймер Show all Показване на всички Show only unbilled Неплатени Show only this year Само от тази година Show only this month Само от този месец Show only this week Само от тази седмица Copyright &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Session conflicts with other sessions. &Restore Unable to read time data. Untitled Неозаглавена Unable to write time data. There are timers running. Stop timers and quit? Има активни таймери. Искате ли да ги спрете и да излезете от програмата? About Информация A program to help track spent time Програма за отчитане на изразходваното време Question Въпрос &Create Report... View R&eports Cancel this session? Прекъсване на тази сесия? Add Project Добавяне на проект Enter project name: Име на проекта: Error Грешка Unable to create time data location. Unable to move time data location. A project with that name already exists. Вече съществува проект с това име. Remove selected project? Премахване на избрания проект? %n timer(s) running %n активен таймер %n активни таймери Kapow Punch Clock Kapow Punch Clock &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Store settings as INI format in specified file. file Do not create automatic backups of time data. The time data file to use. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_cs.ts000066400000000000000000000413611514263554100220420ustar00rootroot00000000000000 LocaleDialog Select application language: Vyberte jazyk aplikace: <System Language> <Jazyk systému> Note Poznámka Please restart this application for the change in language to take effect. Aby se změna jazyka projevila, bude třeba aplikaci restartovat. Report Time Sheet Report Výkaz práce Name: Název: Company: Společnost: Address: Adresa: Phone: Telefon: Fax: Fax: Email: E-mail: Website: Web. stránky: N/A Nezadáno Prepend currency symbol Symbol měny uvádět před částkou Hourly rate: Hodinová sazba: Tax rate: Daňová sazba: Currency symbol: Symbol měny: Contact Information Kontaktní údaje Data Data Preview Náhled Export Export Print Tisk Web Page (*.html *.htm) Web. stránka (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Exportovat výkaz View Reports Zobrazit výkazy Create Report Vytvořit výkaz Phone: %1 Telefon: %1 Fax: %1 Fax: %1 Hours Hodiny Subtotal Mezisoučet Taxes Daně Total Celkem Remove Question Dotaz Remove newest report? Session %n hour(s) Jedna hodina %n hodiny %n hodin %n hodin %L1 hours %L1 hodin SessionDelegate Error Chyba Session conflicts with other sessions. Konflikty s ostatními sezeními. SessionDialog Add Session Přidat sezení Date: Datum: Start: Začátek: Stop: Konec: Task: Úkol: Edit Session Upravit sezení SessionModel Total Celkem Date Datum Start Začátek Stop Konec Task Úkol Hours Hodin Daily Denně Weekly Týdně Monthly Měsíčně Report Výkaz Window 00:00:00 00:00:00 Start Spustit Stop Zastavit Cancel Storno &Minimize &Minimalizovat &Project &Projekt &Add Přid&at Ctrl+Shift+N Ctrl+Shift+N &Remove Odst&ranit Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &Ukončit Ctrl+Q Ctrl+Q &Session &Sezení &Edit &Upravit Ctrl+Delete Ctrl+Delete S&ettings Nastav&ení Columns Sloupce &Decimal Totals &Desetinné zobrazení času &Inline Editing &Přímé upravování hodnot Application &Language... Jazyk ap&likace… &Help &Nápověda &About O &aplikaci About &Qt O &Qt Project Projekt Timer Časomíra Show all Zobrazit vše Show only unbilled Zobrazit pouze nevyúčtované hodiny Show only this year Zobrazit pouze tento rok Show only this month Zobrazit pouze tento měsíc Show only this week Zobrazit pouze tento týden Copyright &copy; 2008-%1 Graeme Gott Autorské právo © 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Vydáno pod licencí GNU <a href=%1>GPL 3</a> Session conflicts with other sessions. Konflikty s ostatními relacemi. &Restore &Obnovit Unable to read time data. Nedaří se načíst časová data. Untitled Bez názvu Unable to write time data. Nedaří se zapsat časová data. There are timers running. Stop timers and quit? Jsou spuštěné časomíry. Zastavit je a ukončit? About O aplikaci A program to help track spent time Aplikace která pomáhá udržovat si přehled o stráveném času. Question Dotaz &Create Report... &Vytvořit zprávu… View R&eports Zobrazit &zprávy Cancel this session? Zrušit toto sezení? Add Project Přidat projekt Enter project name: Zadat název projektu: Error Chyba Unable to create time data location. Nedaří se vytvořit umístění pro časová data. Unable to move time data location. Nedaří se přesunout umístění časových dat. A project with that name already exists. Projekt s tímto názvem už existuje. Remove selected project? Odstranit vybraný projekt? %n timer(s) running Spuštěná %n časomíra Spuštěné %n časomíry Spuštěných %n časomír Spuštěné %n časomíry Kapow Punch Clock Kapow, evidence odpracovaného času, verze &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Aplikace pro evidenci odpracovaného času Store settings as INI format in specified file. Uložit nastavení v INI formátu do zadaného souboru. file soubor Do not create automatic backups of time data. Nepořizovat automatické zálohy časových dat. The time data file to use. Soubor s časovými daty, který použít. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_da.ts000066400000000000000000000377261514263554100220330ustar00rootroot00000000000000 LocaleDialog Select application language: Vælg sprog: <System Language> <Systemsprog> Note Bemærk Please restart this application for the change in language to take effect. Programmet skal genstartes før ændringen træder i kraft. Report Time Sheet Report Timeseddel Name: Navn: Company: Firma: Address: Adresse: Phone: Telefon: Fax: Fax: Email: E-mail: Website: Hjemmeside: N/A Ikke tilgængelig Prepend currency symbol Tilføj valutasymbol i begyndelsen Hourly rate: Timeløn: Tax rate: Skatteprocent: Currency symbol: Valutasymbol: Contact Information Kontaktinformation Data Data Preview Forhåndsvisning Export Eksportér Print Udskriv Web Page (*.html *.htm) Hjemmeside (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Eksporteret rapport View Reports Vis rapporter Create Report Opret rapport Phone: %1 Telefon: %1 Fax: %1 Fax: %1 Hours Timer Subtotal Subtotal Taxes Skatter Total Total Remove Question Spørgsmål Remove newest report? Session %n hour(s) one: %n time other: %n timer %L1 hours %L1 timer SessionDelegate Error Fejl Session conflicts with other sessions. Session er i konflikt med andre sessioner. SessionDialog Add Session Tilføj session Date: Dato: Start: Start: Stop: Slut: Task: Opgave: Edit Session Rediger session SessionModel Total Total Date Dato Start Start Stop Stop Task Opgave Hours Timer Daily Dagligt Weekly Ugentligt Monthly Månedligt Report Rapport Window 00:00:00 00:00:00 Start Start Stop Stop Cancel Annuller &Minimize &Minimer &Project &Projekt &Add &Tilføj Ctrl+Shift+N Ctrl+Shift+N &Remove &Fjern Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &Afslut Ctrl+Q Ctrl+Q &Session &Session &Edit &Rediger Ctrl+Delete Ctrl+Delete S&ettings I&ndstillinger Columns Kolonner &Decimal Totals &Timer i decimaler &Inline Editing &Direkte redigering Application &Language... &Sprog... &Help &Hjælp &About &Om About &Qt Om &Qt Project Projekt Timer Timer Show all Vis alt Show only unbilled Vis kun ubetalte Show only this year Vis kun dette år Show only this month Vis kun denne måned Show only this week Vis kun denne uge Copyright &copy; 2008-%1 Graeme Gott Copyright &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Frigivet under <a href=%1>GPL 3</a>-licens Session conflicts with other sessions. Session er i konflikt med andre sessioner. &Restore &Gendan Unable to read time data. Kan ikke aflæse tidsdata. Untitled Unavngivet Unable to write time data. Kan ikke opgøre tidsdata. There are timers running. Stop timers and quit? Timere kører. Stop timere og afslut? About Om A program to help track spent time Et program til at holde styr på tidsforbruget Question Spørgsmål &Create Report... &Opret rapport... View R&eports Vis R&apporter Cancel this session? Annuller denne session? Add Project Tilføj projekt Enter project name: Angiv projektnavn: Error Fejl Unable to create time data location. Kunne ikke oprette placering. Unable to move time data location. Kunne ikke flytte placering. A project with that name already exists. Et projekt med dette navn eksisterer allerede. Remove selected project? Fjern valgte projekt? %n timer(s) running %n timer kører %n timere kører Kapow Punch Clock Kapow Punch Clock &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Stempelur til tidstagning Store settings as INI format in specified file. Gem indstillinger i INI-format i fil. file fil Do not create automatic backups of time data. Opret ikke automatiske backups af tidsdata. The time data file to use. Tidsdatafilen, der skal bruges. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_de.ts000066400000000000000000000403331514263554100220230ustar00rootroot00000000000000 LocaleDialog Select application language: Programmsprache auswählen <System Language> <Betriebssystemsprache> Note Achtung! Please restart this application for the change in language to take effect. Programm neu starten, um die Sprachänderung wirksam werden zu lassen. Report Time Sheet Report Zeiterfassungsbericht Name: Name: Company: Firma: Address: Anschrift: Phone: Tel.: Fax: Fax: Email: E-Mail: Website: Website: N/A N/A Prepend currency symbol Währungssymbol voranstellen Hourly rate: Stundensatz: Tax rate: MwSt.-Satz: Currency symbol: Währungssymbol: Contact Information Kontaktdaten Data Zeiterfassungsdaten Preview Vorschau Export Exportieren Print Drucken Web Page (*.html *.htm) Web Page (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Bericht exportieren View Reports Berichte anzeigen Create Report Bericht erstellen Phone: %1 Tel.: %1 Fax: %1 Fax: %1 Hours Stunden Subtotal Zwischensumme Taxes MwSt. Total Endsumme Remove Question Frage Remove newest report? Session %n hour(s) %n Stunde %n Stunden %L1 hours %L1 Stunden SessionDelegate Error Fehler Session conflicts with other sessions. Überschneidung mit anderem Eintrag. SessionDialog Add Session Eintrag hinzufügen Date: Datum: Start: Start: Stop: Ende: Task: Aufgabe: Edit Session Eintrag bearbeiten SessionModel Total Summe Date Datum Start Start Stop Ende Task Aufgabe Hours Stunden Daily Täglich Weekly Wöchentlich Monthly Monatlich Report Bericht Window 00:00:00 00:00:00 Start Start Stop Stop Cancel Abbrechen &Minimize &Minimieren &Project &Projekt &Add &Hinzufügen Ctrl+Shift+N Strg+Shift+N &Remove &Entfernen Ctrl+Shift+Delete Strg+Shift+Entf &Quit &Beenden Ctrl+Q Ctrl+Q &Session &Eintrag &Edit &Bearbeiten Ctrl+Delete Strg+Entf S&ettings &Einstellungen Columns Spalten &Decimal Totals &Zeitanzeige dezimal &Inline Editing &direkte Wertebearbeitung Application &Language... Programmsprache &Help &Hilfe &About &Über About &Qt Über &Qt Project Projekt Timer Zeiterfassung Show all Alle anzeigen Show only unbilled Nur nicht abgerechnete anzeigen Show only this year Nur dieses Jahr anzeigen Show only this month Nur diesen Monat anzeigen Show only this week Nur diese Woche anzeigen Copyright &copy; 2008-%1 Graeme Gott Copyright &copy; 2008-2011 Graeme Gott. Released under the <a href=%1>GPL 3</a> license Veröffentlicht unter <a href=%1>GPL 3</a> license Session conflicts with other sessions. Überschneidung mit anderem Eintrag. &Restore &Wiederherstellen Unable to read time data. Unfähig die Zeit zu lesen. Untitled Ohne Titel Unable to write time data. Unfähig die Zeit Daten zu schreiben. There are timers running. Stop timers and quit? Zeiterfassung läuft. Stoppen und Programm beenden? About Über A program to help track spent time Ein Programm zur Zeiterfassung am Rechner. Question Frage &Create Report... Bericht erstellen... View R&eports Berichte anzeigen Cancel this session? Eintrag abbrechen? Add Project Projekt hinzufügen Enter project name: Projektname eingeben: Error Fehler Unable to create time data location. Der Zeitdaten Standort kann nicht erstellt werden. Unable to move time data location. Der Zeitdaten Speicherort kann nicht verschoben werden. A project with that name already exists. Ein Projekt dieses Namens besteht bereits. Remove selected project? Ausgewähltes Projekt löschen? %n timer(s) running %n Zeiterfassung läuft %n Zeiterfassungen laufen Kapow Punch Clock Kapow Zeiterfassung &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Zeiterfassungsprogramm Store settings as INI format in specified file. Die Einstellungen als INI-Format in der angegebenen Datei speichern. file Datei Do not create automatic backups of time data. Keine automatischen Backups von Zeitdaten erstellen. The time data file to use. Die verwendete Zeitdatendatei. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_el.ts000066400000000000000000000437151514263554100220420ustar00rootroot00000000000000 LocaleDialog Select application language: Επιλέξτε γλώσσα εφαρμογής: <System Language> <Γλώσσα συστήματος> Note Σημείωση Please restart this application for the change in language to take effect. Παρακαλώ επανεκκινήστε το πρόγραμμα για εφαρμογή της αλλαγής στη γλώσσα. Report Time Sheet Report Αναφορά κατανομής χρόνου Name: Όνομα: Company: Εταιρεία: Address: Διεύθυνση: Phone: Τηλέφωνο: Fax: Φαξ: Email: Email: Website: Ιστότοπος: N/A Μη διαθέσιμο Prepend currency symbol Προηγείται το σύμβολο νομίσματος Hourly rate: Ωρομίσθιο: Tax rate: ΦΠΑ: Currency symbol: Σύμβολο νομίσματος: Contact Information Στοιχεία επικοινωνίας Data Δεδομένα Preview Προεπισκόπηση Export Εξαγωγή Print Εκτύπωση Web Page (*.html *.htm) Ιστοσελίδα (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Εξαγωγή αναφοράς View Reports Προβολή αναφορών Create Report Δημιουργία αναφοράς Phone: %1 Τηλέφωνο: %1 Fax: %1 Φαξ: %1 Hours Ώρες Subtotal Μερικό σύνολο Taxes Φόροι Total Σύνολο Remove Question Ερώτηση Remove newest report? Session %n hour(s) %n ώρα %n ώρες %L1 hours %L1 ώρες SessionDelegate Error Σφάλμα Session conflicts with other sessions. Η συνεδρία έρχεται σε διένεξη με άλλες συνεδρίες. SessionDialog Add Session Προσθήκη συνεδρίας Date: Ημερομηνία: Start: Έναρξη: Stop: Διακοπή: Task: Εργασία: Edit Session Επεξεργασία συνεδρίας SessionModel Total Σύνολο Date Ημερομηνία Start Έναρξη Stop Διακοπή Task Εργασία Hours Ώρες Daily Ημερήσια Weekly Εβδομαδιαία Monthly Μηνιαία Report Αναφορά Window 00:00:00 00:00:00 Start Έναρξη Stop Διακοπή Cancel Άκυρο &Minimize &Ελαχιστοποίηση &Project Έρ&γο &Add &Προσθήκη Ctrl+Shift+N Ctrl+Shift+Ν &Remove &Απαλοιφή Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit Έ&ξοδος Ctrl+Q Ctrl+Q &Session &Συνεδρία &Edit &Επεξεργασία Ctrl+Delete Ctrl+Delete S&ettings &Ρυθμίσεις Columns Στήλες &Decimal Totals Σύνολα σε &δεκαδική μορφή &Inline Editing &Επεξεργασία στη γραμμή Application &Language... &Γλώσσα προγράμματος... &Help &Βοήθεια &About &Περί About &Qt Περί &Qt Project Έργο Timer Χρονόμετρο Show all Εμφάνιση όλων Show only unbilled Εμφάνιση μόνο μη τιμολογημένων Show only this year Εμφάνιση μόνο αυτό το έτος Show only this month Εμφάνιση μόνο αυτό το μήνα Show only this week Εμφάνιση μόνο αυτή την εβδομάδα Copyright &copy; 2008-%1 Graeme Gott Copyright &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Κυκλοφορεί υπό την Γενική Δημόσια Άδεια <a href=%1>GPL 3</a> Session conflicts with other sessions. Η συνεδρία έρχεται σε διένεξη με άλλες συνεδρίες. &Restore Επανα&φορά Unable to read time data. Δεν ήταν δυνατή η ανάγνωση των δεδομένων χρόνου. Untitled Ανώνυμο Unable to write time data. Δεν ήταν δυνατή η εγγραφή των δεδομένων χρόνου. There are timers running. Stop timers and quit? Υπάρχουν χρονόμετρα σε λειτουργία. Διακοπή χρονομέτρων και έξοδος; About Περί A program to help track spent time Πρόγραμμα παρακολούθησης χρόνου εργασίας Question Ερώτηση &Create Report... &Δημιουργία αναφοράς... View R&eports Π&ροβολή αναφορών Cancel this session? Ακύρωση αυτής της συνεδρίας; Add Project Προσθήκη έργου Enter project name: Εισαγωγή ονόματος έργου: Error Σφάλμα Unable to create time data location. Δεν ήταν δυνατή η δημιουργία θέσης δεδομένων χρόνου. Unable to move time data location. Δεν ήταν δυνατή η μετακίνηση της θέσης δεδομένων χρόνου. A project with that name already exists. Υπάρχει ήδη ένα έργο με αυτό το όνομα. Remove selected project? Απαλοιφή επιλεγμένου έργου; %n timer(s) running %n χρονόμετρο λειτουργεί %n χρονόμετρα λειτουργούν Kapow Punch Clock Kapow Punch Clock &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Πρόγραμμα χρονομέτρου εργασίας Store settings as INI format in specified file. Αποθήκευση ρυθμίσεων με μορφή INI στο καθορισμένο αρχείο. file αρχείο Do not create automatic backups of time data. Όχι αυτόματη δημιουργία αντιγράφων ασφαλείας των δεδομένων χρόνου. The time data file to use. Το αρχείο δεδομένων χρόνου που θα χρησιμοποιηθεί. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_en.ts000066400000000000000000000406061514263554100220400ustar00rootroot00000000000000 LocaleDialog Select application language: <System Language> Note Please restart this application for the change in language to take effect. Report Time Sheet Report Name: Company: Address: Phone: Fax: Email: Website: N/A Prepend currency symbol Hourly rate: Tax rate: Currency symbol: Contact Information Data Preview Export Print Web Page (*.html *.htm) iCalendar (*.ics) Outlook CSV (*.csv) Export Report View Reports Create Report Phone: %1 Fax: %1 Hours Subtotal Taxes Total Remove Question Remove newest report? Session %n hour(s) %n hour %n hours %L1 hours SessionDelegate Error Session conflicts with other sessions. SessionDialog Add Session Date: Start: Stop: Task: Edit Session SessionModel Total Date Start Stop Task Hours Daily Weekly Monthly Report Window 00:00:00 Start Stop Cancel &Minimize &Project &Add Ctrl+Shift+N &Remove Ctrl+Shift+Delete &Quit Ctrl+Q &Session &Edit Ctrl+Delete S&ettings Columns &Decimal Totals &Inline Editing Application &Language... &Help &About About &Qt Project Timer Show all Show only unbilled Show only this year Show only this month Show only this week Copyright &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Session conflicts with other sessions. &Restore Unable to read time data. Untitled Unable to write time data. There are timers running. Stop timers and quit? About A program to help track spent time Question &Create Report... View R&eports Cancel this session? Add Project Enter project name: Error Unable to create time data location. Unable to move time data location. A project with that name already exists. Remove selected project? %n timer(s) running %n timer running %n timers running Kapow Punch Clock &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Remove selected session? Remove selected sessions? Move Session(s) Move Session Move Sessions Move Could not move session(s) because of conflicts. Could not move session because of conflicts. Could not move sessions because of conflicts. main Punch clock program Store settings as INI format in specified file. file Do not create automatic backups of time data. The time data file to use. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_es.ts000066400000000000000000000407401514263554100220440ustar00rootroot00000000000000 LocaleDialog Select application language: Seleccione el idioma de la aplicación: <System Language> <Idioma del sistema> Note Nota Please restart this application for the change in language to take effect. Reinicie la aplicación para el cambio de idioma surta efecto. Report Time Sheet Report Informe de horas trabajadas Name: Nombre: Company: Empresa: Address: Dirección: Phone: Teléfono: Fax: Fax: Email: Correo electrónico: Website: Página web: N/A N/D Prepend currency symbol Anteponer símbolo de moneda Hourly rate: Tarifa por hora: Tax rate: Tasa de impuesto: Currency symbol: Símbolo de moneda: Contact Information Información de contacto Data Datos Preview Previsualización Export Exportar Print Imprimir Web Page (*.html *.htm) Página web (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) CSV de Outlook (*.csv) Export Report Exportar el informe View Reports Ver los informes Create Report Crear informe Phone: %1 Teléfono: %1 Fax: %1 Fax: %1 Hours Horas Subtotal Subtotal Taxes Impuestos Total Total Remove Question Pregunta Remove newest report? Session %n hour(s) %n hora %n horas %n horas %L1 hours %L1 horas SessionDelegate Error Error Session conflicts with other sessions. SessionDialog Add Session Añadir sesión Date: Fecha: Start: Inicio: Stop: Fin: Task: Tarea: Edit Session Editar sesión SessionModel Total Total Date Fecha Start Iniciar Stop Detener Task Tarea Hours Horas Daily Diario Weekly Semanalmente Monthly Mensualmente Report Reporte Window 00:00:00 00:00:00 Start Iniciar Stop Detener Cancel Cancelar &Minimize &Minimizar &Project &Proyecto &Add &Añadir Ctrl+Shift+N Ctrl+Mayús+N &Remove &Remover Ctrl+Shift+Delete Ctrl+Mayús+Supr &Quit &Salir Ctrl+Q Ctrl+Q &Session &Sesión &Edit &Editar Ctrl+Delete Ctrl+Supr S&ettings &Configuración Columns Columnas &Decimal Totals &Totales decimales &Inline Editing &Edición en la misma línea Application &Language... &Idioma de la aplicación… &Help Ay&uda &About &Acerca de About &Qt Acerca de &Qt Project Proyecto Timer Temporizador Show all Mostrar todo Show only unbilled Mostrar solo no facturados Show only this year Mostrar solo este año Show only this month Mostrar solo este mes Show only this week Mostrar solo esta semana Copyright &copy; 2008-%1 Graeme Gott Copyright &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Publicado bajo la licencia <a href=%1>GPL 3</a> Session conflicts with other sessions. &Restore Unable to read time data. No se pudieron leer los datos del tiempo. Untitled Sin título Unable to write time data. No se pudieron escribir los datos del tiempo. There are timers running. Stop timers and quit? Hay temporizadores en ejecución. ¿Quiere detenerlos y salir? About Acerca de A program to help track spent time Un programa para ayudar a rastrear tiempo consumido Question Pregunta &Create Report... &Crear el informe… View R&eports Ver los in&formes Cancel this session? ¿Quiere cancelar esta sesión? Add Project Añadir un proyecto Enter project name: Escriba el nombre del proyecto: Error Error Unable to create time data location. No se pudo crear la ubicación de datos del tiempo. Unable to move time data location. No se pudo mover la ubicación de datos del tiempo. A project with that name already exists. Ya existe un proyecto con ese nombre. Remove selected project? ¿Quiere eliminar el proyecto seleccionado? %n timer(s) running %n temporizador ejecutándose %n temporizadores ejecutándose %n temporizadores ejecutándose Kapow Punch Clock Reloj de control Kapow &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Store settings as INI format in specified file. file Do not create automatic backups of time data. The time data file to use. El archivo temporal a usar. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_et.ts000066400000000000000000000406321514263554100220450ustar00rootroot00000000000000 LocaleDialog Select application language: Vali rakenduse keel: <System Language> <System Language> Note Märkus Please restart this application for the change in language to take effect. Selle muudatuse jõustamiseks palun käivita rakendus uuesti. Report Time Sheet Report Ajaarvestuse aruanne Name: Nimi: Company: Firma: Address: Aadress: Phone: Telefon: Fax: Telefaks: Email: E-posti aadress: Website: Veebisait: N/A n/a Prepend currency symbol Lisa valuuta sümbol ette Hourly rate: Tunnitariif: Tax rate: Maksumäär: Currency symbol: Valuutasümbol: Contact Information Kontaktteave Data Andmed Preview Eelvaade Export Ekspordi Print Trüki Web Page (*.html *.htm) Veebileht (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Ekspordi aruanne View Reports Vaata aruandeid Create Report Koosta aruanne Phone: %1 Telefon: %1 Fax: %1 Telefaks: %1 Hours Tunde Subtotal Vahesumma Taxes Maksud Total Kokku Remove Eemalda Question Küsimus Remove newest report? Kas eemaldame viimase aruande? Session %n hour(s) %n tund %n tundi %L1 hours %L1 tundi SessionDelegate Error Viga Session conflicts with other sessions. See sessioon on teiste sessioonidega vastuolus. SessionDialog Add Session Lisa sessioon Date: Kuupäev: Start: Algus: Stop: Lõpp: Task: Ülesanne: Edit Session Muuda sessiooni SessionModel Total Kokku Date Kuupäev Start Algus Stop Lõpp Task Ülesanne Hours Tunde Daily Päevas Weekly Nädalas Monthly Kuus Report Aruanne Window 00:00:00 00:00:00 Start Alusta Stop Lõpeta Cancel Katkesta &Minimize &Minimeeri &Project &Projekt &Add &Lisa Ctrl+Shift+N Ctrl+Shift+N &Remove &Eemalda Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &Välju Ctrl+Q Ctrl+Q &Session &Sessioon &Edit &Muuda Ctrl+Delete Ctrl+Delete S&ettings S&eadistused Columns Veerud &Decimal Totals Ajaarvestuse summad kümnen&dsüsteemis &Inline Editing Muuda k&irjet avamata Application &Language... Rakenduse kee&l &Help &Abiteave &About R&akenduse teave About &Qt &Qt teave Project Projekt Timer Taimer Show all Näita kõiki Show only unbilled Näita neid, kus arve on tegemata Show only this year Näita selle aasta kirjeid Show only this month Näita selle kuu kirjeid Show only this week Näita selle nädala kirjeid Copyright &copy; 2008-%1 Graeme Gott Autoriõigused &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Avaldatud <a href=%1>GPL 3</a> litsentsi alusel Session conflicts with other sessions. Sessiooni vastuolud teiste sessioonidega. &Restore &Taasta Unable to read time data. Ajaandmete lugemine ei õnnestu. Untitled Ilma nimeta Unable to write time data. Ajaandmete salvestamine ei õnnestu. There are timers running. Stop timers and quit? Taimerid on töös. Kas peatame taimerid ja lõpetame töö? About Rakenduse teave A program to help track spent time Programm ajaarvestuse haldamiseks Question Küsimus &Create Report... &Koosta aruanne... View R&eports Vaata aruand&eid Cancel this session? Kas katkestame selle sessiooni? Add Project Lisa projekt Enter project name: Sisesta projekti nimi Error Viga Unable to create time data location. Ajaandmete salvestamise asukoha loomine ei õnnestu. Unable to move time data location. Ajaandmete salvestamise asukoha teisaldamine ei õnnestu. A project with that name already exists. Sellise nimega projekt on juba olemas. Remove selected project? Kas kustutame valitud projekti? %n timer(s) running %n taimer on töös %n taimerit on töös Kapow Punch Clock Kapow - sinu tööaja arvestus &Close to Tray &Sulge süsteemisalve Re&move Report Ee&malda aruanne &Start Minimized &Käivita minimeerituna Stop All Peata kõik Stop all timers? Kas peatame kõik taimerid? &Move To... &Teisalda asukohta... Remove selected session(s)? Kas eemaldad valitud sessiooni? Kas eemaldad valitud sessioonid? Move Session(s) Teisalda sessioon Teisalda sessioonid Move Teisalda Could not move session(s) because of conflicts. Andmekonfliktide tõttu ei õnnestunud sessiooni teisaldamine. Andmekonfliktide tõttu ei õnnestunud sessioonide teisaldamine. main Punch clock program Tööaja arvestuse programm Store settings as INI format in specified file. Salvesta seadistused määratud faili ini-vormingus. file fail Do not create automatic backups of time data. Ära tee andmetest automaatset varukoopiat. The time data file to use. Kasutatav ajaandmete fail. Start minimized in system tray. Käivita minimeerituna süsteemisalve gottcode-kapow-350ecea/translations/kapow_fr.ts000066400000000000000000000420651514263554100220460ustar00rootroot00000000000000 LocaleDialog Select application language: Sélectionner la langue pour l'application : <System Language> <Langue du système> Note Remarque Please restart this application for the change in language to take effect. Veuillez relancer l'application pour que la modification de la langue prenne effet. Report Time Sheet Report Fiche horaire Name: Nom : Company: Société : Address: Adresse : Phone: Téléphone : Fax: Télécopie : Email: Courriel : Website: Site web : N/A N/D Prepend currency symbol Faire précéder le symbole monétaire Hourly rate: Taux horaire : Tax rate: TVA : Currency symbol: Symbole monétaire : Contact Information Informations sur le contact Data Données Preview Aperçu Export Exporter Print Imprimer Web Page (*.html *.htm) Page Web (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) CSV Outlook (*.csv) Export Report Exporter le rapport View Reports Afficher les rapports Create Report Créer un rapport Phone: %1 Téléphone : %1 Fax: %1 Télécopie : %1 Hours Heures Subtotal Sous-total Taxes TVA Total Total Remove Supprimer Question Question Remove newest report? Supprimer le dernier rapport ? Session %n hour(s) %n heure %n heures %n heures %L1 hours %L1 heures SessionDelegate Error Erreur Session conflicts with other sessions. Session en conflit avec d'autres sessions. SessionDialog Add Session Ajouter une session Date: Date : Start: Début : Stop: Fin : Task: Tâche : Edit Session Modifier la session SessionModel Total Total Date Date Start Démarrer Stop Arrêter Task Tâche Hours Heures Daily Quotidien Weekly Hebdomadaire Monthly Mensuel Report Rapport Window 00:00:00 00:00:00 Start Démarrer Stop Arrêter Cancel Annuler &Minimize &Réduire &Project &Projet &Add &Ajouter Ctrl+Shift+N Ctrl+Maj+N &Remove &Supprimer Ctrl+Shift+Delete Ctrl+Maj+Suppr &Quit &Quitter Ctrl+Q Ctrl+Q &Session &Session &Edit &Modifier Ctrl+Delete Ctrl+Suppr S&ettings &Paramètres Columns Colonnes &Decimal Totals Totaux &décimaux &Inline Editing Mod&ification en ligne Application &Language... &Langue de l'application… &Help &Aide &About À &propos de… About &Qt À propos de &Qt Project Projet Timer Minuteur Show all Afficher tout Show only unbilled Heures non-facturées uniquement Show only this year Cette année uniquement Show only this month Ce mois uniquement Show only this week Cette semaine uniquement Copyright &copy; 2008-%1 Graeme Gott Copyright &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Distribué sous licence GNU <a href=%1>GPL 3</a> Session conflicts with other sessions. Session en conflit avec d'autres sessions. &Restore &Agrandir Unable to read time data. Impossible de lire les données horaires. Untitled Sans titre Unable to write time data. Impossible d'écrire les données horaires. There are timers running. Stop timers and quit? Des minuteurs sont toujours en cours d'exécution. Voulez-vous les arrêter et quitter ? About À propos A program to help track spent time Programme d'aide au suivi du temps passé Question Question &Create Report... &Créer un rapport… View R&eports &Afficher les rapports Cancel this session? Annuler cette session ? Add Project Ajouter un projet Enter project name: Nom du projet : Error Erreur Unable to create time data location. Impossible de créer l'emplacement des données horaires. Unable to move time data location. Impossible de déplacer l'emplacement des données horaires. A project with that name already exists. Un projet portant le même nom existe déjà. Remove selected project? Supprimer le projet sélectionné ? %n timer(s) running %n minuteur en cours %n minuteurs en cours %n minuteurs en cours Kapow Punch Clock Pointeuse Kapow &Close to Tray &Placer dans la barre Re&move Report Su&pprimer le rapport &Start Minimized &Démarrer minimisé Stop All Arrêter tout Stop all timers? Arrêter tous les minuteurs ? &Move To... Dé&placer vers... Remove selected session(s)? Supprimer la session sélectionnée ? Supprimer les sessions sélectionnées ? Supprimer les sessions sélectionnées ? Move Session(s) Déplacer la session Déplacer les sessions Déplacer les sessions Move Déplacer Could not move session(s) because of conflicts. Déplacement de la session impossible en raison de conflits. Déplacement des sessions impossible en raison de conflits. Déplacement de session impossible en raison de conflits. main Punch clock program Programme de pointeuse Store settings as INI format in specified file. Stocker les paramètres au format INI dans le fichier indiqué. file fichier Do not create automatic backups of time data. Ne pas créer de sauvegarde automatique des données horaires. The time data file to use. Fichier à utiliser pour les données horaires. Start minimized in system tray. Démarrage minimisé dans la barre des tâches. gottcode-kapow-350ecea/translations/kapow_it.ts000066400000000000000000000411231514263554100220450ustar00rootroot00000000000000 LocaleDialog Select application language: Seleziona la lingua dell'applicazione: <System Language> <Lingua di sistema> Note Note Please restart this application for the change in language to take effect. Per favore è necessario riavviare l'applicazione affinché il cambio di lingua abbia effetto. Report Time Sheet Report Rapporto ore lavorate Name: Nome: Company: Ditta: Address: Indirizzo: Phone: Telefono: Fax: Fax: Email: Email: Website: Sito web: N/A N/A Prepend currency symbol Anteponi simbolo valuta Hourly rate: Tasso orario: Tax rate: percentuale di tasse: Currency symbol: Simbolo valuta: Contact Information Informazioni contatto Data Data Preview Anteprima Export Esporta Print Stampa Web Page (*.html *.htm) pagina web (*.html, *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Esporta Report View Reports Visualizza Report Create Report Crea Report Phone: %1 Telefono: %1 Fax: %1 Fax: %1 Hours Ore Subtotal Subtotale Taxes Tasse Total Totale Remove Rimuovi Question Domanda Remove newest report? Rimuovere il rapporto più recente? Session %n hour(s) %n ora %n ore %n ore %L1 hours %L1 ore SessionDelegate Error Errore Session conflicts with other sessions. La sessone è in conflitto con altre sessioni SessionDialog Add Session Aggiungi sessione Date: Data: Start: Inizio: Stop: Fine: Task: Compito: Edit Session Modifica sessione SessionModel Total Totale Date Data Start Start Stop Stop Task Compito Hours Ore Daily Giornaliero Weekly Settimanale Monthly Mensile Report Report Window 00:00:00 00:00:00 Start Inizio Stop Fine Cancel Cancella &Minimize Minimizza &Project &Progetto &Add &Aggiungi Ctrl+Shift+N Ctrl+Shift+N &Remove &Rimuovi Ctrl+Shift+Delete Ctrl+Shift+Canc &Quit &Esci Ctrl+Q Ctrl+Q &Session &Sessione &Edit &Modifica Ctrl+Delete Ctrl+Canc S&ettings &Impostazioni Columns Colonne &Decimal Totals Totali &Decimali &Inline Editing &Modifica in linea Application &Language... &Lingua... &Help &Aiuto &About &A proposito About &Qt A proposito delle &Qt Project Progetto Timer Tempo Show all Mostra tutto Show only unbilled Mostra solo occorrenze non fatturate Show only this year Mostra solo occorrenze di quest'anno Show only this month Mostra solo occorrenze di questo mese Show only this week Mostra solo occorrenze di questa settimana Copyright &copy; 2008-%1 Graeme Gott Copyright &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Rilasciata sotto licenza <a href=%1>GPL 3</a> Session conflicts with other sessions. La sessione è in conflitto con altre sessioni. &Restore &Ripristina Unable to read time data. Impossibile leggere i dati relativi alla temporizzazione Untitled Senza titolo Unable to write time data. Impossibile leggere i dati relativi alla temporizzazione. There are timers running. Stop timers and quit? Ci sono dei timer in esecuzione. Fermare i timer e chiudere l'applicazione? About A proposito A program to help track spent time Un programma per aiutarvi a tenere traccia del tempo speso Question Domande &Create Report... &Crea Report... View R&eports Visualizza R&eports Cancel this session? Cancella questa sessione? Add Project Aggiungi Progetto Enter project name: Inserisci nome progetto: Error Errore Unable to create time data location. Impossibile creare la posizione dei dati temporali. Unable to move time data location. Impossibile spostare la posizione dei dati temporali. A project with that name already exists. Un progetto con quel nome esiste già. Remove selected project? Rimuovi il progetto selezionato? %n timer(s) running %n orologio partito %n orologi partito %n orologi partito Kapow Punch Clock Kapow Punch Clock &Close to Tray Re&move Report Ri&muovi Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Store settings as INI format in specified file. Memorizza le impostazioni come formato INI nel file specificato. file file Do not create automatic backups of time data. Non creare backup automatici dei dati temporali. The time data file to use. Il file di dati temporali da utilizzare. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_lt.ts000066400000000000000000000422061514263554100220530ustar00rootroot00000000000000 LocaleDialog Select application language: Pasirinkite programos kalbą: <System Language> <Sistemos kalba> Note Pastaba Please restart this application for the change in language to take effect. Tam, kad įsigaliotų kalbos pakeitimai, prašome paleisti programą iš naujo. Report Time Sheet Report Tabelis Name: Vardas: Company: Įmonė: Address: Adresas: Phone: Telefono nr.: Fax: Faksas: Email: El. paštas: Website: Svetainė: N/A Nėra Prepend currency symbol Valiutos simbolį pridėti pradžioje Hourly rate: Valandinis tarifas: Tax rate: Mokesčių tarifas: Currency symbol: Valiutos simbolis: Contact Information Kontaktinė informacija Data Duomenys Preview Peržiūra Export Eksportuoti Print Spausdinti Web Page (*.html *.htm) Internetinis puslapis (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Eksportuoti ataskaitą View Reports Žiūrėti ataskaitas Create Report Sukurti ataskaitą Phone: %1 Telefono nr.: %1 Fax: %1 Faksas: %1 Hours Valandos Subtotal Tarpinė suma Taxes Mokesčiai Total Iš viso Remove Šalinti Question Klausimas Remove newest report? Šalinti naujausią ataskaitą? Session %n hour(s) %n valanda %n valandos %n valandų %n valandų %L1 hours %L1 valandų SessionDelegate Error Klaida Session conflicts with other sessions. Seansas konfliktuoja su kitais seansais. SessionDialog Add Session Pridėti seansą Date: Data: Start: Pradžia: Stop: Pabaiga: Task: Užduotis: Edit Session Redaguoti seansą SessionModel Total Iš viso Date Data Start Pradėta Stop Užbaigta Task Užduotis Hours Valandų Daily Per dieną Weekly Per savaitę Monthly Per mėnesį Report Ataskaita Window 00:00:00 00:00:00 Start Pradėti Stop Stabdyti Cancel Atsisakyti &Minimize &Suskleisti &Project &Projektas &Add P&ridėti Ctrl+Shift+N Ctrl+Shift+N &Remove Ša&linti Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &Išeiti Ctrl+Q Ctrl+Q &Session &Seansas &Edit R&edaguoti Ctrl+Delete Ctrl+Delete S&ettings &Nustatymai Columns Stulpeliai &Decimal Totals &Dešimtainis apvalinimas &Inline Editing &Redagavimas eilutėse Application &Language... Programos ka&lba... &Help Ži&nynas &About &Apie About &Qt Apie &Qt Project Projektas Timer Laikmatis Show all Rodyti visas Show only unbilled Rodyti tik neapmokestinamas Show only this year Rodyti tik šių metų Show only this month Rodyti tik šio mėnesio Show only this week Rodyti tik šios savaitės Copyright &copy; 2008-%1 Graeme Gott Autorių Teisės &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Išleista pagal <a href=%1>GPL 3</a> licenciją Session conflicts with other sessions. Seansas konfliktuoja su kitais seansais. &Restore &Atkurti Unable to read time data. Nepavyko perskaityti laiko duomenų. Untitled Bevardis Unable to write time data. Nepavyko įrašyti laiko duomenų. There are timers running. Stop timers and quit? Yra aktyvių laikmačių. Sustabdyti laikmačius ir išeiti? About Apie A program to help track spent time Programa, padedanti sekti leidžiamą laiką Question Klausimas &Create Report... Su&kurti ataskaitą... View R&eports Žiūrėti a&taskaitas Cancel this session? Atšaukti šį seansą? Add Project Pridėti projektą Enter project name: Įveskite projekto pavadinimą: Error Klaida Unable to create time data location. Nepavyko sukurti laiko duomenų vietos. Unable to move time data location. Nepavyko perkelti laiko duomenų vietos. A project with that name already exists. Projektas tokiu pavadinimu jau yra. Remove selected project? Šalinti pasirinktą projektą? %n timer(s) running %n aktyvus laikmatis %n aktyvūs laikmačiai %n aktyvių laikmačių %n aktyvių laikmačių Kapow Punch Clock Kapow kontrolinis laikrodis &Close to Tray &Užverti į dėklą Re&move Report Ša&linti ataskaitą &Start Minimized &Paleisti suskleistą Stop All Stabdyti visus Stop all timers? Stabdyti visus laikmačius? &Move To... &Perkelti į... Remove selected session(s)? Šalinti pasirinktą seansą? Šalinti pasirinktus seansus? Šalinti pasirinktus seansus? Šalinti pasirinktus seansus? Move Session(s) Perkelti seansą Perkelti seansus Perkelti seansus Perkelti seansus Move Perkelti Could not move session(s) because of conflicts. Nepavyko perkelti seanso dėl konfliktų. Nepavyko perkelti seansų dėl konfliktų. Nepavyko perkelti seansų dėl konfliktų. Nepavyko perkelti seansų dėl konfliktų. main Punch clock program Kontrolinio laikrodžio programa Store settings as INI format in specified file. Saugoti nustatymus INI formatu nurodytame faile. file failas Do not create automatic backups of time data. Nekurti automatinių laiko duomenų atsarginių kopijų. The time data file to use. Laiko duomenų failas, kurį naudoti. Start minimized in system tray. Paleisti suskleistą sistemos dėkle. gottcode-kapow-350ecea/translations/kapow_nl.ts000066400000000000000000000407641514263554100220540ustar00rootroot00000000000000 LocaleDialog Select application language: Kies de programmataal: <System Language> <Systeemtaal> Note Let op: Please restart this application for the change in language to take effect. Herstart het programma om de taalwijziging toe te passen. Report Time Sheet Report Tijdkaartrapport Name: Naam: Company: Bedrijf: Address: Adres: Phone: Telefoonnummer: Fax: Fax: Email: E-mailadres: Website: Website: N/A n.v.t. Prepend currency symbol Valutateken toevoegen Hourly rate: Uurloon: Tax rate: Belastingtarief: Currency symbol: Valutateken: Contact Information Contactinformatie Data Gegevens Preview Voorvertoning Export Exporteren Print Afdrukken Web Page (*.html *.htm) Webpagina (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook (*.csv) Export Report Rapport exporteren View Reports Rapporten bekijken Create Report Rapport opstellen Phone: %1 Telefoonnummer: %1 Fax: %1 Fax: %1 Hours Uren Subtotal Subtotaal Taxes Belasting Total Totaal Remove Verwijderen Question Vraag Remove newest report? Wilt u het recentste rapport verwijderen? Session %n hour(s) %n uur %n uur %L1 hours %L1 uur SessionDelegate Error Foutmelding Session conflicts with other sessions. De sessie botst met andere sessies. SessionDialog Add Session Sessie toevoegen Date: Datum: Start: Begintijd: Stop: Eindtijd: Task: Taak: Edit Session Sessie bewerken SessionModel Total Totaal Date Datum Start Begintijd Stop Eindtijd Task Taak Hours Uren Daily Dagelijks Weekly Wekelijks Monthly Maandelijks Report Rapport Window 00:00:00 00:00:00 Start Starten Stop Stoppen Cancel Annuleren &Minimize &Minimaliseren &Project &Project &Add &Toevoegen Ctrl+Shift+N Ctrl+Shift+N &Remove Ve&rwijderen Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &Afsluiten Ctrl+Q Ctrl+Q &Session &Sessie &Edit B&ewerken Ctrl+Delete Ctrl+Delete S&ettings Inst&ellingen Columns Kolommen &Decimal Totals Aantal &decimalen &Inline Editing H&ier bewerken Application &Language... Programmataa&l… &Help &Hulp &About &Over About &Qt Over &Qt Project Project Timer Tijdklok Show all Alles tonen Show only unbilled Alleen ongefactureerde tonen Show only this year Alleen dit jaar tonen Show only this month Alleen deze maand tonen Show only this week Alleen deze week tonen Copyright &copy; 2008-%1 Graeme Gott Copyright &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Uitgebracht onder de voorwaarden van de <a href=%1>GPL 3</a>-licentie Session conflicts with other sessions. De sessie botst met andere sessies. &Restore He&rstellen Unable to read time data. De tijdgegevens kunnen niet worden uitgelezen. Untitled Naamloos Unable to write time data. De tijdgegevens kunnen niet worden weggeschreven. There are timers running. Stop timers and quit? Er zijn nog lopende tijdklokken. Wilt u ze stopzetten en afsluiten? About Over A program to help track spent time Een programma dat doorgebrachte tijd bijhoudt Question Vraag &Create Report... Rapport &opstellen… View R&eports Rapport&en bekijken Cancel this session? Wilt u deze sessie afbreken? Add Project Project toevoegen Enter project name: Voer de projectnaam in: Error Foutmelding Unable to create time data location. De tijdgegevenslocatie kan niet worden aangemaakt. Unable to move time data location. De tijdgegevenslocatie kan niet worden verplaatst. A project with that name already exists. Er is al een project met deze naam. Remove selected project? Wilt u het geselecteerde project verwijderen? %n timer(s) running %n lopende tijdklok %n lopende tijdklokken Kapow Punch Clock Kapow-prikklok &Close to Tray &Sluiten naar systeemvak Re&move Report Rapport ver&wijderen &Start Minimized Geminimaliseerd op&starten Stop All Alles stopzetten Stop all timers? Wilt u alle tijdklokken stopzetten? &Move To... Verplaatsen &naar… Remove selected session(s)? Wilt u de geselecteerde sessie verwijderen? Wilt u de geselecteerde sessies verwijderen? Move Session(s) Sessie verplaatsen Sessies verplaatsen Move Verplaatsen Could not move session(s) because of conflicts. De sessies kan wegens conflicten niet worden verplaatst. De sessies kunnen wegens conflicten niet worden verplaatst. main Punch clock program Prikklokprogramma Store settings as INI format in specified file. Sla de instellingen op in het opgegeven ini-bestand. file bestand Do not create automatic backups of time data. Maak geen automatische back-ups van tijdgegevens. The time data file to use. Het te gebruiken tijdgegevensbestand. Start minimized in system tray. Start Kapow geminimaliseerd in het systeemvak. gottcode-kapow-350ecea/translations/kapow_no.ts000066400000000000000000000400261514263554100220460ustar00rootroot00000000000000 LocaleDialog Select application language: Velg programspråk <System Language> <Samme som System Språk> Note Notat Please restart this application for the change in language to take effect. Restart programmet for å aktivere endret språkvalg Report Time Sheet Report Timeliste Rapport Name: Navn: Company: Firma: Address: Adresse: Phone: Telefon: Fax: Faks: Email: Epost: Website: Nettside: N/A Ikke tilgjengelig Prepend currency symbol Valuta prefiks Hourly rate: Timepris: Tax rate: MVA: Currency symbol: Valutasymbol: Contact Information Kontakt informasjon Data Info Preview Forhåndsvis Export Eksporter Print Skriv ut Web Page (*.html *.htm) Webside (*html *.htm) iCalendar (*.ics) iKalender (*ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Eksporter rapport View Reports Se rapporter Create Report Lag rapport Phone: %1 Telefon: %1 Fax: %1 Faks: %1 Hours Timer Subtotal Totalsum Taxes MVA Total Totalt Remove Question Spørsmål Remove newest report? Session %n hour(s) %n time %n time %L1 hours %L1 timer SessionDelegate Error Feil Session conflicts with other sessions. SessionDialog Add Session Legg til oppgave Date: Dato: Start: Start: Stop: Stopp: Task: Oppgave: Edit Session Rediger oppgave SessionModel Total Totalt Date Start Start Stop Stopp Task Hours Timer Daily Weekly Monthly Report Window 00:00:00 00:00:00 Start Start Stop Stopp Cancel Avbryt &Minimize &Project &Prosjekt &Add &Legg til Ctrl+Shift+N Ctrl+Shift+N &Remove &Fjern Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &Avslutt Ctrl+Q Ctrl+Q &Session &Oppgave &Edit &Rediger Ctrl+Delete Ctrl+Delete S&ettings I&nnstillinger Columns Kolonner &Decimal Totals &antall desimaler &Inline Editing &Direkte redigering Application &Language... Program &Språk... &Help &Hjelp &About &Om About &Qt Om &Qt Project Prosjekt Timer Tidtaker Show all Vis alle Show only unbilled Vis bare ubelastete Show only this year Vis kun fra i år Show only this month Vis bare denne måneden Show only this week Vis kun denne uken Copyright &copy; 2008-%1 Graeme Gott Copyright &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Utgitt med <a href=%1>GPL 3</a> lisensen Session conflicts with other sessions. &Restore Unable to read time data. Finner ikke tidspunkt Untitled Uten tittel Unable to write time data. Kan ikke føre tidspunkt There are timers running. Stop timers and quit? Du har tidsmålere i gang. Vil du stanse og Avslutte? About Om A program to help track spent time Et program som hjelper å logge tidsforbruk Question Spørsmål &Create Report... &Lag rapport View R&eports Se r&apporter Cancel this session? Avbryte oppgaven? Add Project Legg til Prosjekt Enter project name: Skriv inn prosjektnavn: Error Feil Unable to create time data location. Kan ikke opprette lagringssted Unable to move time data location. Kan ikke flytte lagringssted A project with that name already exists. Du har allerede et prosjekt med det navnet. Remove selected project? Fjerne valgte prosjekt? %n timer(s) running %n tidsmåler kjører %n tidsmålere kjører Kapow Punch Clock Kapow Stemplingsur &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Store settings as INI format in specified file. file Do not create automatic backups of time data. The time data file to use. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_pl.ts000066400000000000000000000413471514263554100220540ustar00rootroot00000000000000 LocaleDialog Select application language: Wybierz język programu: <System Language> <Język systemowy> Note Uwaga Please restart this application for the change in language to take effect. Proszę ponownie uruchomić ten program, aby zastosować zmianę języka. Report Time Sheet Report Raport czasu pracy Name: Imię: Company: Firma: Address: Adres: Phone: Telefon: Fax: Fax: Email: Email: Website: Strona internetowa: N/A brak Prepend currency symbol Dołącz symbol waluty Hourly rate: Stawka godzinowa: Tax rate: Stawka podatkowa: Currency symbol: Symbol waluty: Contact Information Informacje kontaktowe Data Dane czasu pracy Preview Podgląd Export Eksportuj Print Wydrukuj Web Page (*.html *.htm) Strona internetowa (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Eksportuj raport View Reports Pokaż raporty Create Report Utwórz raport Phone: %1 Telefon: %1 Fax: %1 Fax: %1 Hours Godziny Subtotal Podsuma Taxes Podatki Total Suma Remove Question Pytanie Remove newest report? Session %n hour(s) %n godzina %n godziny %n godzin %n godzin %L1 hours %L1 godziny SessionDelegate Error Błąd Session conflicts with other sessions. Konflikt sesji z innych sesjami. SessionDialog Add Session Dodaj sesję Date: Data: Start: Początek: Stop: Koniec: Task: Zadanie: Edit Session Edytuj sesję SessionModel Total Suma Date Data Start Początek Stop Koniec Task Zadanie Hours Godziny Daily Codziennie Weekly Cotygodniowo Monthly Miesięcznie Report Raport Window 00:00:00 00:00:00 Start Początek Stop Koniec Cancel Anuluj &Minimize &Minimalizuj &Project &Projekt &Add &Dodaj Ctrl+Shift+N Ctrl+Shift+N &Remove &Usuń Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &Zakończ Ctrl+Q Ctrl+Q &Session &Sesja &Edit &Edytuj Ctrl+Delete Ctrl+Delete S&ettings Us&tawienia Columns Kolumny &Decimal Totals Wyświetlacz &czasu dziesiętnego &Inline Editing &bezpośrednia edycja wartości Application &Language... &Język programu... &Help &Pomoc &About &O About &Qt O &Qt Project Projekt Timer Czasomierz Show all Pokaż wszystko Show only unbilled Pokaż tylko nierozliczone Show only this year Pokaż tylko w tym roku Show only this month Pokaż tylko tym miesiącu Show only this week Pokaż tylko w tym tygodniu Copyright &copy; 2008-%1 Graeme Gott Prawo autorskie &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Wydano na licencji <a href=%1>GPL 3</a> Session conflicts with other sessions. Konflikt sesji z innych sesjami. &Restore &Przywróć Unable to read time data. Nie można odczytać danych czasowych. Untitled Bez tytułu Unable to write time data. Nie można zapisać danych czasowych. There are timers running. Stop timers and quit? Jeszcze są uruchomione czasomierze. Czy zatrzymać je i zakończyć program? About O A program to help track spent time Program do rejestracji czasu spędzonego przy pracy na komputerze. Question Pytanie &Create Report... &Utwórz raport... View R&eports Pokaż &raporty Cancel this session? Anulować tę sesję? Add Project Dodaj projekt Enter project name: Podaj nazwę projektu: Error Błąd Unable to create time data location. Nie można utworzyć lokalizacji danych czasowych. Unable to move time data location. Nie można przenieść lokalizacji danych czasowych. A project with that name already exists. Projekt o tej nazwie już istnieje. Remove selected project? Czy usunąć wybrany projekt? %n timer(s) running %n uruchomiony czasomierz %n uruchomione czasomierze %n uruchomionych czasomierzy %n uruchomionych czasomierzy Kapow Punch Clock Rejestracja czasu pracy Kapow &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Program rejestracji czasu pracy Store settings as INI format in specified file. Zapisz ustawienia w formacie INI w określonym pliku. file plik Do not create automatic backups of time data. Nie twórz automatycznych kopii zapasowych danych czasu. The time data file to use. Używany plik danych czasu. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_pt.ts000066400000000000000000000411621514263554100220570ustar00rootroot00000000000000 LocaleDialog Select application language: Selecione o idioma da aplicação: <System Language> <Idioma do Sistema> Note Nota Please restart this application for the change in language to take effect. Por favor reinicie esta aplicação para que a alteração do idioma surta efeito. Report Time Sheet Report Relatório de Horas de Trabalho Name: Nome: Company: Empresa: Address: Endereço: Phone: Telefone: Fax: Fax: Email: Email: Website: Website: N/A N/A Prepend currency symbol Símbolo de moeda à frente do valor Hourly rate: Preço por hora: Tax rate: Taxa de imposto: Currency symbol: Símbolo de moeda: Contact Information Informação de Contacto Data Dados Preview Pré-visualizar Export Exportar Print Imprimir Web Page (*.html *.htm) Página Web (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Exportar Relatório View Reports Ver Relatórios Create Report Criar Relatório Phone: %1 Telefone: %1 Fax: %1 Fax: %1 Hours Horas Subtotal Subtotal Taxes Impostos Total Total Remove Remover Question Questão Remove newest report? Remover o relatório mais recente? Session %n hour(s) %n hora %n houras %n horas %L1 hours %L1 horas SessionDelegate Error Erro Session conflicts with other sessions. A sessão está em conflito com outras sessões. SessionDialog Add Session Adicionar Sessão Date: Data: Start: Iniciar: Stop: Parar: Task: Tarefa: Edit Session Editar Sessão SessionModel Total Total Date Data Start Iniciar Stop Parar Task Tarefa Hours Horas Daily Diariamente Weekly Semanalmente Monthly Mensalmente Report Relatório Window 00:00:00 00:00:00 Start Iniciar Stop Parar Cancel Cancelar &Minimize &Minimizar &Project &Projecto &Add &Adicionar Ctrl+Shift+N Ctrl+Shift+N &Remove &Remover Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &Sair Ctrl+Q Ctrl+S &Session &Sessão &Edit &Editar Ctrl+Delete Ctrl+Delete S&ettings &Configurações Columns Colunas &Decimal Totals Totais no Formato &Decimal &Inline Editing &Edição Directa na Tabela Application &Language... &Idioma da Aplicação... &Help &Ajuda &About &Sobre About &Qt Sobre o &Qt Project Projecto Timer Contador Show all Mostrar tudo Show only unbilled Mostrar apenas por facturar Show only this year Mostrar apenas este ano Show only this month Mostrar apenas este mês Show only this week Mostrar apenas esta semana Copyright &copy; 2008-%1 Graeme Gott Direitos de Autor &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Lançado sob a licença <a href=%1>GPL 3</a> Session conflicts with other sessions. A sessão está em conflito com outras sessões. &Restore &Restaurar Unable to read time data. Não foi possível ler os dados de tempo. Untitled Sem título Unable to write time data. Não foi possível gravar os dados de tempo. There are timers running. Stop timers and quit? Há contadores a decorrer. Parar contadores e sair? About Sobre A program to help track spent time Um programa para ajudar a rastrear o tempo utilizado Question Questão &Create Report... &Criar Relatório... View R&eports Ver R&elatórios Cancel this session? Cancelar esta sessão? Add Project Adicionar Projeto Enter project name: Introduza o nome do projeto: Error Erro Unable to create time data location. Não foi possível criar a localização dos dados de tempo. Unable to move time data location. Não foi possível mover a localização dos dados de tempo. A project with that name already exists. Já existe um projecto com esse nome. Remove selected project? Remover o projecto selecionado? %n timer(s) running %n contador a decorrer %n contadores a decorrer %n contadores a decorrer Kapow Punch Clock Kapow Punch Clock &Close to Tray Fe&char para a bandeja Re&move Report Re&mover Relatório &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Programa de relógio de ponto Store settings as INI format in specified file. Armazenar as configurações no formato INI no ficheiro especificado. file ficheiro Do not create automatic backups of time data. Não criar cópias de segurança automáticas de dados de tempo. The time data file to use. Ficheiro de dados de tempo a utilizar. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_pt_BR.ts000066400000000000000000000410741514263554100224440ustar00rootroot00000000000000 LocaleDialog Select application language: Selecione o idioma do aplicativo: <System Language> <idioma do sistema> Note Nota Please restart this application for the change in language to take effect. Por favor, reinicie este aplicativo para que a alteração do idioma tenha efeito. Report Time Sheet Report Relatório de ponto Name: Nome: Company: Empresa: Address: Endereço: Phone: Telefone: Fax: Fax: Email: E-mail: Website: Site: N/A N/D Prepend currency symbol Preceder símbolo de moeda Hourly rate: Taxa de horas: Tax rate: Taxa de imposto: Currency symbol: Símbolo de moeda: Contact Information Informação de contato Data Dados Preview Pré-visualizar Export Exportar Print Imprimir Web Page (*.html *.htm) Página web (*.html, *htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Exportar relatório View Reports Ver relatórios Create Report Criar relatórios Phone: %1 Telefone: %1 Fax: %1 Fax: %1 Hours Horas Subtotal Subtotal Taxes Impostos Total Total Remove Question Pergunta Remove newest report? Session %n hour(s) %n hora %n horas %n horas %L1 hours %L1 horas SessionDelegate Error Erro Session conflicts with other sessions. SessionDialog Add Session Adicionar sessão Date: Data: Start: Início: Stop: Fim: Task: Tarefa: Edit Session Editar sessão SessionModel Total Total Date Start Iniciar Stop Parar Task Hours Horas Daily Weekly Monthly Report Window 00:00:00 00:00:00 Start Iniciar Stop Parar Cancel Cancelar &Minimize &Project &Projeto &Add &Adicionar Ctrl+Shift+N Ctrl+Shift+N &Remove &Remover Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &Sair Ctrl+Q Ctrl+Q &Session &Sessão &Edit &Editar Ctrl+Delete Ctrl+Delete S&ettings &Configurações Columns Colunas &Decimal Totals Total de &decinais &Inline Editing Edição em linha Application &Language... Idioma do ap&licativo... &Help &Ajuda &About &Sobre About &Qt Sobre &Qt Project Projeto Timer Cronômetro Show all Mostrar todos Show only unbilled Mostrar somente não faturados Show only this year Mostrar somente este ano Show only this month Mostrar somente este mês Show only this week Mostrar somente esta semana Copyright &copy; 2008-%1 Graeme Gott Copyright &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Disponibilizado sob a licença <a href=%1>GPL 3</a> Session conflicts with other sessions. &Restore Unable to read time data. Não foi possível ler dados do horário. Untitled Sem título Unable to write time data. Não foi possível escrever dados do horário. There are timers running. Stop timers and quit? Há cronômetros em execução. Parar cronômetros e sair? About Sobre A program to help track spent time Um programa para ajudar a registrar o tempo despendido Question Pergunta &Create Report... &Criar relatório... View R&eports Ver R&elatórios Cancel this session? Cancelar esta sessão? Add Project Adicionar projeto Enter project name: Informe o nome do projeto: Error Erro Unable to create time data location. Não foi possível criar a localização dos dados do horário. Unable to move time data location. Não foi possível mover a localização dos dados do horário. A project with that name already exists. Um projeto com esse nome já existe. Remove selected project? Remover o projeto selecionado? %n timer(s) running %n cronômetro em execução %n cronômetros em execução %n cronômetros em execução Kapow Punch Clock Relógio de Ponto Kapow &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Store settings as INI format in specified file. file Do not create automatic backups of time data. The time data file to use. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_ro.ts000066400000000000000000000407101514263554100220520ustar00rootroot00000000000000 LocaleDialog Select application language: Selectaţi limba aplicaţiei <System Language> <Limbaj sistem> Note Notă Please restart this application for the change in language to take effect. Vă rugăm reporniţi această aplicaţie pentru ca schimbarea limbii să aibă efect. Report Time Sheet Report Raport pontaj Name: Nume: Company: Companie: Address: Adresă: Phone: Telefon: Fax: Fax: Email: e-mail: Website: Site web: N/A Indisponibil Prepend currency symbol Prefixul simbolului monetar Hourly rate: Rată orară: Tax rate: Rată de impozitare: Currency symbol: Simbol monedă: Contact Information Informaţii de contact Data Date Preview Previzualizare Export Exportare Print Imprimare Web Page (*.html *.htm) Pagină web (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Raport exportare View Reports Vizualizare rapoarte Create Report Creare raport Phone: %1 Telefon: %1 Fax: %1 Fax: %1 Hours Ore Subtotal Subtotal Taxes Taxe Total Total Remove Înlătură Question Întrebare Remove newest report? Înlătură raportul recent? Session %n hour(s) %n oră %n ore %n ore %L1 hours %L1 ore SessionDelegate Error Eroare Session conflicts with other sessions. Sesiunea este în conflict cu alte sesiuni. SessionDialog Add Session Adăugare sesiune Date: Dată: Start: Start: Stop: Stop: Task: Sarcină: Edit Session Editare sesiune SessionModel Total Total Date Dată Start Start Stop Stop Task Sarcină Hours Ore Daily Zilnic Weekly Săptămînal Monthly Lunar Report Raport Window 00:00:00 00:00:00 Start Start Stop Stop Cancel Anulare &Minimize &Minimizează &Project &Proiect &Add &Adăugare Ctrl+Shift+N Ctrl+Shift+N &Remove E&liminare Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &Ieşire Ctrl+Q Ctrl+Q &Session &Sesiune &Edit &Editare Ctrl+Delete Ctrl+Delete S&ettings S&etări Columns Coloane &Decimal Totals Total &zecimale &Inline Editing Editare în linie Application &Language... &Limbă aplicaţie... &Help &Ajutor &About &Despre About &Qt Despre &Qt Project Proiect Timer Cronometru Show all Arată toate Show only unbilled Arată doar nefacturate Show only this year Arată doar acest an Show only this month Arată doar luna aceasta Show only this week Arată daor luna aceasta Copyright &copy; 2008-%1 Graeme Gott Toate drepturile rezervate &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Lansat sub licenţă <a href=%1>GPL 3</a> Session conflicts with other sessions. Sesiunea este în conflict cu alte sesiuni. &Restore &Restaurează Unable to read time data. Nu se pot citit datele de timp. Untitled Fără titlu Unable to write time data. Nu se pot scrie datele de timp. There are timers running. Stop timers and quit? Există cronometre care rulează. Opriţi cronometrele şi ieşiţi? About Despre A program to help track spent time Un program pentru a vă ajuta să urmăriţi timpul petrecut Question Întrebare &Create Report... &Creare raport... View R&eports Vizualizare rapoarte Cancel this session? Anulează această sesiune? Add Project Adăugare proiect Enter project name: Introduceţi numele proiectului: Error Eroare Unable to create time data location. Nu se poate crea locaţia datelor de timp. Unable to move time data location. Nu se poate muta locaţia datelor de timp. A project with that name already exists. Un proiect cu acel nume deja există. Remove selected project? Eliminaţi proiectul selectat? %n timer(s) running %n cronometru rulează %n cronometre rulează %n cronometre rulează Kapow Punch Clock Kapow Punch Clock &Close to Tray În&chide în bară Re&move Report Înlătură raport &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Program ceas Store settings as INI format in specified file. Stochează setările în format INI în fişierul specificat. file fişier Do not create automatic backups of time data. Nu creează automat copii de siguranţă a datelor timpului. The time data file to use. Fişier date timp de folosit. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_ru.ts000066400000000000000000000437361514263554100220730ustar00rootroot00000000000000 LocaleDialog Select application language: Выберите язык приложения: <System Language> <Язык системы> Note Заметка Please restart this application for the change in language to take effect. Пожалуйста перезапустите приложение, чтобы изменения вступили в силу. Report Time Sheet Report Отчет о рабочем времени Name: Имя: Company: Компания: Address: Адрес: Phone: Телефон: Fax: Факс: Email: Электронная почта: Website: Веб-сайт: N/A Н/Д Prepend currency symbol Добавлять символ валюты Hourly rate: Почасовая ставка: Tax rate: Налоговая ставка: Currency symbol: Символ валюты: Contact Information Контактная информация Data Данные Preview Просмотр Export Экспорт Print Печать Web Page (*.html *.htm) Вэб-страница (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Экспорт отчета View Reports Просмотр отчетов Create Report Создать отчет Phone: %1 Телефон: %1 Fax: %1 Факс: %1 Hours Часы Subtotal Промежуточный итог Taxes Налоги Total Итого Remove Question Вопрос Remove newest report? Session %n hour(s) %n час %т часов %n часов %n часов %L1 hours %L1 часов SessionDelegate Error Ошибка Session conflicts with other sessions. Сессия конфликтует с другими сеансами. SessionDialog Add Session Создать сессию Date: Дата: Start: Начало: Stop: Конец: Task: Задача: Edit Session Правка сессии SessionModel Total Всего Date Дата Start Начать Stop Остановить Task Задача Hours Часы Daily Ежедневно Weekly Еженедельно Monthly Ежемесячно Report Отчёт Window 00:00:00 00:00:00 Start Старт Stop Стоп Cancel Отмена &Minimize &Свернуть &Project &Проект &Add &Создать Ctrl+Shift+N Ctrl+Shift+N &Remove &Удалить Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &Выход Ctrl+Q Ctrl+Й &Session &Сессия &Edit &Правка Ctrl+Delete Ctrl+Delete S&ettings &Настройки Columns Столбцы &Decimal Totals &Десятичные итоги &Inline Editing &Правка в строке Application &Language... &Язык приложения... &Help По&мощь &About &О программе About &Qt О &библиотеке Qt Project Проект Timer Таймер Show all Показать все Show only unbilled Показать только неоплаченные Show only this year Показать за этот год Show only this month Показать за этот месяц Show only this week Показать за эту неделю Copyright &copy; 2008-%1 Graeme Gott Защищено авторским правом &copy; 2008-%1 Грэм Готт Released under the <a href=%1>GPL 3</a> license Распространяется под лицензией <a href=%1>GPL 3</a> Session conflicts with other sessions. Сессия конфликтует с другими сеансами. &Restore &Развернуть Unable to read time data. Невозможно прочитать данные. Untitled Без имени Unable to write time data. Невозможно записать данные. There are timers running. Stop timers and quit? Есть работающие таймеры. Остановить их и выйти? About О программе A program to help track spent time Программа для учета потраченного времени Question Вопрос &Create Report... &Создать отчет View R&eports &Просмотр отчетов Cancel this session? Отменить сессию? Add Project Создать проект Enter project name: Имя проекта: Error Ошибка Unable to create time data location. Невозможно создать временной интервал. Unable to move time data location. Невозможно переместить временной интервал. A project with that name already exists. Проект с таким именем уже существует. Remove selected project? Удалить выбранный проект? %n timer(s) running %n таймер работает %n таймеров работает %n таймеров работает %n таймеров работает Kapow Punch Clock Kapow Punch Clock &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Програма по учёту времени Store settings as INI format in specified file. Храните настройки в формате INI в указанном файле. file файл Do not create automatic backups of time data. Не создавайте автоматических бэкапов временных данных. The time data file to use. Используемый файл данных времени. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_sv.ts000066400000000000000000000400251514263554100220610ustar00rootroot00000000000000 LocaleDialog Select application language: Välj programmets språk: <System Language> <System Language> Note Anteckning Please restart this application for the change in language to take effect. Starta om detta program för att språkändringen ska verkställas. Report Time Sheet Report Tidrapport Name: Namn: Company: Företag: Address: Adress: Phone: Telefon: Fax: Fax: Email: E-post: Website: Hemsida: N/A N/A Prepend currency symbol Inledande valutasymbol Hourly rate: Timtaxa: Tax rate: Momssats: Currency symbol: Valutasymbol: Contact Information Kontaktuppgifter Data Data Preview Förhandsgranskning Export Exportera Print Skriv ut Web Page (*.html *.htm) Hemsida (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Exportera rapport View Reports Visa rapport Create Report Skapa rapport Phone: %1 Telefon: %1 Fax: %1 Fax: %1 Hours Timmar Subtotal Delsumma Taxes Moms Total Summa Remove Question Fråga Remove newest report? Session %n hour(s) %n timma %n timmar %L1 hours %L1 timmar SessionDelegate Error Fel Session conflicts with other sessions. Sessionskonflikt med andra sessioner. SessionDialog Add Session Lägg till session Date: Datum: Start: Start: Stop: Stopp: Task: Uppgift: Edit Session Redigera session SessionModel Total Summa Date Datum Start Start Stop Stopp Task Uppgift Hours Timmar Daily Dagligen Weekly Veckovis Monthly Månadsvis Report Rapport Window 00:00:00 00:00:00 Start Start Stop Stopp Cancel Avbryt &Minimize &Minimera &Project &Projekt &Add &Lägg till Ctrl+Shift+N Ctrl+Shift+L &Remove &Ta bort Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &Avsluta Ctrl+Q Ctrl+A &Session &Session &Edit &Redigera Ctrl+Delete Ctrl+Delete S&ettings Inst&ällningar Columns Kolumner &Decimal Totals Summa i &decimaltal &Inline Editing Radred&igering Application &Language... Programsprå&k &Help &Hjälp &About &Om About &Qt Om &Qt Project Projekt Timer Timer Show all Visa alla Show only unbilled Visa endast ofakturerade Show only this year Visa endast detta året Show only this month Visa endast denna månaden Show only this week Visa endast denna veckan Copyright &copy; 2008-%1 Graeme Gott Copyright &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Utgiven under <a href=%1>GPL 3</a> licens Session conflicts with other sessions. Sessionskonflikt med andra sessioner. &Restore &Återställ Unable to read time data. Kan inte läsa tidsdata. Untitled Titel saknas Unable to write time data. Kan inte skriva tidsdata. There are timers running. Stop timers and quit? Timers är igång. Vill du stoppa timers och avsluta? About Om A program to help track spent time Ett program för att hjälpa till att spåra spenderad tid Question Fråga &Create Report... &Skapa rapport... View R&eports &Visa rapporter Cancel this session? Avbryta denna session? Add Project Lägg till projekt Enter project name: Ange projektnamn: Error Fel Unable to create time data location. Kan inte skapa plats för tidsdata. Unable to move time data location. Kan inte flytta plats för tidsdata. A project with that name already exists. Ett projekt med det namnet finns redan. Remove selected project? Ta bort valt projekt? %n timer(s) running %n timer igång %n timers igång Kapow Punch Clock Kapow Stämpelklocka &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Stämpelklocksprogram Store settings as INI format in specified file. Spara inställningar som INI-format i angiven fil. file fil Do not create automatic backups of time data. Skapa inte automatisk säkerhetskopiering av tidsdata. The time data file to use. Tidsdatafil att använda. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_tr.ts000066400000000000000000000403471514263554100220650ustar00rootroot00000000000000 LocaleDialog Select application language: Uygulama dilini seçin: <System Language> <Sistem Dili> Note Note Please restart this application for the change in language to take effect. Dil değişikliğinin etkin olması için lütfen bu uygulamayı yeniden başlatın. Report Time Sheet Report Saat Sayfa Raporu Name: İsim: Company: Şirket Address: Adres: Phone: Telefone: Fax: Faks: Email: E-posta: Website: İnternet Sitesi: N/A N/A Prepend currency symbol Para birimi simgesini baş tarafa al Hourly rate: Saatlik ücret: Tax rate: Vergi oranı: Currency symbol: Para birimi simgesi: Contact Information İletişim Bilgileri Data Veri Preview Önizleme Export Ver Print Yazdır Web Page (*.html *.htm) Web Sayfası (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Raporu Ver View Reports Raporları Gör Create Report Rapor Oluştur Phone: %1 Telefone: %1 Fax: %1 Faks: %1 Hours Saat Subtotal Ara Toplam Taxes Vergiler Total Toplam Remove Kaldır Question Soru Remove newest report? Yeni raporlar kaldırılsın mı? Session %n hour(s) %n saat %n saat %L1 hours %L1 saat SessionDelegate Error Hata Session conflicts with other sessions. Oturum başka bir oturumla çakışıyor. SessionDialog Add Session Oturum Ekle Date: Tarih: Start: Başlama: Stop: Bitiş: Task: Görev: Edit Session Oturumu düzenle SessionModel Total Toplam Date Tarih Start Başlama Stop Bitiş Task Görev Hours Saat Daily Günlük Weekly Haftalık Monthly Aylık Report Rapor Window 00:00:00 00:00:00 Start Başlat Stop Bitir Cancel İptal Et &Minimize &Küçült &Project &Proje &Add &Ekle Ctrl+Shift+N Ctrl+Shift+N &Remove &Kaldır Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit &Çıkış Ctrl+Q Ctrl+Q &Session &Oturum &Edit &Düzenle Ctrl+Delete Ctrl+Delete S&ettings &Ayarlar Columns Sütunlar &Decimal Totals &Ondalık Toplamlar &Inline Editing &Üzerinde Düzenleme Application &Language... &Uygulama Dili... &Help &Yardım &About &Hakkında About &Qt &Qt Hakkında Project Proje Timer Zamanlayıcı Show all Tümünü göster Show only unbilled Yalnızca faturalandırılmamışları göster Show only this year Yalnızca bu yılı göster Show only this month Yalnızca bu ayı göser Show only this week Yalnızca bu haftayı göster Copyright &copy; 2008-%1 Graeme Gott Telif hakları saklıdır &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license <a href=%1>GPL 3</a> lisansı altında yayınlanmıştır Session conflicts with other sessions. Oturum başka oturumlarla çakışıyor. &Restore &Geri Yükle Unable to read time data. Zaman verikeri okunamıyor. Untitled Başlıksız Unable to write time data. Zaman verileri yazlıamıyor. There are timers running. Stop timers and quit? Çalışan zamanlayıcılar var. Zamanlayıcıları durdurup çıkılsın mı? About Hakkında A program to help track spent time Harcanan zamanı izleyen bir program Question Soru &Create Report... Rapor &Oluştur... View R&eports Raporları &Gör Cancel this session? Bu oturum iptal edilsin mi? Add Project Proje Ekle Enter project name: Proje ismini girin: Error Hata Unable to create time data location. Zaman verileri konumu oluşturulamıyor. Unable to move time data location. Zaman verileri konumu taşınamıyor. A project with that name already exists. Zaten bu isimde bir proje var. Remove selected project? Seçili proje kaldırılsın mı? %n timer(s) running %n zamanlayıcı çalışıyor %n zamanlayıcı çalışıyor Kapow Punch Clock Kapow Punch Saati &Close to Tray Sistem Çekmecesine &Kapat Re&move Report Raporu &Kaldır &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Store settings as INI format in specified file. Ayarları belirtilen dosyada INI biçiminde sakla. file dosya Do not create automatic backups of time data. Zaman verilerinin otomatik yedeklerini oluşturma. The time data file to use. Kullanılacak zaman veri dosyası. Start minimized in system tray. gottcode-kapow-350ecea/translations/kapow_uk.ts000066400000000000000000000437451514263554100220640ustar00rootroot00000000000000 LocaleDialog Select application language: Вибрати мову програми: <System Language> <Системна мова> Note Примітка Please restart this application for the change in language to take effect. Перезапустіть програму, щоб нова мова вступила в дію. Report Time Sheet Report Облік робочого часу Name: Ім'я: Company: Компанія: Address: Адреса: Phone: Телефон: Fax: Факс: Email: Електронна пошта: Website: Веб-сайт: N/A Не доступно Prepend currency symbol Додавати символ валюти Hourly rate: Погодинна оплата: Tax rate: Податкова ставка: Currency symbol: Символ валюти: Contact Information Контактні дані Data Дані Preview Огляд Export Експорт Print Друк Web Page (*.html *.htm) Веб сторінка (*.html *.htm) iCalendar (*.ics) iCalendar (*.ics) Outlook CSV (*.csv) Outlook CSV (*.csv) Export Report Експортувати звіт View Reports Переглянути звіти Create Report Створити звіт Phone: %1 Телефон: %1 Fax: %1 Факс: %1 Hours Час Subtotal Проміжний підсумок Taxes Податки Total Загалом Remove Question Запитання Remove newest report? Session %n hour(s) %n година %n години %n годин %n годин %L1 hours %L1 год. SessionDelegate Error Помилка Session conflicts with other sessions. Сесія конфліктує з іншими сесіями. SessionDialog Add Session Додати сеанс Date: Дата: Start: Початок: Stop: Зупинка: Task: Завдання: Edit Session Змінити сеанс SessionModel Total Всього Date Дата Start Початок Stop Зупинка Task Завдання Hours Час Daily Щодня Weekly Щотижня Monthly Щомісяця Report Звіт Window 00:00:00 00:00:00 Start Початок Stop Зупинка Cancel Скасувати &Minimize &Мінімізувати &Project &Проект &Add &Додати Ctrl+Shift+N Ctrl+Shift+N &Remove &Вилучити Ctrl+Shift+Delete Ctrl+Shift+Delete &Quit В&ийти Ctrl+Q Ctrl+Q &Session &Сеанс &Edit З&міни Ctrl+Delete Ctrl+Delete S&ettings П&араметри Columns Стовпчики &Decimal Totals Д&есятичний підсумок &Inline Editing Редагування в &один рядок Application &Language... &Мова програми... &Help &Довідка &About &Про програму About &Qt Про &Qt Project Проект Timer Таймер Show all Показати все Show only unbilled Показувати лише невідфактуровані Show only this year Показувати лише за цей рік Show only this month Показувати лише за цей місяць Show only this week Показувати лише за цей тиждень Copyright &copy; 2008-%1 Graeme Gott Copyright &copy; 2008-%1 Graeme Gott Released under the <a href=%1>GPL 3</a> license Випущено за ліцензією <a href=%1>GPL 3</a> Session conflicts with other sessions. Сесія конфліктує з іншими сесіями. &Restore &Відновити Unable to read time data. Неможливо прочитати дані про час. Untitled Без назви Unable to write time data. Неможливо записати дані про час. There are timers running. Stop timers and quit? Таймери працюють. Зупинити їх і вийти? About Про A program to help track spent time Програма для відстежування витраченого часу Question Запитання &Create Report... &Створення звіту... View R&eports &Переглянути звіти Cancel this session? Скасувати цей сеанс? Add Project Додати проект Enter project name: Введіть назву проекту: Error Помилка Unable to create time data location. Не вдається створити розташування даних часу Unable to move time data location. Неможливо перемістити розташування даних часу. A project with that name already exists. Проект з такою назвою вже є. Remove selected project? Вилучити вибраний проект? %n timer(s) running Працює %n таймер Працюють %n таймери Працюють %n таймерів Працюють %n таймерів Kapow Punch Clock Kapow Punch Clock &Close to Tray Re&move Report &Start Minimized Stop All Stop all timers? &Move To... Remove selected session(s)? Move Session(s) Move Could not move session(s) because of conflicts. main Punch clock program Запустити годинник програми Store settings as INI format in specified file. Зберігайте налаштування в форматі INI у вказаному файлі. file файл Do not create automatic backups of time data. Не створювати автоматичні резервні копії даних часу. The time data file to use. Файл даних часу, який слід використовувати Start minimized in system tray. gottcode-kapow-350ecea/windows/000077500000000000000000000000001514263554100166305ustar00rootroot00000000000000gottcode-kapow-350ecea/windows/installer.nsi000066400000000000000000000163221514263554100213440ustar00rootroot00000000000000;-------------------------------- ;Definitions !define APPNAME "Kapow" !define VERSIONMAJOR 1 !define VERSIONMINOR 7 !define VERSIONPATCH 0 !define APPVERSION "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONPATCH}" !define ABOUTURL "https://gottcode.org/kapow/" ;-------------------------------- ;Includes !include "MUI2.nsh" !include "FileFunc.nsh" !include "TextFunc.nsh" ;-------------------------------- ;General ;Use highest compression SetCompressor /SOLID /FINAL lzma ;Name and file Name "${APPNAME}" OutFile "${APPNAME}_${APPVERSION}.exe" ;Default installation folder InstallDir "$PROGRAMFILES64\${APPNAME}" InstallDirRegKey HKLM "Software\${APPNAME}" "" ;Request application privileges for Windows Vista RequestExecutionLevel admin ;-------------------------------- ;Variables Var StartMenuFolder ;-------------------------------- ;Interface Settings !define MUI_ICON "..\icons\kapow.ico" !define MUI_UNICON "..\icons\kapow.ico" !define MUI_ABORTWARNING !define MUI_LANGDLL_ALLLANGUAGES ;-------------------------------- ;Language Selection Dialog Settings ;Remember the installer language !define MUI_LANGDLL_REGISTRY_ROOT "HKLM" !define MUI_LANGDLL_REGISTRY_KEY "Software\${APPNAME}" !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" ;-------------------------------- ;Start Menu Folder Page Settings !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\${APPNAME}" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" ;-------------------------------- ;Finish Page Settings !define MUI_FINISHPAGE_RUN "$INSTDIR\${APPNAME}.exe" !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\ReadMe.txt" ;-------------------------------- ;Pages !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "..\COPYING" !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ;-------------------------------- ;Languages !insertmacro MUI_LANGUAGE "English" ;first language is the default language !insertmacro MUI_LANGUAGE "French" !insertmacro MUI_LANGUAGE "German" !insertmacro MUI_LANGUAGE "Spanish" !insertmacro MUI_LANGUAGE "SpanishInternational" !insertmacro MUI_LANGUAGE "SimpChinese" !insertmacro MUI_LANGUAGE "TradChinese" !insertmacro MUI_LANGUAGE "Japanese" !insertmacro MUI_LANGUAGE "Korean" !insertmacro MUI_LANGUAGE "Italian" !insertmacro MUI_LANGUAGE "Dutch" !insertmacro MUI_LANGUAGE "Danish" !insertmacro MUI_LANGUAGE "Swedish" !insertmacro MUI_LANGUAGE "Norwegian" !insertmacro MUI_LANGUAGE "NorwegianNynorsk" !insertmacro MUI_LANGUAGE "Finnish" !insertmacro MUI_LANGUAGE "Greek" !insertmacro MUI_LANGUAGE "Russian" !insertmacro MUI_LANGUAGE "Portuguese" !insertmacro MUI_LANGUAGE "PortugueseBR" !insertmacro MUI_LANGUAGE "Polish" !insertmacro MUI_LANGUAGE "Ukrainian" !insertmacro MUI_LANGUAGE "Czech" !insertmacro MUI_LANGUAGE "Slovak" !insertmacro MUI_LANGUAGE "Croatian" !insertmacro MUI_LANGUAGE "Bulgarian" !insertmacro MUI_LANGUAGE "Hungarian" !insertmacro MUI_LANGUAGE "Thai" !insertmacro MUI_LANGUAGE "Romanian" !insertmacro MUI_LANGUAGE "Latvian" !insertmacro MUI_LANGUAGE "Macedonian" !insertmacro MUI_LANGUAGE "Estonian" !insertmacro MUI_LANGUAGE "Turkish" !insertmacro MUI_LANGUAGE "Lithuanian" !insertmacro MUI_LANGUAGE "Slovenian" !insertmacro MUI_LANGUAGE "Serbian" !insertmacro MUI_LANGUAGE "SerbianLatin" !insertmacro MUI_LANGUAGE "Arabic" !insertmacro MUI_LANGUAGE "Farsi" !insertmacro MUI_LANGUAGE "Hebrew" !insertmacro MUI_LANGUAGE "Indonesian" !insertmacro MUI_LANGUAGE "Mongolian" !insertmacro MUI_LANGUAGE "Luxembourgish" !insertmacro MUI_LANGUAGE "Albanian" !insertmacro MUI_LANGUAGE "Breton" !insertmacro MUI_LANGUAGE "Belarusian" !insertmacro MUI_LANGUAGE "Icelandic" !insertmacro MUI_LANGUAGE "Malay" !insertmacro MUI_LANGUAGE "Bosnian" !insertmacro MUI_LANGUAGE "Kurdish" !insertmacro MUI_LANGUAGE "Irish" !insertmacro MUI_LANGUAGE "Uzbek" !insertmacro MUI_LANGUAGE "Galician" !insertmacro MUI_LANGUAGE "Afrikaans" !insertmacro MUI_LANGUAGE "Catalan" !insertmacro MUI_LANGUAGE "Esperanto" !insertmacro MUI_LANGUAGE "Asturian" ;-------------------------------- ;Reserve Files !insertmacro MUI_RESERVEFILE_LANGDLL ;-------------------------------- ;Installer Functions Function .onInit !insertmacro MUI_LANGDLL_DISPLAY FunctionEnd ;-------------------------------- ;Installer Section Section "install" ;Remove previous installs !include removeprevious.nsh ;Copy files SetOutPath "$INSTDIR" File /r "..\${APPNAME}\*" ;Registry information for add/remove programs WriteRegStr HKLM "Software\${APPNAME}" "" "$INSTDIR" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayName" "${APPNAME}" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "Publisher" "Graeme Gott" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "InstallLocation" "$\"$INSTDIR$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayIcon" "$\"$INSTDIR\${APPNAME}.exe$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "URLInfoAbout" "$\"${ABOUTURL}$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayVersion" "${APPVERSION}" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "VersionMajor" ${VERSIONMAJOR} WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "VersionMinor" ${VERSIONMINOR} WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "NoModify" 1 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "NoRepair" 1 ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 IntFmt $0 "0x%08X" $0 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "EstimatedSize" "$0" ;Create uninstaller WriteUninstaller "$INSTDIR\Uninstall.exe" ;Create shortcut SetShellVarContext all !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateDirectory "$SMPROGRAMS\$StartMenuFolder" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\${APPNAME}.lnk" "$INSTDIR\${APPNAME}.exe" !insertmacro MUI_STARTMENU_WRITE_END SetShellVarContext current SectionEnd ;-------------------------------- ;Uninstaller Functions Function un.onInit !insertmacro MUI_UNGETLANGUAGE FunctionEnd ;-------------------------------- ;Uninstaller Section Section "Uninstall" ; Remove from registry DeleteRegKey HKLM "Software\${APPNAME}" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" ;Remove files !include files.nsh Delete "$INSTDIR\Uninstall.exe" ;Remove directories !include dirs.nsh RMDir "$INSTDIR" ;Remove shortcut SetShellVarContext all !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder Delete "$SMPROGRAMS\$StartMenuFolder\${APPNAME}.lnk" RMDir "$SMPROGRAMS\$StartMenuFolder" SetShellVarContext current SectionEnd gottcode-kapow-350ecea/windows/removeprevious.nsh000066400000000000000000000050501514263554100224340ustar00rootroot00000000000000Delete "$INSTDIR\bearer\qgenericbearer.dll" Delete "$INSTDIR\bearer\qnativewifibearer.dll" Delete "$INSTDIR\COPYING.txt" Delete "$INSTDIR\CREDITS.txt" Delete "$INSTDIR\libgcc_s_dw2-1.dll" Delete "$INSTDIR\mingwm10.dll" Delete "$INSTDIR\printsupport\windowsprintersupport.dll" Delete "$INSTDIR\Qt5Core.dll" Delete "$INSTDIR\Qt5Gui.dll" Delete "$INSTDIR\Qt5Network.dll" Delete "$INSTDIR\Qt5PrintSupport.dll" Delete "$INSTDIR\Qt5Widgets.dll" Delete "$INSTDIR\QtCore4.dll" Delete "$INSTDIR\QtGui4.dll" Delete "$INSTDIR\QtNetwork4.dll" Delete "$INSTDIR\QtXml4.dll" Delete "$INSTDIR\styles\qwindowsvistastyle.dll" Delete "$INSTDIR\translations\kapow_he.qm" Delete "$INSTDIR\translations\qtbase_bg.qm" Delete "$INSTDIR\translations\qtbase_ca.qm" Delete "$INSTDIR\translations\qtbase_cs.qm" Delete "$INSTDIR\translations\qtbase_da.qm" Delete "$INSTDIR\translations\qtbase_de.qm" Delete "$INSTDIR\translations\qtbase_en.qm" Delete "$INSTDIR\translations\qtbase_es.qm" Delete "$INSTDIR\translations\qtbase_fi.qm" Delete "$INSTDIR\translations\qtbase_fr.qm" Delete "$INSTDIR\translations\qtbase_gd.qm" Delete "$INSTDIR\translations\qtbase_he.qm" Delete "$INSTDIR\translations\qtbase_hu.qm" Delete "$INSTDIR\translations\qtbase_it.qm" Delete "$INSTDIR\translations\qtbase_ja.qm" Delete "$INSTDIR\translations\qtbase_ko.qm" Delete "$INSTDIR\translations\qtbase_lv.qm" Delete "$INSTDIR\translations\qtbase_pl.qm" Delete "$INSTDIR\translations\qtbase_ru.qm" Delete "$INSTDIR\translations\qtbase_sk.qm" Delete "$INSTDIR\translations\qtbase_sv.qm" Delete "$INSTDIR\translations\qtbase_uk.qm" Delete "$INSTDIR\translations\qt_gl.qm" Delete "$INSTDIR\translations\qt_help_cs.qm" Delete "$INSTDIR\translations\qt_help_da.qm" Delete "$INSTDIR\translations\qt_help_de.qm" Delete "$INSTDIR\translations\qt_help_en.qm" Delete "$INSTDIR\translations\qt_help_fr.qm" Delete "$INSTDIR\translations\qt_help_gl.qm" Delete "$INSTDIR\translations\qt_help_hu.qm" Delete "$INSTDIR\translations\qt_help_it.qm" Delete "$INSTDIR\translations\qt_help_ja.qm" Delete "$INSTDIR\translations\qt_help_ko.qm" Delete "$INSTDIR\translations\qt_help_pl.qm" Delete "$INSTDIR\translations\qt_help_ru.qm" Delete "$INSTDIR\translations\qt_help_sk.qm" Delete "$INSTDIR\translations\qt_help_sl.qm" Delete "$INSTDIR\translations\qt_help_uk.qm" Delete "$INSTDIR\translations\qt_help_zh_CN.qm" Delete "$INSTDIR\translations\qt_help_zh_TW.qm" Delete "$INSTDIR\translations\qt_lt.qm" Delete "$INSTDIR\translations\qt_pt.qm" Delete "$INSTDIR\translations\qt_sl.qm" Delete "$INSTDIR\translations\qt_sv.qm" RMDir "$INSTDIR\bearer" RMDir "$INSTDIR\printsupport" gottcode-kapow-350ecea/windows_deploy.bat000066400000000000000000000032561514263554100207020ustar00rootroot00000000000000@ECHO ON>..\kapow\windows\dirs.nsh @ECHO ON>..\kapow\windows\files.nsh @ECHO OFF SET SRCDIR=..\kapow SET APP=Kapow SET VERSION=1.7.0 ECHO Copying executable MKDIR %SRCDIR%\%APP% COPY %APP%.exe %SRCDIR%\%APP%\%APP%.exe >nul ECHO Copying translations SET TRANSLATIONS=%SRCDIR%\%APP%\translations MKDIR %TRANSLATIONS% COPY *.qm %TRANSLATIONS% >nul CD %SRCDIR% ECHO Copying Qt windeployqt.exe --verbose 0 --release --compiler-runtime^ --no-opengl-sw --no-system-dxc-compiler --no-system-d3d-compiler^ --no-svg^ --skip-plugin-types imageformats^ %APP%\%APP%.exe ECHO Creating ReadMe TYPE README >> %APP%\ReadMe.txt ECHO. >> %APP%\ReadMe.txt ECHO. >> %APP%\ReadMe.txt ECHO CREDITS >> %APP%\ReadMe.txt ECHO ======= >> %APP%\ReadMe.txt ECHO. >> %APP%\ReadMe.txt TYPE CREDITS >> %APP%\ReadMe.txt ECHO. >> %APP%\ReadMe.txt ECHO. >> %APP%\ReadMe.txt ECHO NEWS >> %APP%\ReadMe.txt ECHO ==== >> %APP%\ReadMe.txt ECHO. >> %APP%\ReadMe.txt TYPE ChangeLog >> %APP%\ReadMe.txt ECHO Creating installer CD %APP% SETLOCAL EnableDelayedExpansion SET "parentfolder=%__CD__%" FOR /R . %%F IN (*) DO ( SET "var=%%F" ECHO Delete "$INSTDIR\!var:%parentfolder%=!" >> ..\windows\files.nsh ) FOR /R /D %%F IN (*) DO ( TYPE ..\windows\dirs.nsh > temp.txt SET "var=%%F" ECHO RMDir "$INSTDIR\!var:%parentfolder%=!" > ..\windows\dirs.nsh TYPE temp.txt >> ..\windows\dirs.nsh ) DEL temp.txt ENDLOCAL CD .. makensis.exe /V0 windows\installer.nsi ECHO Making portable MKDIR %APP%\Data COPY COPYING %APP%\COPYING.txt >nul ECHO Creating compressed file CD %APP% 7z a -mx=9 %APP%_%VERSION%.zip * >nul CD .. MOVE %APP%\%APP%_%VERSION%.zip . >nul ECHO Cleaning up RMDIR /S /Q %APP% DEL windows\dirs.nsh DEL windows\files.nsh