pax_global_header00006660000000000000000000000064145012745760014525gustar00rootroot0000000000000052 comment=100ca9f323f4cb90eade1af9d7c6d5351f8c2783 kraft-1.1/000077500000000000000000000000001450127457600124755ustar00rootroot00000000000000kraft-1.1/.github/000077500000000000000000000000001450127457600140355ustar00rootroot00000000000000kraft-1.1/.github/workflows/000077500000000000000000000000001450127457600160725ustar00rootroot00000000000000kraft-1.1/.github/workflows/main.yml000066400000000000000000000044001450127457600175370ustar00rootroot00000000000000name: CI on: [push, pull_request, workflow_dispatch] jobs: appimage-build: runs-on: ubuntu-latest container: opensuse/leap:15.2 steps: # need to install Git >= 2.18 before checkout according to GitHub actions # we can just install all the dependencies beforehand, though - name: Install dependencies run: | zypper install -y \ gcc \ gcc-c++ \ cmake \ make \ wget \ git \ extra-cmake-modules \ libctemplate-devel pkgconf \ "cmake(Grantlee5)" \ "cmake(KF5Codecs)" \ "cmake(KF5Config)" \ "cmake(KF5Contacts)" \ "cmake(KF5I18n)" \ "cmake(Qt5Core)" \ "cmake(Qt5Gui)" \ "cmake(Qt5Sql)" \ "cmake(Qt5Test)" \ "cmake(Qt5Widgets)" \ "cmake(Qt5Xml)" \ "cmake(Qt5Svg)" \ libQt5Sql5-sqlite \ libQt5Sql5-mysql \ libqt5-qtdeclarative-tools - uses: actions/checkout@v3 with: submodules: recursive fetch-depth: 0 - name: Build AppImage run: | export APPIMAGE_EXTRACT_AND_RUN=1 wget https://github.com/TheAssassin/appimagecraft/releases/download/continuous/appimagecraft-x86_64.AppImage chmod +x appimagecraft-x86_64.AppImage ./appimagecraft-x86_64.AppImage - name: Archive artifacts uses: actions/upload-artifact@v3 with: if-no-files-found: error name: AppImage path: | Kraft*.AppImage* upload: name: Create release and upload artifacts needs: - appimage-build runs-on: ubuntu-20.04 steps: - name: Download artifacts uses: actions/download-artifact@v3 - name: Inspect directory after downloading artifacts run: ls -alFR - name: Create release and upload artifacts env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | wget -q https://github.com/TheAssassin/pyuploadtool/releases/download/continuous/pyuploadtool-x86_64.AppImage chmod +x pyuploadtool-x86_64.AppImage ./pyuploadtool-x86_64.AppImage **/Kraft*.AppImage* kraft-1.1/.gitignore000066400000000000000000000000321450127457600144600ustar00rootroot00000000000000build *.*swp* *.AppImage* kraft-1.1/AUTHORS000066400000000000000000000002171450127457600135450ustar00rootroot00000000000000Klaas Freitag Thomas Richard Ronald Stroethoff (Manual, dutch translation) kraft-1.1/CMakeLists.txt000066400000000000000000000106421450127457600152400ustar00rootroot00000000000000project(kraft) cmake_minimum_required(VERSION 3.16.0) cmake_policy(SET CMP0063 NEW) find_package(ECM REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) set(CMAKE_AUTOMOC TRUE) option(AKONADI_LEGACY_BUILD "Build with older versions of Akonadi (KF5 Prefix)" OFF) # Akonadi Prefix: Set this to KF5 for builds with Akonadi Libs before 5.23 set(AKO_PREFIX "KPim5") if (AKONADI_LEGACY_BUILD) set(AKO_PREFIX "KF5") endif() message("Akonadi Prefix is ${AKO_PREFIX}") include(GetGitRevisionDescription) # set git revision info get_git_head_revision(GIT_REFSPEC GIT_SHA1) # if we cannot get it from git, directly try .tag (packages) # this will work if the tar balls have been properly created # via git-archive. if ("${GIT_SHA1}" STREQUAL "GITDIR-NOTFOUND") file(READ ${CMAKE_SOURCE_DIR}/.tag sha1_candidate) string(REPLACE "\n" "" sha1_candidate ${sha1_candidate}) if (NOT ${sha1_candidate} STREQUAL "$Format:%H$") message("${sha1_candidate}") set (GIT_SHA1 "${sha1_candidate}") endif() endif() message(STATUS "Git dynamic information") message("GIT_SHA1: ${GIT_SHA1}") execute_process( COMMAND git rev-parse --abbrev-ref HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE ) message("GIT_BRANCH: ${GIT_BRANCH}") cmake_host_system_information(RESULT BUILD_HOST_NAME QUERY HOSTNAME) if(${CMAKE_VERSION} VERSION_GREATER "3.22.0") cmake_host_system_information(RESULT BUILD_HOST_DISTRI QUERY DISTRIB_PRETTY_NAME) else () set(BUILD_HOST_DISTRI "unknown distribution") endif() message("Build host name: ${BUILD_HOST_NAME}") message("Build host distribution: ${BUILD_HOST_DISTRI}") include(KDEInstallDirs) include(KDECMakeSettings) include(ECMInstallIcons) include(KDEFrameworkCompilerSettings) include(KDECMakeSettings) include(FeatureSummary) # Uncomment to enable some tweaks for AppImage build # add_definitions(-DBUILD_APPIMAGE=1) kde_enable_exceptions() remove_definitions(-DQT_NO_SIGNALS_SLOTS_KEYWORDS) remove_definitions(-DQT_NO_CAST_FROM_ASCII) find_package(Qt5 CONFIG REQUIRED Core Gui Sql Widgets Xml Svg ) # XmlGui for the ConfigSkeleton find_package(KF5 REQUIRED COMPONENTS I18n Config Contacts ) # Grantlee templating engine find_package(Grantlee5 REQUIRED) set_package_properties(Grantlee5 PROPERTIES DESCRIPTION "Library for templating html and pdf output" URL "https://www.grantlee.org/" PURPOSE "Optionally used for templating" TYPE OPTIONAL ) find_package(${AKO_PREFIX}Akonadi) set_package_properties(${AKO_PREFIX}Akonadi PROPERTIES DESCRIPTION "Library for general Access to Akonadi" URL "https://www.kde.org/" PURPOSE "Optionally used for addressbook integration" TYPE OPTIONAL ) find_package(${AKO_PREFIX}AkonadiContact) set_package_properties(${AKO_PREFIX}AkonadiContact PROPERTIES DESCRIPTION "Library for Accessing Contacts stored in Akonadi" URL "https://www.kde.org/" PURPOSE "Optionally used for addressbook integration" TYPE OPTIONAL ) find_package(${AKO_PREFIX}ContactEditor) set_package_properties(${AKO_PREFIX}ContactEditor PROPERTIES DESCRIPTION "Library for editing contacts stored in Akonadi" URL "https://www.kde.org/" PURPOSE "Optionally used for addressbook integration" TYPE OPTIONAL ) if(${AKO_PREFIX}Akonadi_FOUND AND ${AKO_PREFIX}AkonadiContact_FOUND AND ${AKO_PREFIX}ContactEditor_FOUND) add_definitions(-DHAVE_AKONADI) endif() find_package(Ctemplate REQUIRED) find_package(Asciidoctor) # Sets the variable ASCIIDOCTOR_FOUND set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-suggest-override") # disable the warning about null-pointer zero. FIXME. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-zero-as-null-pointer-constant") set(QT_DEFINITIONS "${Qt5Core_DEFINITIONS} ${Qt5Gui_DEFINITIONS} ${Qt5Widgets_DEFINITIONS}") add_definitions(${QT_DEFINITIONS} ) include_directories(${QT_INCLUDES} src) include_directories( /usr/include/${AKO_PREFIX}/AkonadiCore ) include_directories(/usr/include/${AKO_PREFIX}/) if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ki18n_install(po) endif() add_subdirectory(src) add_subdirectory(database) add_subdirectory(reports) add_subdirectory(views) add_subdirectory(importfilter) add_subdirectory(tools) add_subdirectory(styles) add_subdirectory(meta) add_subdirectory(tests) add_subdirectory(manual) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) kraft-1.1/COPYING000066400000000000000000000432541450127457600135400ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. 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 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. kraft-1.1/Changes.txt000066400000000000000000000471071450127457600146170ustar00rootroot00000000000000Changes since version 1.0: ######################################### - updated nl translations of the manual - update the app translations - Fix the application icon - Fix the changed Akonadi Prefix, added build switch AKONADI_LEGACY_BUILD - More Akonadi related ifdefs - Few fixes and improvements to cmake files (eg. #205) - cleanup of code and remove endl which removes lots of warnings - Allow Macros in pre- and post text, to support date calculations and sum calculation (incl. tax) based on tags - more tests - Add Button to Allow to insert template pre- and post texts rather than replace the entire text #167 => release v. 1.1 (2023) Changes since version 0.98: ######################################### - Have two new merge modes for the watermark tool - PDF watermark tool can also append PDF files now - Add numbercycle day counter variable (#138) - Test improvements and new tests added - User manual improvements - Localized screenshots in the user manual (Thx Ronald) - Demand and Alternative: Do not overwrite custom prefix - Default Demand and Alternative text configurable in prefix dialog - Add more variables to weasyprint (#166) - Ability to add EPC QR code to invoices (Giro Code) - Maintain users bank account to be included in documents - Add some metadata to the html representation (weasyprint) - Use custom icons for all icons in Krafti (#175) - Experimental: html tags in pre- and post tags and items & catalogs - Add more contrib documents from Achim (BNC) - Database refresh only in readonly mode - Huge improvements to the AppImage build (#191) - Fix: Numbercycle dialog with day counter (#138) - Fix: Strikeout for deleted items working again - Fix: Delete column in sqlite migrations (#162) - Fix: Add -p switch to call of weasyprint (html presentational hints) - Fix: Set reconnect option for MySQL (#183) => release v. 1.0 (Dec 17, 2022) Changes since version 0.97: ######################################### - Add dutch translation of the manual, Kudos to Ronald Stroethoff - Add support for XRechnung export of invoices - User manual improvements - Translations updates (German) - Add TOC to the manual - Add predecessor template variable to weasyprint documents - Adopt to latest Akonadi versions - Add ECE20 units for XRechnung - Fix: Record usage of catalog items properly. Store usage amount and last usage time. Display that properly in the catalog editor. - Fix: Drag and drop sorting of items now working properly. - Fix: Adopt to new Akonadi v. 5.19 - Fix: Add predecessor variable to weasyprint template. - Fix: Use correct icons everywhere. - Fix: Format of date and time corrected. - Fix: Store useful value for the locale in db. For later. - Fix: Textselection behaviour consitent - Fix: Write useful locale settings into the database. - Fix: Sorting in material catalogue now working. - Fix: Better error messages if python modules are missing. - Fix: Read mysql port from config file - Fix: Rearrange docdetails view a bit if there is a project set. => release v. 0.98 (May 22, 2022) Changes since version 0.96: ######################################### Add read only mode to kraft. Documents can not be edited, but viewed and printed. Needs to be configured to share database and the PDF store directory. - Fix: Bring back the checkbox for items, this fixes #103 - Fix: Command line option -d works again - Fix: Fix out of index deletes of items, #102 - Fix: Do watermark on PDFs properly - Fix: Fix watermark on all pages functionality - Fix: Align watermark files entry fields properly (community contrib) - Cmake: Build a static lib of all sources to link with kraft and all the tests. => release v. 0.97 (Aug 15, 2021) Changes since version 0.95: ######################################### - Found new MIT licensed icons to avoid uncertainess with CC license. - Allow to use the "add new" button in the doc editor to add new catalog templates. It presets the correct chapter. - Fix: Use the xmlArchivePath correctly (#80) - Fix: Handling of Cancel button in template to doc dialog. - Fix: Convert newlines in the items to
for the weasyprint doc generation. - Fix: In Followup document: If the standard text for pre and post text of the target document type is empty, the one from the source document is copied over instead. (#91) => release v. 0.96 (Feb. 27, 2021) Changes since version 0.90: ######################################### - Add Grantlee as templating engine. - Add Weasyprint as rendering engine for PDFs. - Removed Splash screen completely for simplification. - Switch to python3 with the erml2pdf tool. - Add a date format selector to Kraft settings. Allow to set a four digit year in dates and other formats. - Fix: Show proper amount of items in no-price-display mode. - Fix: Show proper timestamp of last change of catalog items with SQLite database. - Fix: show proper number of items also in Lieferschein. - Fix: Save some more window states (size, position) - Fix: Set the unit of discount items to pauschal. - Fix: Also change lastmodified-Timestamp if only an item was added. - Add the user manual. Open it according to user language. => release v. 0.95 (Aug. 28, 2020) Changes since version 0.82: ######################################### - Reworked follow up and copy document * set the correct header- and footer-texts according to the doc type * Added a checkbox if items should be copied or not - New feature: partial invoices that are substracted in the final invoice - Use an XML based migration system for document types - Added the first unit tests to Kraft - Made the document templates not containing any language specific strings any more. There is only one doc now for all languages, getting translated strings as template variables. - Removed KeepTogether flag for tables to avoid that a long list of items only starts on the next page. Might have impact on some docs. - Fixed formatting of the amount number in the XML output - More Less-KDE: Removed more mandatory dependencies on KDE. - Added 'About Kraft' information to Krafts system view. - Added document type 'Offer without price tags', which does not print price tags on the PDF (issue #58). - Internationalization: Added dutch translation => release v. 0.90 (Dec. 14, 2019) Changes since version 0.81: ######################################### - Fix send document by email - Allow emailing through xdg-email and not only through thunderbird To enable, set mailUA=xdg in the config file in the system section. - Fixed wrong usage of i18n command which caused a lot of error messages on the console. (#37) - Time calculation: Add a time unit to the form, allow to calculate times in hours, minutes and seconds (#43) - Refactored the calculation dialog, fixed using margin. (#42) - Properly ask to waste changes if user hits cancel in Calc dialog. - Fix some glitches in the setup code path, ie. db update. - Relaxed the document layout a bit by choosing a smaller font and adjusting the table column settings a bit. - More minor bug fixes and improvements => release v. 0.82 (Oct 17, 2018) Changes since version 0.80: ######################################### - Fix to build with Qt 5.11 - CMake fixes: Installation directories - Use QProcess instead of system call - Fix appstream XML data - Fix display of individual tax block on documents => release v. 0.81 (June 12, 2018) Changes since version 0.59: ######################################### - Port to Qt5/KDE Frameworks 5 - Reduction of build and runtime dependencies, especially of KDE Frameworks, replacing old KDE classes with their Qt equivalents - Dropped Webkit. Use QTextbrowser instead. Ported html generating code and CSS accordingly - Dependency on Akonadi is now optional, so builds without Akonadi are possible - Address management in Kraft was abstracted to work with or without Akonadi, other address backends could be implemented much easier now - Refresh of the GUI plus new icons, easier. - Refactored time line models completely - Show summaries for month and year items: Amount of doc types and added sums for each document type - GUI: New filter combo to limit to docs of last week or last month - Use templates for system view (contributed by Andy Wuest) - Ship an AppImage for easy testing of Kraft - Updated ReportLab based PDF generation script (erml2pdf) - countless bug fixes and improvements => release v. 0.80 (Apr 1, 2018) Changes since version 0.57: ######################################### - Fix handling of slashes in the doc id template - Fix a bug in calculation of the VAT sum - Removed kraftcat library as it was unused. Easier building now. => release v. 0.58 (Apr, 2014) Changes since version 0.56: ######################################### - No code changes. Just version bump because of a bogus tarball. => release v. 0.57 (Nov 7, 2014) Changes since version 0.55: ######################################### - Fix handling of custom greetings in combobox. - Handle document type changes correctly: Set a new ident number depending on the new document id - Fix behaviour of the greeting combobox: Do not loose custom entries any more - Add receipient email address if document is emailed - Fix document emailing for thunderbird - Fix removing of alternative- and on-demand state of items - Wording fixes - Fix Ok/Cancel for doc editor - Better error messages if template can not be read - A couple of crash fixes and memory management cleanups => release v. 0.56 (oct 30, 2014) Changes since version 0.54: ######################################### - Fix a bug with the PDF generation, regression in 0.54 - Fix compiling with latest version of ctemplate => release v. 0.55 (may 29, 2014) Changes since version 0.53: ######################################### - Use new address fetch job implementation that works independant from Nepomuk- or Baloo indexing of contacts. (KDE >= 4.12) - Support note-of-delivery documents (Lieferscheine) without prices. - Added findcontact utility - Generate a customer sorted document storage structure on disk - Improve stylesheet handling in templates, introduce CSS_IMG_PATH - Use environment variable KRAFT_HOME more consquentely - Fix tax sum calculation - Add customer address UID variable to number circle tags - Some memleak fixes - Add "followup document" to main menu - Fix installation of identity.trml - Allow the tags USERNAME, DATE and TIME in item templates. - Lots of other cleanups and fixes => release v. 0.54 (may 13, 2014) Changes since version 0.50: ######################################### - Fixes drag and drop handling in catalog window. - Fixes with units, do not confuse units any more - Utf8 fixes - other minor fixes - Releases 0.51 and 0.52 screwed. => release v. 0.53 (oct 11, 2013) Changes since version 0.50: ######################################### - Fix drag and drop in catalogues. - Implemented removal of sub chapters. - Add the content of an entire template catalog chapter to the document if the chapter item is selected. - Added a new setting "Own Identity" to allow to pick the own identity from the address books in an installed system. - Make text template loading utf8 save. - Reworked image-in-template example in invoice report template. - Fixed unit handling, no more startsWith coparison of text. => release v. 0.51 (sep 22, 2013) Changes since version 0.45: ######################################### - Handling of individual tax rates for each document item - bugfix: escape texts in reports correctly (reported by Lars Diel). - bugfix: if akonadi address was not found, display proper msg. - Proper error message if a python module is not installed but needed by the pdf generator. - added button to assign an address book entry as document receiver for existing documents (Bug #3477467) - bugfix: Display of number of processed sql commands in setup assistant (Bug #3560611) - started to optimize database save of documents for more performant saves. - bugfix: Fixed import of document items from csv lists. - added page number on default document from page two to end. - bugfix: Fixed mysql database setup. - Rearragned doc type setup dialog to better display path names of template file and watermark file. - bugfix: If a manual entered template has checkbox "store in template catalog, the template is immediately written to and catalog is reloaded. - bugfix: Focus on the last added item on document edit. => release v. 0.50 (dec 17, 2012) Changes since version 0.44: ######################################### - bugfix release: Fixed the display of decimal places in the PDF document which caused broken documents. => release v. 0.45 (nov 08,2011) Changes since version 0.43: ######################################### - Completely reworked the addressbook widget in Kraft, used in new doc assistant and in the "who am i" dialog: Fully Akonadi-based, works with various addressbooks and loads addresses way more fast. - Completely reworked text template widget used in the document editor: Less bugs, more obvious gui, help texts where needed - Fixed bug that crashed Kraft when clicking on empty catalog chapters. - Add ability to add localized report template files, added german localization - Fixed bug that numbers in the doc are not localized correctly - Fixed bug that the doc type is not taken correctly from the new doc wizard - No need any more to checkbox single item templates to move them into the document. Selecting is sufficient. - Added a search line in the "who am i"-dialog => release v. 0.44 (nov 03,2011) Changes since version 0.41: ######################################### - Added search box in digest lists again, for that enhanced the search field class. - cleaned up the digest models - optimized the digest model - changed from treeview to tableview for latest- and all view => release v. 0.43 (may 25, 2011) Changes since version 0.40: ######################################### - More changes to the Akonadi based addressbook integration - switched to a python only version of trml2pdf called erml2pdf, makes porting to other platforms easier plus dropped dependency on java with pdftk - used Qt Model/View for the document lists. Way faster startup. - New document digest view - Catalogs: Implemented nested catalog structure - Catalogs: Moving templates around per d&d - Catalogs: user defined sorting in catalogs - Catalogs: dropping of templates => released v. 0.41 (april 18th, 2011) Changes since version 0.32: ######################################### - Ported to the KDE 4 Platform. In particular, to KDE 4.4 - Use Akonadi based addressbook - Edit dialog for Wages and Units - SQLite-Support - Setup Assistant for SQLite and MySQL Databases => released v. 0.40 Changes since version 0.31: ######################################### - Tax: Added more flexible tax calculation. Kraft now has the tax in a table for easy changing, supports no, reduced and full tax on document level for this release, on item level later. - Numbercycles: All Kraft documents need an unique document number. These are taken from numbercycles now which can be edited and shared between document types. - Watermark: Kraft documents can now be merged with an existing pdf file with the company logo. Configuration through the Kraft settings on a per document type basis - Templates: Kraft now supports different templates for each document type. Templates can be configured through the Kraft settings. - Project-String: There is a project label at the document. It is exported to the document template. - System-Tab: Display of some interesting setup information - Templates for PDF and HTML output are reloaded if modified => released v. 0.32 Changes since version 0.30: ######################################### - added a read only view on documents, customizable with ctemplate as html page - added importing items from text files with configurable import filters, to enable usage of special software which is able to export text files - added document number cycles: The unique id of a document depends on a unique number. Now there can be multiple number cycles which can be used by document types. Multiple doc types can use the same number cycle, that means that for example all types of invoices count the same number cycle while offers are in another. => released v. 0.31 Changes since version 0.25: ######################################### - introduced the extended combo box with explanation line for units. - added document item tagging - added discount item system, based on tagging - tag templates with tag template edit dialog - fixed a bunch of bugs with text templates (header- and footer text) - tag selection in ordinary add-item-to-document dialog => released v. 0.30 Changes since version 0.24: ######################################### - Added a Wizard for document creation - Improved the document overview widget for more intuitive use. - Copying of complete documents added. - Followup documents (eg. Invoice follows Offer) added - Litte marker for new documents added to doc overview list. - Help text added to positions canvas - Client address bits added to the available template variables Changes since version 0.23: ######################################### - internationalisation: Ability to do documents in a different location than the desktop is running under. => released BETA v. 0.24 Changes since version 0.22: ######################################### - fixed: database migration 5: added IF EXISTS - fixed: encoding in the report file - improved: The document digest overview is not longer always redrawed and looses its selected item. => released v. 0.23 Changes since version 0.20: ######################################### - fixed: select from catalogs with doubleclick - fixed: allow prices for positions larger than 10k - fixed: openArchivedDocument printed again instead of opening archived doc from the archive path - fixed: template texts in the catalog view where not shown if they were exactly 60 chars long. - feature: Alternative positions - feature: Demand positions - feature: Switched to google template system, see http://code.google.com/p/google-ctemplate/ - bugfix: Catalog changes show up directly in opened catalogs, also if open as a template catalog in the doc window. => released v. 0.22 Changes since version 0.14: ######################################### - fixed bug with manual price field that needs to be left by TAB to get a change recognised. - increased precision to 2 digits for position amounts - allow euro-sign in texts and in the whiteboard. Due to a lack in the qt3 mysql driver the char needs to be en- and decoded. - reduced the amount of toolbar buttons to only show the important ones. - more beautifull and working navigation block in the document dialog - mailing documents added - Completely changed header- and footer text template system: * now there is more than one text available per text- and doc type * direct adding, editing and removing of texts from the dialog * selecting template texts in the same way as selecting position templates, more intuitive GUI - Addresses also selectable from an address catalog - persist the selection of the greeting and salut text - Document ID now configurable in the settings file, key DocIdent: [document] DocIdent=T-%y%w%i - database upgrade code more robust - now additionally save archived xml documents Bugs fixed: - fixed time lined doc overview, now displaying all documents of all months of a year. - fixed modification indication: Now also adding a position counts as modification - encoding bugs fixed - allow to leave text edit fields using the tab key - deletion of positions: Fixed an iteration over the list issue - smarter template-to-doc-position dialog - others kraft-1.1/INSTALL.md000066400000000000000000000104021450127457600141220ustar00rootroot00000000000000# Kraft Build and Installation This document describes how to compile and install Kraft. This requires a bit of Linux knowledge and is only recommended for experienced users and developers. ## Packages Linux Distributions have package management systems to provide users with all kind of software in a clean and easy way. This should be the prefered way to install Kraft. Check the package pools of your prefered distribution first. If the package is outdated, consider asking your distribution to upgrade! ## Compiling Kraft The following section briefly describes how to build Kraft with cmake. ### Precondition Check that cmake is installed on your machine and is in your PATH. To do so, just type ``` $ cmake --version ``` on your command line. Version 2.4 is required, the most recent stable version of cmake is preferred. To build Kraft, the following libs and software versions have to be provided: - cmake and the cmake extra modules - Qt libs incl. devel packages version 5.5.0 or later - kcontacts for using the KDE contact classes - A few other KDE classes (kxmlgui, ki18n) - google ctemplate, A simple but powerful template language for C++, packages from the openSUSE Buildservice or from the website https://github.com/OlafvdSpek/ctemplate - grantlee, an C++ text template framework - optional: akonadi contact for Akonadi based addressbook access Required packages for building with openSUSE: - cmake - extra-cmake-modules - gcc-c++ - kcontacts-devel - gettext - libctemplate-devel - libQt5Core-devel - libQt5Gui-devel - libQt5Sql-devel - libQt5Widgets-devel - libQt5Xml-devel - libQt5Svg-devel - grantlee5-devel These are optional to build with Akonadi Support: - akonadi-contact-devel - akonadi-devel To build with Akonadi versions before 23.04, cmake has to run wtih the build option `-DAKONADI_LEGACY_BUILD=ON` to use the old prefix KF5. ### Build Kraft cmake is designed so that the build process can be done in a separate directory. This is highly recommended for users and required for packagers. Go to the top level of the source directory. To build Kraft in the subdirectory `./build/` type ``` $ mkdir build $ cd build $ cmake .. # to generate the Makefiles. $ cmake . # to change the configuration of the build process. (optional) ``` Check out for errors during the cmake run. Fix them, usually you need more devel packages installed. Ready? Congratulations, your Makefiles were generated! Now you could just type ``` $ make # to build the project in the build/ directory. ``` Note that 'make' automatically checks whether any CMakeLists.txt file has changed and reruns cmake if necessary. To start Kraft from the build directory, set the environment variable `KRAFT_HOME` to the root of the _source_ directory to let Kraft find its resource files: ``` $ KRAFT_HOME=/home/me/sources/kraft ``` ## Kraft Installation Type ``` $ make install ``` To change the target root directory to where it is installed, call cmake with the parameter `-DCMAKE_INSTALL_PREFIX=/my_install_dir` ## Kraft Manual Kraft ships a user manual in different languages. To rebuild it, asciidoctor is required. If that dependency is found, cmake detects it and gives a new make target: ``` $ make manual ``` to re-create the docs. ## Database Kraft either can use a SQLite file based database or a MySQL server based database. The SQLite database is created automatically on the fly on first start. Its use is recommended for all users who want to evaluate Kraft. To run Kraft with MySQL, create or pick a user on the MySQL server with appropiate permissions to write to a specific database and create tables on it. Create an empty database to use with Kraft. Remember both the database name and the credentials. On Krafts first start, enter these data in the setup assistant. Kraft will create the database tables and fill it automatically. ## Document Generation Kraft generates PDF documents. For that it uses either a python tool named erml2pdf or the python project weasyprint. erml2pdf can be found in Kraft's tools directory in this source package. Weasyprint should be installed separately on the machine that is running Kraft. To compute PDF watermarks, Kraft uses python-pypdf2 for pdf processing. The python modules are not part of Kraft and should be installed separately on the system. kraft-1.1/README.md000066400000000000000000000031641450127457600137600ustar00rootroot00000000000000 # The Kraft Project **Kraft is free software to help to handle documents like quotes and invoices in your small business.** It is a Qt/KF5 based desktop software with a strong focus on ease of use and the just enough feature set for the use case. With Kraft, creating documents will run smooth and free time for more enjoyable things than office work. Check out the website http://volle-kraft-voraus.de for more information. Kraft runs on your Linux desktop. No cloud involved, your data stays with you! With Kraft, writing documents like quotes and invoices is very easy and fast. Repeating tasks are supported, documents can be generated semi automatically, ie. invoices from offers sent out before. For efficient work, Kraft supports catalogs to organize materials and template texts. It focuses on high quality printouts because paper is still the main communication media in the small business world. However, it also sends documents via email. Kraft utilizes a bunch of very useful tools of the free softare world: - KDE addressbook for customer management - MySQL or alternatively SQLite for database support - [WeasyPrint](https://weasyprint.org) or [ReportLab](http://www.reportlab.com/opensource/) for PDF generation. - [Grantlee](https://github.com/steveire/grantlee) or [ctemplate](https://github.com/OlafvdSpek/ctemplate) templating library. ## Interested? [Install Kraft](http://volle-kraft-voraus.de/Main/Download) on your Linux desktop. For questions and comments, please speak up. Check the [web site](http://volle-kraft-voraus.de/Main/Contribution) for contact details. Jun 2005-2023, Klaas Freitag kraft-1.1/Releasechecklist.md000066400000000000000000000011571450127457600162750ustar00rootroot00000000000000## Kraft Release Checklist _Before drafting a release, copy this checklist template into an issue for the specific version._ Release Checklist for Kraft Version XX ### Before the first beta - [ ] Check entries in `src/version.h` - [ ] Check the database scheme version number. - [ ] Update Changes file ### Before the first RC - [ ] Send a tweet/blog about the upcoming release ### For every RC - [ ] Create a proper tag - [ ] Update the packages in a hidden repo on OBS - [ ] x ### Build packages - [ ] in OBS for KDE:Extra - [ ] Submit to Tumbleweed ### AppImage - Update the Kraft package for the AppImage kraft-1.1/Releasenotes.txt000066400000000000000000000057401450127457600156750ustar00rootroot00000000000000 ==================================================================== Please refer to the Kraft Project website http://volle-kraft-voraus.de/Main/Releases ==================================================================== older entries: Das Kraft Release 0.22 verwendet ein neues Text-Template System, das für die benutzerkonfigurierbare PDF-Ausgabe der Dokumente verwendet wird. Es wird das google ctemplate-System verwendet, Details dazu unter http://code.google.com/p/google-ctemplate/ Das neue System ist sehr flexibel und stabil und daher zukunftssicher und löst das selbstgeschriebene alte System ab. Leider hat sich die Syntax geändert, weshalb eigene Templates angepasst werden müssen. Weiterhin enthält Kraft 0.22 zwei neue Arten von Dokument Posten. Es gibt Alternativpositionen, die eine Alternative zu einer vorhergegangenen Position beschreiben. Bedarfspositionen beschreiben Aufwände, die nur bei Bedarf anfallen. Beide Arten addieren ihre Kosten nicht zur Gesamtsumme und sind durch Kursivschrift im Dokument hervorgehoben. Weiterhin wurden viele Fehler behoben und generelle Code Verbesserungen vorgenommen. Das Datenbankschema wurde geändert, das Update geschieht automatisch durch Kraft. ---------------------------------------------------------------------- The Kraft release 0.22 changes the text template system that is used by Kraft to support user configureable pdf output. It was changed from a very basic homegrown system to the google ctemplate system, details under http://code.google.com/p/google-ctemplate/ It is very flexible and mature and thus future proof which was reason enough to switch to it at this early project state. The template format is slightly different to the former format, so editing of own templates is required. Additionally two new kinds of document positions were added: Alternative and demand positions. The alternative positions describe an alternative to another position. The demand position describes a position where it is not yet clear if and how much of it is needed. Both position kinds do not add to overall sum and are marked through italic characters in the printout by default. Furthermore a lot of bugfixes and genral code improvements where committed. The database scheme was extended, update is automatically performed. ==================================================================== This release 0.20 of Kraft brings a big step ahead in the way text templates for the header and footer texts for the different doc types are managed. Kraft now supports to have several templates per type (ie. for the header of invoices) and all of them are offered very handy right to select from a catalog kind in a context aware manner. Kraft takes another important step towards a really well integrated KDE addressbook. All customer addresses are managed in the KDE addressbook but there is a customer catalog now integrated. This release contains a lot of important bug fixes and small additions to functionality, update is really recommended. kraft-1.1/TODO000066400000000000000000000002321450127457600131620ustar00rootroot00000000000000Todo list for Kraft =================== Please use the github issue tracker for enhancements and bug reports: https://github.com/dragotin/kraft/issues kraft-1.1/appimagecraft.yml000066400000000000000000000020331450127457600160210ustar00rootroot00000000000000version: 1 project: name: de.volle_kraft_voraus.kraft.desktop version_command: git describe --tags build: cmake: scripts: post_build: # make sure weasyprint can be launched from a path next to the kraft binary # this simplifies the lookup greatly # also, if we create the file now (i.e., before linuxdeploy runs), it won't be overwritten by the python plugin - | cat > "$BUILD_DIR"/AppDir/usr/bin/weasyprint <<\EOF #! /bin/bash set -eo pipefail own_path="$(dirname "$(readlink -f "$0")")" exec "$own_path"/../conda/bin/python -m weasyprint "$@" EOF chmod +x "$BUILD_DIR"/AppDir/usr/bin/weasyprint appimage: linuxdeploy: plugins: - qt - conda - https://github.com/linuxdeploy/misc-plugins/raw/master/grantlee5/linuxdeploy-plugin-grantlee5.sh environment: UPD_INFO: "gh-releases-zsync|dragotin|kraft|latest|Kraft-*x86_64.AppImage.zsync" PIP_REQUIREMENTS: "weasyprint reportlab pypdf2" GRANTLEE5_PLUGINS_DIR: "/usr/lib64/grantlee/5.2/" kraft-1.1/cmake/000077500000000000000000000000001450127457600135555ustar00rootroot00000000000000kraft-1.1/cmake/modules/000077500000000000000000000000001450127457600152255ustar00rootroot00000000000000kraft-1.1/cmake/modules/COPYING-CMAKE-SCRIPTS000066400000000000000000000024571450127457600202330ustar00rootroot00000000000000Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. kraft-1.1/cmake/modules/FindAsciidoctor.cmake000066400000000000000000000005431450127457600212750ustar00rootroot00000000000000# Find Asciidoctor - an Asciidoc converter to html # # ASCIIDOCTOR_FOUND # ASCIIDOCTOR_EXECUTABLE FIND_PROGRAM(ASCIIDOCTOR_EXECUTABLE asciidoctor) MARK_AS_ADVANCED(ASCIIDOCTOR_EXECUTABLE) IF (NOT ASCIIDOCTOR_EXECUTABLE) SET(ASCIIDOCTOR_FOUND "NO") ELSE (NOT ASCIIDOCTOR_EXECUTABLE) SET(ASCIIDOCTOR_FOUND "YES") ENDIF (NOT ASCIIDOCTOR_EXECUTABLE) kraft-1.1/cmake/modules/FindCtemplate.cmake000066400000000000000000000015671450127457600207570ustar00rootroot00000000000000# - Try to find the ctemplate # Once done this will define # # CTEMPLATE_FOUND - system has ctemplate # CTEMPLATE_INCLUDE_DIR - the ctemplate include directory # CTEMPLATE_LIBRARIES - Link this to use ctemplate # # Copyright (c) 2009, Thomas Richard, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (CTEMPLATE_INCLUDE_DIR AND CTEMPLATE_LIBRARIES) # in cache already SET(CTEMPLATE_FOUND TRUE) else (CTEMPLATE_INCLUDE_DIR AND CTEMPLATE_LIBRARIES) FIND_PATH(CTEMPLATE_INCLUDE_DIR ctemplate/template.h) FIND_LIBRARY(CTEMPLATE_LIBRARIES NAMES ctemplate) include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Ctemplate DEFAULT_MSG CTEMPLATE_INCLUDE_DIR CTEMPLATE_LIBRARIES ) endif (CTEMPLATE_INCLUDE_DIR AND CTEMPLATE_LIBRARIES) kraft-1.1/cmake/modules/GetGitRevisionDescription.cmake000066400000000000000000000067021450127457600233420ustar00rootroot00000000000000# - Returns a version string from Git # # These functions force a re-configure on each git commit so that you can # trust the values of the variables in your build system. # # get_git_head_revision( [ ...]) # # Returns the refspec and sha hash of the current head revision # # git_describe( [ ...]) # # Returns the results of git describe on the source tree, and adjusting # the output so that it tests false if an error occurs. # # git_get_exact_tag( [ ...]) # # Returns the results of git describe --exact-match on the source tree, # and adjusting the output so that it tests false if there was no exact # matching tag. # # Requires CMake 2.6 or newer (uses the 'function' command) # # Original Author: # 2009-2010 Ryan Pavlik # http://academic.cleardefinition.com # Iowa State University HCI Graduate Program/VRAC # # Copyright Iowa State University 2009-2010. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) if(__get_git_revision_description) return() endif() set(__get_git_revision_description YES) # We must run the following at "include" time, not at function call time, # to find the path to this module rather than the path to a calling list file get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) function(get_git_head_revision _refspecvar _hashvar) set(GIT_DIR "${PROJECT_SOURCE_DIR}/.git") if (NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) return() endif() set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") if(NOT EXISTS "${GIT_DATA}") file(MAKE_DIRECTORY "${GIT_DATA}") endif() if(NOT EXISTS "${GIT_DIR}/HEAD") return() endif() set(HEAD_FILE "${GIT_DATA}/HEAD") configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" "${GIT_DATA}/grabRef.cmake" @ONLY) include("${GIT_DATA}/grabRef.cmake") set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) endfunction() function(git_describe _var) if(NOT GIT_FOUND) find_package(Git QUIET) endif() get_git_head_revision(refspec hash) if(NOT GIT_FOUND) set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) return() endif() if(NOT hash) set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) return() endif() # TODO sanitize #if((${ARGN}" MATCHES "&&") OR # (ARGN MATCHES "||") OR # (ARGN MATCHES "\\;")) # message("Please report the following error to the project!") # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") #endif() #message(STATUS "Arguments to execute_process: ${ARGN}") execute_process(COMMAND "${GIT_EXECUTABLE}" describe ${hash} ${ARGN} WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" RESULT_VARIABLE res OUTPUT_VARIABLE out ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT res EQUAL 0) set(out "${out}-${res}-NOTFOUND") endif() set(${_var} "${out}" PARENT_SCOPE) endfunction() function(git_get_exact_tag _var) git_describe(out --exact-match ${ARGN}) set(${_var} "${out}" PARENT_SCOPE) endfunction() kraft-1.1/cmake/modules/GetGitRevisionDescription.cmake.in000066400000000000000000000022621450127457600237440ustar00rootroot00000000000000# # Internal file for GetGitRevisionDescription.cmake # # Requires CMake 2.6 or newer (uses the 'function' command) # # Original Author: # 2009-2010 Ryan Pavlik # http://academic.cleardefinition.com # Iowa State University HCI Graduate Program/VRAC # # Copyright Iowa State University 2009-2010. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) set(HEAD_HASH) file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) if(HEAD_CONTENTS MATCHES "ref") # named branch string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") if(EXISTS "@GIT_DIR@/${HEAD_REF}") configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) set(HEAD_HASH "${HEAD_REF}") endif() else() # detached HEAD configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) endif() if(NOT HEAD_HASH) file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) string(STRIP "${HEAD_HASH}" HEAD_HASH) endif() kraft-1.1/database/000077500000000000000000000000001450127457600142415ustar00rootroot00000000000000kraft-1.1/database/CMakeLists.txt000066400000000000000000000001111450127457600167720ustar00rootroot00000000000000add_subdirectory(mysql) add_subdirectory(sqlite3) add_subdirectory(meta) kraft-1.1/database/README000066400000000000000000000024531450127457600151250ustar00rootroot00000000000000Kraft - solution for open craft =============================== Kraft is a program that supports craftsmen in their daily jobs: making offers, invoices and confirmations. Kraft needs a mysql database running. But setup is easy, please try it. How to setup the database? ========================== First, install the mysql packages of your distribution. Create a database user and select a suitable password. Please replace the word 'user' in the following code examples with the user name you created. The database can be set up using the creation scripts in Krafts database directory. The scripts do create the database completely new, even if they exists. The standard way however to let Kraft create and maintain the database schema for you. All that needs to be done is to - start MySQL on the system - have a user and password combination that has acces to the database - create an empty database with a suitable name like for example "kraft". - enter the credentials and the database name in Kraft's config dialog. Schema creation and maintenance is done by Kraft automatically. To create the database, perform the following steps: The database credentials must be entered into the settings dialog in kraft after the first start. Please restart after you have entered the data. That's it. kraft-1.1/database/errorcodes.txt000066400000000000000000000004461450127457600171550ustar00rootroot00000000000000type problem + native db error 1 mysql not started on the system: 'Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111) QMYSQL3: Unable to connect' 1 mysql running, but no db kraft there 'Unknown database 'kraft' QMYSQL3: Unable to connect' kraft-1.1/database/meta/000077500000000000000000000000001450127457600151675ustar00rootroot00000000000000kraft-1.1/database/meta/21_meta.xml000066400000000000000000000115161450127457600171450ustar00rootroot00000000000000 Progress Payment Invoice default en PartialInvoice true Final Invoice Invoice Partial Invoice default en PartialInvoice true Final Invoice Invoice Final Invoice default en SubstractPartialInvoice true Teilrechnung default de PartialInvoice true Schlussrechnung Rechnung Abschlagsrechnung default de PartialInvoice true Schlussrechnung Rechnung Schlussrechnung default de SubstractPartialInvoice true Angebot de Abschlagsrechnung Teilrechnung Schlussrechnung Rechnung Auftragsbestätigung de Abschlagsrechnung Teilrechnung Schlussrechnung Rechnung Lieferschein de docTemplateFile delivery_receipt.trml HidePrices 1 Abschlagsrechnung Teilrechnung Schlussrechnung Rechnung Angebot (keine Preise) de docTemplateFile offer_no_prices.trml HidePrices 1 Delivery Receipt en docTemplateFile delivery_receipt.trml HidePrices 1 Final Invoice Partial Invoice Progress Payment Invoice Invoice Acceptance of Order en Final Invoice Partial Invoice Progress Payment Invoice Invoice Offer en Final Invoice Partial Invoice Progress Payment Invoice Invoice Offer (No Pricetags) en docTemplateFile offer_no_prices.trml HidePrices 1 Offerte nl Rekening Pakbon Pakbon nl docTemplateFile delivery_receipt.trml Rekening Rekening nl kraft-1.1/database/meta/CMakeLists.txt000066400000000000000000000002431450127457600177260ustar00rootroot00000000000000########### install files ############### file(GLOB meta_scripts *_meta.xml) install(FILES ${meta_scripts} DESTINATION ${DATA_INSTALL_DIR}/kraft/meta) kraft-1.1/database/mysql/000077500000000000000000000000001450127457600154065ustar00rootroot00000000000000kraft-1.1/database/mysql/CMakeLists.txt000066400000000000000000000003031450127457600201420ustar00rootroot00000000000000add_subdirectory(migration) ########### install files ############### install(FILES create_schema.sql fill_schema_de.sql fill_schema_en.sql DESTINATION ${DATA_INSTALL_DIR}/kraft/dbinit/mysql) kraft-1.1/database/mysql/create_schema.sql000066400000000000000000000117701450127457600207200ustar00rootroot00000000000000# DROP DATABASE IF EXISTS kraft; # CREATE DATABASE kraft DEFAULT CHARACTER SET "utf8"; # use kraft; CREATE TABLE preisArten ( preisArtID INT NOT NULL, preisArt VARCHAR(64) NOT NULL, PRIMARY KEY( preisArtID ) ); CREATE TABLE wordLists( category VARCHAR(64), word VARCHAR(255), PRIMARY KEY( category, word ) ); CREATE TABLE CatalogSet( catalogSetID INT NOT NULL AUTO_INCREMENT, name VARCHAR(255), description VARCHAR(255), catalogType VARCHAR(64), sortKey INT NOT NULL, PRIMARY KEY(catalogSetID) ); CREATE TABLE CatalogChapters( chapterID INT NOT NULL AUTO_INCREMENT, catalogSetID INT NOT NULL, chapter VARCHAR(255), sortKey INT NOT NULL, PRIMARY KEY(chapterID), INDEX(chapter) ); CREATE TABLE Catalog ( TemplID INT NOT NULL AUTO_INCREMENT, chapterID INT NOT NULL default 1, unitID INT NOT NULL, Floskel TEXT, Gewinn DECIMAL(6,2) default 0, zeitbeitrag TINYINT default 1, enterDatum DATETIME, modifyDatum TIMESTAMP, Preisart INT NOT NULL default 1, EPreis DECIMAL(10,2) default 0, PRIMARY KEY( TemplID ), INDEX ( chapterID ) ); UPDATE Catalog SET modifyDatum=enterDatum; CREATE TABLE CalcTime ( TCalcID INT NOT NULL AUTO_INCREMENT, TemplID INT NOT NULL, name VARCHAR(255), minutes INT default 0, percent INT default 0, stdHourSet INT default 0, allowGlobal INT default 1, modDate TIMESTAMP, PRIMARY KEY( TCalcID), INDEX( TemplID ) ); CREATE TABLE CalcFixed( FCalcID INT NOT NULL AUTO_INCREMENT, TemplID INT NOT NULL, name VARCHAR(255), amount DECIMAL(10,2) default 1.0, price DECIMAL(10,2), percent INT default 0, modDate TIMESTAMP, PRIMARY KEY(FCalcID), INDEX(TemplID) ); CREATE TABLE CalcMaterials( MCalcID INT NOT NULL AUTO_INCREMENT, TemplID INT NOT NULL, name VARCHAR(255), percent INT default 0, modDate TIMESTAMP, PRIMARY KEY(MCalcID), INDEX(TemplID) ); CREATE TABLE CalcMaterialDetails( MCalcDetailID INT NOT NULL AUTO_INCREMENT, CalcID INT NOT NULL, materialID INT NOT NULL, amount DECIMAL(10,2), PRIMARY KEY(MCalcDetailID), INDEX(CalcID) ); CREATE TABLE units( unitID INT NOT NULL, unitShort VARCHAR(255), unitLong VARCHAR(255), unitPluShort VARCHAR(255), unitPluLong VARCHAR(255), PRIMARY KEY(unitID), INDEX(unitShort) ); CREATE TABLE stockMaterial ( matID INT NOT NULL AUTO_INCREMENT, chapterID INT NOT NULL default 1, material mediumtext, unitID INT NOT NULL, perPack DECIMAL(10,2), priceIn DECIMAL(10,2), priceOut DECIMAL(10,2), enterDate DATETIME, modifyDate TIMESTAMP, PRIMARY KEY(matID), INDEX(chapterID) ); CREATE TABLE stdSaetze( stdSaetzeID INT NOT NULL AUTO_INCREMENT, name VARCHAR(255), price DECIMAL(10,2), sortKey int, PRIMARY KEY(stdSaetzeID) ); CREATE TABLE document( docID INT NOT NULL AUTO_INCREMENT, ident VARCHAR(32), docType VARCHAR(255), clientID VARCHAR(32), clientAddress TEXT, salut VARCHAR(255), goodbye VARCHAR(128), lastModified TIMESTAMP, date DATE, pretext TEXT, posttext TEXT, PRIMARY KEY( docID ), INDEX(ident), INDEX(clientID) ); CREATE TABLE docposition( positionID INT NOT NULL AUTO_INCREMENT, docID INT NOT NULL, ordNumber INT NOT NULL, text TEXT, amount DECIMAL(10,2), unit INT, price DECIMAL(10,2), PRIMARY KEY( positionID ), INDEX(docID), UNIQUE( docID, ordNumber) ); CREATE TABLE archdocStates( stateID INT NOT NULL AUTO_INCREMENT, state VARCHAR(32), PRIMARY KEY( stateID ) ); CREATE TABLE archdoc( archDocID INT NOT NULL AUTO_INCREMENT, ident VARCHAR(32), docType VARCHAR(255), docDescription TEXT, clientAddress TEXT, salut VARCHAR(255), goodbye VARCHAR(128), printDate TIMESTAMP, date DATE, pretext TEXT, posttext TEXT, state int, PRIMARY KEY( archDocID ), INDEX(ident) ); CREATE TABLE archdocpos( archPosID INT NOT NULL AUTO_INCREMENT, archDocID INT NOT NULL, ordNumber INT NOT NULL, text TEXT, amount DECIMAL(10,2), unit VARCHAR(64), price DECIMAL(10,2), vat DECIMAL(4,1), PRIMARY KEY( archPosID ), INDEX(archDocID), UNIQUE( archDocID, ordNumber) ); CREATE TABLE kraftsystem( dbschemaversion INT NOT NULL, updateUser VARCHAR(256) ); INSERT INTO kraftsystem ( dbschemaversion ) VALUES ( 1 ); # message Database created. kraft-1.1/database/mysql/fill_schema_de.sql000066400000000000000000000064341450127457600210540ustar00rootroot00000000000000DELETE FROM preisArten; INSERT INTO preisArten VALUES (0, 'offen'); INSERT INTO preisArten VALUES (1, 'selbsterstellt'); INSERT INTO preisArten VALUES (2, 'kalkuliert'); DELETE FROM CatalogSet; INSERT INTO CatalogSet (name, description, catalogType, sortKey) VALUES ( "Standard Mustertexte", "Kalkulierte Musterposten", "TemplCatalog", 1 ); SET @newCat := LAST_INSERT_ID(); DELETE FROM CatalogChapters; INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Arbeit', 1, @newCat ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Maschine', 2, @newCat ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Materialeinsatz', 3, @newCat ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Service', 4, @newCat ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Sonstige', 5, @newCat ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Transport', 6, @newCat ); UPDATE CatalogChapters SET catalogSetID=@newCat; INSERT INTO CatalogSet( name, description, catalogType, sortKey) VALUES ("Material", "Materialkatalog", "MaterialCatalog", 2 ); SET @newCat := LAST_INSERT_ID(); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Schüttgüter', 3, @newCat); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Naturstein', 2, @newCat); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Beton', 1, @newCat); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Rohre', 4, @newCat); DELETE FROM units; INSERT INTO units VALUES (0, 'm', 'Meter', 'm', 'Meter' ); INSERT INTO units VALUES (1, 'qm', 'Quadratmeter', 'qm', 'Quadratmeter' ); INSERT INTO units VALUES (2, 'cbm', 'Kubikmeter', 'cbm', 'Kubikmeter' ); INSERT INTO units VALUES (3, 'Sck.', 'Sack', 'Sck.', 'Saecke' ); INSERT INTO units VALUES (4, 'l', 'Liter', 'l', 'Liter' ); INSERT INTO units VALUES (5, 'kg', 'Kilogramm', 'kg', 'Kilogramm' ); INSERT INTO units VALUES (6, 'Stck.', 'Stueck', 'Stck.', 'Stueck' ); INSERT INTO units VALUES (7, 't', 'Tonne', 't', 'Tonnen' ); INSERT INTO units VALUES (8, 'pausch.', 'pauschal', 'pausch.', 'pauschal' ); INSERT INTO units VALUES (9, 'Std.', 'Stunde', 'Std.', 'Stunden' ); DELETE FROM stdSaetze; INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Geselle', 34.00, 1 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Meister', 39.00, 2 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Helfer', 30.00, 4 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Auszubildender', 21.00, 3 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Maschinenfuehrer', 33.00, 5 ); DELETE FROM wordLists; INSERT INTO wordLists VALUES ('greeting', 'mit den besten Grüssen,' ); INSERT INTO wordLists VALUES ('greeting', 'liebe Grüsse,' ); INSERT INTO wordLists VALUES ('greeting', 'Hochachtungsvoll,' ); INSERT INTO wordLists VALUES ('greeting', 'mit freundlichem Gruß,' ); INSERT INTO wordLists VALUES ('salut', 'Sehr geehrter Herr %NAME,' ); INSERT INTO wordLists VALUES ('salut', 'Sehr geehrte Frau %NAME,' ); INSERT INTO wordLists VALUES ('salut', 'Sehr geehrte Frau %NAME, sehr geehrter Herr %NAME,' ); INSERT INTO wordLists VALUES ('salut', 'Lieber %GIVEN_NAME,' ); INSERT INTO wordLists VALUES ('salut', 'Liebe %GIVEN_NAME,' ); kraft-1.1/database/mysql/fill_schema_en.sql000066400000000000000000000067301450127457600210650ustar00rootroot00000000000000DELETE FROM preisArten; INSERT INTO preisArten VALUES (0, 'open'); INSERT INTO preisArten VALUES (1, 'manual'); INSERT INTO preisArten VALUES (2, 'calculated'); DELETE FROM CatalogSet; INSERT INTO CatalogSet (name, description, catalogType, sortKey) VALUES ( "Standard Templates", "A set of templates suitable for business", "TemplCatalog", 1 ); SET @newCat := LAST_INSERT_ID(); DELETE FROM CatalogChapters; INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Work', 1, @newCat ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Machine', 2, @newCat ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Concrete', 3, @newCat ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Stones', 4, @newCat ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Misc', 5, @newCat ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Transportation', 6, @newCat ); INSERT INTO CatalogSet( name, description, catalogType, sortKey) VALUES ("Material", "Material Catalog to Use in Calculations in Templates", "MaterialCatalog", 2 ); SET @newCat := LAST_INSERT_ID(); INSERT INTO CatalogChapters ( chapter, sortKey, catalogSetID ) VALUES ('Sand etc.', 3, @newCat ); INSERT INTO CatalogChapters ( chapter, sortKey, catalogSetID ) VALUES ('Stones', 2, @newCat ); INSERT INTO CatalogChapters ( chapter, sortKey, catalogSetID ) VALUES ('Concreate', 1, @newCat ); INSERT INTO CatalogChapters ( chapter, sortKey, catalogSetID ) VALUES ('Pipes', 4, @newCat ); INSERT INTO CatalogChapters ( chapter, sortKey, catalogSetID ) VALUES ('Wood', 5, @newCat ); INSERT INTO CatalogChapters ( chapter, sortKey, catalogSetID ) VALUES ('Art and Furnitures', 6, @newCat ); DELETE FROM units; INSERT INTO units VALUES (0, 'm', 'Meter', 'm', 'Meter' ); INSERT INTO units VALUES (1, 'sm', 'Squaremeter', 'qm', 'Squaremeter' ); INSERT INTO units VALUES (2, 'cbm', 'Cubikmeter', 'cbm', 'Cubikmeter' ); INSERT INTO units VALUES (3, 'Bag.', 'Bag', 'Bag', 'Bags' ); INSERT INTO units VALUES (4, 'l', 'Liter', 'l', 'Liter' ); INSERT INTO units VALUES (5, 'kg', 'Kilogramm', 'kg', 'Kilogramm' ); INSERT INTO units VALUES (6, 'Pcs.', 'Piece', 'Pcs.', 'Pieces' ); INSERT INTO units VALUES (7, 't', 'Ton', 't', 'Tons' ); INSERT INTO units VALUES (8, 'pausch.', 'pauschal', 'pausch.', 'pauschal' ); INSERT INTO units VALUES (9, 'Hour', 'Hour', 'Hours', 'Hours' ); DELETE FROM stdSaetze; INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Worker', 34.00, 1 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Master', 39.00, 2 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Helper', 30.00, 4 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Trainee', 21.00, 3 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Machine Driver', 33.00, 5 ); DELETE FROM wordLists; INSERT INTO wordLists VALUES ('greeting', 'with kind regards,' ); INSERT INTO wordLists VALUES ('greeting', 'with best regards,' ); INSERT INTO wordLists VALUES ('greeting', 'yours faithfully,' ); INSERT INTO wordLists VALUES ('greeting', 'goodbye and thanks for the fish,' ); INSERT INTO wordLists VALUES ('greeting', 'goodbye' ); INSERT INTO wordLists VALUES ('greeting', 'forever yours,' ); INSERT INTO wordLists VALUES ('salut', 'Dear Mr. %NAME' ); INSERT INTO wordLists VALUES ('salut', 'Dear Mrs. %NAME' ); INSERT INTO wordLists VALUES ('salut', 'Dear Mrs. %NAME, dear Mr. %NAME' ); INSERT INTO wordLists VALUES ('salut', 'Dear %GIVEN_NAME' ); kraft-1.1/database/mysql/migration/000077500000000000000000000000001450127457600173775ustar00rootroot00000000000000kraft-1.1/database/mysql/migration/10_dbmigrate.sql000066400000000000000000000051221450127457600223560ustar00rootroot00000000000000# message allow laternatives and demand positions for offers SELECT @item := docTypeID FROM DocTypes WHERE name="Offer"; INSERT IGNORE INTO attributes (hostObject, hostId, name, value) VALUES ('DocType', @item, 'AllowAlternative', '1'); INSERT IGNORE INTO attributes (hostObject, hostId, name, value) VALUES ('DocType', @item, 'AllowDemand', '1'); SELECT @item := docTypeID FROM DocTypes WHERE name="Angebot"; INSERT IGNORE INTO attributes (hostObject, hostId, name, value) VALUES ('DocType', @item, 'AllowAlternative', '1'); INSERT IGNORE INTO attributes (hostObject, hostId, name, value) VALUES ('DocType', @item, 'AllowDemand', '1'); # message Add a list value identification column to the attribute table ALTER TABLE attributes ADD COLUMN valueIsList tinyint default 0 after value; DROP TABLE IF EXISTS tmp_attrib; CREATE TABLE tmp_attrib ( id INT NOT NULL AUTO_INCREMENT, hostObject VARCHAR(64), hostId INT, name VARCHAR(64), value MEDIUMTEXT, valueIsList TINYINT, PRIMARY KEY(id), UNIQUE INDEX( hostObject, hostId, name ) ); INSERT INTO tmp_attrib (hostObject, hostId, name, value, valueIsList) SELECT hostObject, hostId, name, value, 0 FROM attributes; # message Create an attribute value table CREATE TABLE IF NOT EXISTS attributeValues ( id INT NOT NULL AUTO_INCREMENT, attributeId INT NOT NULL, value VARCHAR(255), PRIMARY KEY( id ), INDEX( attributeId ) ); # message copy the attribute values over to the new attribute value table INSERT INTO attributeValues (attributeId, value) SELECT id, value FROM tmp_attrib WHERE value is not null; # message drop the attrib column ALTER TABLE tmp_attrib DROP COLUMN value; DROP TABLE IF EXISTS attribute_old; RENAME TABLE attributes TO attribute_old, tmp_attrib TO attributes; # message create a table to keep tag templates CREATE TABLE IF NOT EXISTS `tagTemplates` ( `tagTmplID` int(11) NOT NULL auto_increment, `sortkey` int(11) NOT NULL, `name` varchar(255) default NULL, `description` varchar(255) default NULL, `color` char(7) default NULL, PRIMARY KEY (`tagTmplID`), KEY `sortkey` (`sortkey`) ); INSERT IGNORE INTO tagTemplates (sortkey, name, description, color) VALUES (3, 'Discount', 'Marks items to give discount on', '#ff1c1c' ); INSERT IGNORE INTO tagTemplates (sortkey, name, description, color) VALUES (1, 'Material', 'Marks material', '#4e4e4e' ); INSERT IGNORE INTO tagTemplates (sortkey, name, description, color) VALUES (2, 'Work', 'Marks working hour items', '#ffbb39' ); INSERT IGNORE INTO tagTemplates (sortkey, name, description, color) VALUES (4, 'Plants', 'Marks plant items', '#26b913' ); kraft-1.1/database/mysql/migration/11_dbmigrate.sql000066400000000000000000000005461450127457600223640ustar00rootroot00000000000000# message Adding relation table information to attribute table ALTER TABLE attributes ADD COLUMN relationTable varchar(64) default NULL AFTER valueIsList; ALTER TABLE attributes ADD COLUMN relationIDColumn varchar(64) default NULL AFTER relationTable; ALTER TABLE attributes ADD COLUMN relationStringColumn varchar(64) default NULL AFTER relationIDColumn; kraft-1.1/database/mysql/migration/12_dbmigrate.sql000066400000000000000000000006641450127457600223660ustar00rootroot00000000000000CREATE TABLE numberCycles ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(64) NOT NULL, lastIdentNumber INT NOT NULL DEFAULT 0, identTemplate VARCHAR(64) NOT NULL DEFAULT "%i-%yyyy", PRIMARY KEY( id ), UNIQUE(name) ); SELECT @id := IF( ISNULL(MAX( docID)), 1, MAX(docID) ) FROM document; INSERT INTO numberCycles (name, lastIdentNumber) VALUES ("default", @id); kraft-1.1/database/mysql/migration/13_dbmigrate.sql000066400000000000000000000001501450127457600223550ustar00rootroot00000000000000# message Adding a taxType column ALTER TABLE docposition ADD COLUMN taxType int default 3 AFTER price; kraft-1.1/database/mysql/migration/14_dbmigrate.sql000066400000000000000000000005671450127457600223720ustar00rootroot00000000000000# message Add tax table CREATE TABLE taxes ( id INT NOT NULL AUTO_INCREMENT, fullTax DECIMAL(5,1), reducedTax DECIMAL(5,1), startDate DATE, PRIMARY KEY( id ) ); INSERT INTO taxes ( fullTax, reducedTax, startDate ) VALUES (16.0, 7.0, '1998-04-01' ); INSERT INTO taxes ( fullTax, reducedTax, startDate ) VALUES (19.0, 7.0, '2007-01-01' ); kraft-1.1/database/mysql/migration/15_dbmigrate.sql000066400000000000000000000006201450127457600223610ustar00rootroot00000000000000ALTER TABLE document ADD COLUMN projectLabel VARCHAR(255) AFTER language; ALTER TABLE archdoc ADD COLUMN projectLabel VARCHAR(255) AFTER language; ALTER TABLE archdoc ADD COLUMN tax DECIMAL(5,1) AFTER projectLabel; ALTER TABLE archdoc ADD COLUMN reducedTax DECIMAL(5,1) AFTER tax; ALTER TABLE archdocpos DROP COLUMN vat; ALTER TABLE archdocpos ADD COLUMN taxType INT DEFAULT 0 AFTER overallPrice; kraft-1.1/database/mysql/migration/16_dbmigrate.sql000066400000000000000000000013351450127457600223660ustar00rootroot00000000000000ALTER TABLE CalcMaterials RENAME TO CalcMaterialsOld; CREATE TABLE CalcMaterials ( MCalcID INT NOT NULL AUTO_INCREMENT, TemplID INT NOT NULL, materialID INT NOT NULL, percent INT DEFAULT 0, amount DECIMAL(10,2), modDate TIMESTAMP, PRIMARY KEY(MCalcID) ); INSERT INTO CalcMaterials (TemplID, materialID, amount, percent, modDate) SELECT CalcMaterialsOld.TemplID, CalcMaterialDetails.materialID, CalcMaterialDetails.amount, CalcMaterialsOld.percent, CalcMaterialsOld.modDate FROM CalcMaterialDetails INNER JOIN CalcMaterialsOld ON CalcMaterialDetails.CalcID=CalcMaterialsOld.MCalcID; DROP TABLE IF EXISTS CalcMaterialsOld; DROP TABLE IF EXISTS CalcMaterialDetails; DROP TABLE IF EXISTS attribute_old;kraft-1.1/database/mysql/migration/17_dbmigrate.sql000066400000000000000000000002021450127457600223570ustar00rootroot00000000000000ALTER TABLE CatalogChapters ADD COLUMN parentChapter int(11) default 0; ALTER TABLE CatalogChapters ADD COLUMN description text; kraft-1.1/database/mysql/migration/18_dbmigrate.sql000066400000000000000000000003341450127457600223660ustar00rootroot00000000000000# message Adding sort column and usage statistics ALTER TABLE Catalog ADD COLUMN sortKey INT(11) default 0; ALTER TABLE Catalog ADD COLUMN lastUsed DATETIME; ALTER TABLE Catalog ADD COLUMN useCounter INT(11) default 0; kraft-1.1/database/mysql/migration/19_dbmigrate.sql000066400000000000000000000025301450127457600223670ustar00rootroot00000000000000# message Create new document type delivery note INSERT INTO DocTypes (name) VALUES ('Lieferschein'); SET @lsId := LAST_INSERT_ID(); INSERT INTO attributes (hostObject, hostId, name, valueIsList) VALUES ('DocType', @lsId, 'HidePrices', 1); INSERT INTO DocTypes (name) VALUES ('Delivery Receipt'); SET @nodId := LAST_INSERT_ID(); INSERT INTO attributes (hostObject, hostId, name, valueIsList) VALUES ('DocType', @nodId, 'HidePrices', 1); # message Add more document relation settings # Lieferschein follows Angebot SELECT @item := docTypeID FROM DocTypes WHERE name="Angebot"; # mayfail INSERT INTO DocTypeRelations VALUES( @item, @lsId, 10 ); # Rechnung follows Lieferschein SELECT @follower := docTypeID FROM DocTypes WHERE name="Rechnung"; # mayfail INSERT INTO DocTypeRelations VALUES( @lsId, @follower, 11 ); # Delivery Receipt follows Offer SELECT @item := docTypeID FROM DocTypes WHERE name="Offer"; # mayfail INSERT INTO DocTypeRelations VALUES( @item, @nodId, 12 ); # Invoice follows Delivery Receipt SELECT @follower := docTypeID FROM DocTypes WHERE name="Invoice"; # mayfail INSERT INTO DocTypeRelations VALUES( @nodId, @follower, 13 ); # enhance the clientID col in document because the ids can be larger. ALTER TABLE document CHANGE COLUMN clientID clientID VARCHAR(255); ALTER TABLE archdoc CHANGE COLUMN clientUid clientUid VARCHAR(255); # Done. kraft-1.1/database/mysql/migration/20_dbmigrate.sql000066400000000000000000000004001450127457600223510ustar00rootroot00000000000000ALTER TABLE CalcTime ADD COLUMN timeUnit INT default 0; -- Add a unit id ALTER TABLE DocCalcTime ADD COLUMN timeUnit INT default 0; -- Add a unit id UPDATE CalcTime set timeUnit=0; -- Update existing CalcTime entries. UPDATE DocCalcTime set timeUnit=0; kraft-1.1/database/mysql/migration/21_dbmigrate.sql000066400000000000000000000003431450127457600223600ustar00rootroot00000000000000ALTER TABLE document ADD COLUMN predecessor VARCHAR(32) AFTER projectLabel; ALTER TABLE archdoc ADD COLUMN predecessor VARCHAR(32) AFTER projectLabel; UPDATE document SET predecessor = 0; UPDATE archdoc SET predecessor = 0; kraft-1.1/database/mysql/migration/22_dbmigrate.sql000066400000000000000000000002551450127457600223630ustar00rootroot00000000000000 INSERT INTO taxes (fullTax, reducedTax, startDate) VALUES (16.0, 5.0, '2020-07-01'); INSERT INTO taxes (fullTax, reducedTax, startDate) VALUES (19.0, 7.0, '2021-01-01'); kraft-1.1/database/mysql/migration/23_dbmigrate.sql000066400000000000000000000004611450127457600223630ustar00rootroot00000000000000ALTER TABLE stockMaterial ADD COLUMN sortKey INT default 0; CREATE TABLE catItemUsage ( catId INT NOT NULL, itemId INT NOT NULL, usageCount INT default 0, lastUsed DATETIME, PRIMARY KEY(catId, itemId) ); ALTER TABLE Catalog DROP COLUMN lastUsed; ALTER TABLE Catalog DROP COLUMN useCounter; kraft-1.1/database/mysql/migration/24_dbmigrate.sql000066400000000000000000000011721450127457600223640ustar00rootroot00000000000000 ALTER TABLE units ADD COLUMN ec20 VARCHAR(10); UPDATE units set ec20 = "MTR" WHERE unitShort = "m"; UPDATE units set ec20 = "MTK" WHERE unitShort = "qm" or unitShort = "sm"; UPDATE units set ec20 = "MTQ" WHERE unitShort = "cbm"; UPDATE units set ec20 = "XSA" WHERE unitLong = "Sack" or unitLong = "Bag"; UPDATE units set ec20 = "LTR" WHERE unitLong = "Liter"; UPDATE units set ec20 = "KGM" WHERE unitLong = "Kilogramm"; UPDATE units set ec20 = "XPP" WHERE unitShort = "Stck." or unitShort ="Pcs."; UPDATE units set ec20 = "TNE" WHERE unitShort = "t"; UPDATE units set ec20 = "HUR" WHERE unitLong = "Stunde" or unitLong ="Hour"; kraft-1.1/database/mysql/migration/2_dbmigrate.sql000066400000000000000000000021551450127457600223020ustar00rootroot00000000000000# message: Creating document position calulation tables ; CREATE TABLE DocCalcTime ( TCalcID INT NOT NULL AUTO_INCREMENT, TemplID INT NOT NULL, name VARCHAR(255), minutes INT default 0, percent INT default 0, stdHourSet INT default 0, allowGlobal INT default 1, modDate TIMESTAMP, PRIMARY KEY( TCalcID), INDEX(TemplID) ); CREATE TABLE DocCalcFixed( FCalcID INT NOT NULL AUTO_INCREMENT, TemplID INT NOT NULL, name VARCHAR(255), amount DECIMAL(10,2) default 1.0, price DECIMAL(10,2), percent INT default 0, modDate TIMESTAMP, PRIMARY KEY(FCalcID), INDEX(TemplID) ); CREATE TABLE DocCalcMaterials( MCalcID INT NOT NULL AUTO_INCREMENT, TemplID INT NOT NULL, name VARCHAR(255), percent INT default 0, modDate TIMESTAMP, PRIMARY KEY(MCalcID), INDEX(TemplID) ); CREATE TABLE DocCalcMaterialDetails( MCalcDetailID INT NOT NULL AUTO_INCREMENT, CalcID INT NOT NULL, materialID INT NOT NULL, amount DECIMAL(10,2), PRIMARY KEY(MCalcDetailID), INDEX(CalcID) ); kraft-1.1/database/mysql/migration/3_dbmigrate.sql000066400000000000000000000003421450127457600222770ustar00rootroot00000000000000CREATE TABLE plantPrices ( matchCode VARCHAR(255), price DECIMAL(8,2), lastUpdate TIMESTAMP, PRIMARY KEY( matchCode ) ); ALTER TABLE document ADD COLUMN docDescription TEXT AFTER docType; kraft-1.1/database/mysql/migration/4_dbmigrate.sql000066400000000000000000000077461450127457600223170ustar00rootroot00000000000000CREATE TABLE DocTexts ( docTextID INT NOT NULL AUTO_INCREMENT, name VARCHAR(64), description TEXT, text TEXT, docType VARCHAR( 64 ), textType VARCHAR( 64 ), modDate TIMESTAMP, PRIMARY KEY( docTextID ), INDEX( docType, textType ) ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Offer', 'Header Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Offer', 'Footer Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Invoice', 'Header Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Invoice', 'Footer Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Acceptance of Order', 'Header Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Acceptance of Order', 'Footer Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Angebot', 'Kopf Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Angebot', 'Fuß Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Rechnung', 'Kopf Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Rechnung', 'Fuß Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Auftragsbestätigung', 'Kopf Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Auftragsbestätigung', 'Fuß Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Offer', 'Footer Text' FROM wordLists WHERE category='docFooter_Offer'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Offer', 'Header Text' FROM wordLists WHERE category='docHeader_Offer'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Invoice', 'Footer Text' FROM wordLists WHERE category='docFooter_Invoice'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Invoice', 'Header Text' FROM wordLists WHERE category='docHeader_Invoice'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Acceptance of Order', 'Footer Text' FROM wordLists WHERE category='docFooter_Acceptance of Order'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Acceptance of Order', 'Header Text' FROM wordLists WHERE category='docHeader_Acceptance of Order'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Angebot', 'Fuß Text' FROM wordLists WHERE category='docFooter_Angebot'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Angebot', 'Kopf Text' FROM wordLists WHERE category='docHeader_Angebot'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Rechnung', 'Fuß Text' FROM wordLists WHERE category='docFooter_Rechnung'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Rechnung', 'Kopf Text' FROM wordLists WHERE category='docHeader_Rechnung'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Auftragsbestätigung', 'Fuß Text' FROM wordLists WHERE category='docFooter_Auftragsbestätigung'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Auftragsbestätigung', 'Kopf Text' FROM wordLists WHERE category='docHeader_Auftragsbestätigung'; kraft-1.1/database/mysql/migration/5_dbmigrate.sql000066400000000000000000000043051450127457600223040ustar00rootroot00000000000000# message Creating attributes table... CREATE TABLE attributes ( hostObject VARCHAR(64), hostId INT NOT NULL, name VARCHAR(64), value MEDIUMTEXT, PRIMARY KEY( hostObject, hostId, name ) ); # message Creating attributes for archived documents CREATE TABLE archPosAttribs ( archPosAttribId INT NOT NULL AUTO_INCREMENT, archDocID INT NOT NULL, name VARCHAR(64), value VARCHAR(64), PRIMARY KEY( archPosAttribId ) ); # message Adding position type and overall price ot archdocpositions ALTER TABLE archdocpos ADD COLUMN kind VARCHAR(64) AFTER ordNumber; ALTER TABLE archdocpos ADD COLUMN overallPrice DECIMAL(10,2) AFTER price; # message Changing old kinds to Normal UPDATE archdocpos SET kind = "Normal"; # message Calculating archive position price UPDATE archdocpos SET overallPrice = ROUND( price * amount, 2); # message Creating Document Type table CREATE TABLE DocTypes ( docTypeID INT NOT NULL AUTO_INCREMENT, name VARCHAR(255), PRIMARY KEY( docTypeID ) ); # message Filling doc type attributes INSERT INTO DocTypes (name) VALUES ( 'Offer' ); SET @dtId := LAST_INSERT_ID(); INSERT INTO attributes VALUES ('DocType', @dtId, 'AllowDemand', 'true'); INSERT INTO attributes VALUES ('DocType', @dtId, 'AllowAlternative', 'true'); INSERT INTO DocTypes (name) VALUES ( 'Acceptance of Order' ); SET @dtId := LAST_INSERT_ID(); INSERT INTO attributes VALUES ('DocType', @dtId, 'AllowDemand', 'true'); INSERT INTO attributes VALUES ('DocType', @dtId, 'AllowAlternative', 'true'); INSERT INTO DocTypes (name) VALUES ( 'Invoice' ); # message Filling doc type attributes INSERT INTO DocTypes (name) VALUES ( 'Angebot' ); SET @dtId := LAST_INSERT_ID(); INSERT INTO attributes VALUES ('DocType', @dtId, 'AllowDemand', 'true'); INSERT INTO attributes VALUES ('DocType', @dtId, 'AllowAlternative', 'true'); INSERT INTO DocTypes (name) VALUES ( 'Auftragsbestätigung' ); SET @dtId := LAST_INSERT_ID(); INSERT INTO attributes VALUES ('DocType', @dtId, 'AllowDemand', 'true'); INSERT INTO attributes VALUES ('DocType', @dtId, 'AllowAlternative', 'true'); INSERT INTO DocTypes (name) VALUES ( 'Rechnung' ); # message Drop an unused table archdocStates DROP TABLE IF EXISTS archdocStates; kraft-1.1/database/mysql/migration/6_dbmigrate.sql000066400000000000000000000004511450127457600223030ustar00rootroot00000000000000# message Localisation information on document level ALTER TABLE document ADD country VARCHAR(32) AFTER posttext; ALTER TABLE document ADD language VARCHAR(32) AFTER country; ALTER TABLE archdoc ADD country VARCHAR(32) AFTER posttext; ALTER TABLE archdoc ADD language VARCHAR(32) AFTER country; kraft-1.1/database/mysql/migration/7_dbmigrate.sql000066400000000000000000000001051450127457600223000ustar00rootroot00000000000000 ALTER TABLE archdoc ADD clientUid VARCHAR(32) AFTER clientAddress; kraft-1.1/database/mysql/migration/8_dbmigrate.sql000066400000000000000000000027711450127457600223140ustar00rootroot00000000000000 CREATE TABLE DocTypeRelations ( typeId INT NOT NULL, followerId INT NOT NULL, sequence INT NOT NULL, PRIMARY KEY( typeId, followerId ) ); # Acceptance of Order follows Offer SELECT @item := docTypeID FROM DocTypes WHERE name="Offer"; SELECT @follower := docTypeID FROM DocTypes WHERE name="Acceptance of Order"; INSERT INTO DocTypeRelations VALUES( @item, @follower, 1 ); # Invoice follorws Offer SELECT @item := docTypeID FROM DocTypes WHERE name="Offer"; SELECT @follower := docTypeID FROM DocTypes WHERE name="Invoice"; INSERT INTO DocTypeRelations VALUES( @item, @follower, 2 ); # Invoice follows Acceptance of Order SELECT @item := docTypeID FROM DocTypes WHERE name="Acceptance of Order"; SELECT @follower := docTypeID FROM DocTypes WHERE name="Invoice"; INSERT INTO DocTypeRelations VALUES( @item, @follower, 3 ); # Acceptance of Order follows Offer SELECT @item := docTypeID FROM DocTypes WHERE name="Angebot"; SELECT @follower := docTypeID FROM DocTypes WHERE name="Auftragsbestätigung"; INSERT INTO DocTypeRelations VALUES( @item, @follower, 4 ); # Invoice follorws Offer SELECT @item := docTypeID FROM DocTypes WHERE name="Angebot"; SELECT @follower := docTypeID FROM DocTypes WHERE name="Rechnung"; INSERT INTO DocTypeRelations VALUES( @item, @follower, 5 ); # Invoice follows Acceptance of Order SELECT @item := docTypeID FROM DocTypes WHERE name like "Auftragsbest%"; SELECT @follower := docTypeID FROM DocTypes WHERE name="Rechnung"; INSERT INTO DocTypeRelations VALUES( @item, @follower, 6 ); kraft-1.1/database/mysql/migration/9_dbmigrate.sql000066400000000000000000000007531450127457600223130ustar00rootroot00000000000000# message add a document type id to text table alter table DocTexts add column docTypeId int after docType; # message populate the doc type id column in docTexts update DocTexts set docTypeId=( SELECT docTypeID FROM DocTypes WHERE name=docType ); # message create a type column for the docposition alter table docposition add column postype VARCHAR(64) AFTER text; # message create type column for the archdocpos table alter table archdocpos add column postype VARCHAR(64) AFTER kind; kraft-1.1/database/mysql/migration/CMakeLists.txt000066400000000000000000000002711450127457600221370ustar00rootroot00000000000000########### install files ############### file(GLOB mig_scripts *_dbmigrate.sql) install(FILES README ${mig_scripts} DESTINATION ${DATA_INSTALL_DIR}/kraft/dbmigrate/mysql) kraft-1.1/database/mysql/migration/README000066400000000000000000000014721450127457600202630ustar00rootroot00000000000000Kraft Database Migration ======================== The Kraft database schema might change over the time. To achieve that smoothly for the users, here is a database migration system. Every version of Kraft has a hardcoded version of the required database schema version. In the Kraft database there is a system table that carries the version of the current running database schema. In case the current database version is lower than the required, Kraft looks in this migration directory if there is a script starting with the number "current version +1". If found, Kraft executes the sql commands contained in the file. After all are finished, the version in the database system table is updated. Note that the migration file my contain lines like # message: bla bla Kraft shows the message lines in the status line. kraft-1.1/database/sqlite3/000077500000000000000000000000001450127457600156255ustar00rootroot00000000000000kraft-1.1/database/sqlite3/CMakeLists.txt000066400000000000000000000003051450127457600203630ustar00rootroot00000000000000add_subdirectory(migration) ########### install files ############### install(FILES create_schema.sql fill_schema_de.sql fill_schema_en.sql DESTINATION ${DATA_INSTALL_DIR}/kraft/dbinit/sqlite3) kraft-1.1/database/sqlite3/create_schema.sql000066400000000000000000000160211450127457600211310ustar00rootroot00000000000000 CREATE TABLE preisArten ( preisArtID INTEGER PRIMARY KEY ASC autoincrement, preisArt VARCHAR(64) NOT NULL ); CREATE TABLE wordLists( category VARCHAR(64), word VARCHAR(255), PRIMARY KEY( category, word ) ); CREATE TABLE CatalogSet( catalogSetID INTEGER PRIMARY KEY ASC autoincrement, name VARCHAR(255), description VARCHAR(255), catalogType VARCHAR(64), sortKey INT NOT NULL ); CREATE TABLE CatalogChapters( chapterID INTEGER PRIMARY KEY ASC autoincrement, catalogSetID INT NOT NULL, chapter VARCHAR(255), sortKey INT NOT NULL ); CREATE INDEX chapterIndx ON CatalogChapters( chapter ); CREATE TABLE Catalog ( TemplID INTEGER PRIMARY KEY ASC autoincrement, chapterID INT NOT NULL default 1, unitID INT NOT NULL, Floskel TEXT, Gewinn DECIMAL(6,2) default 0, zeitbeitrag TINYINT default 1, enterDatum DATETIME, modifyDatum TIMESTAMP(14), Preisart INT NOT NULL default 1, EPreis DECIMAL(10,2) default 0 ); CREATE INDEX chapterIdIndx ON Catalog( chapterID ); CREATE TRIGGER insert_catalog_timeEnter AFTER INSERT ON Catalog BEGIN UPDATE Catalog SET enterDatum = DATETIME('NOW') WHERE TemplID = new.TemplID; END; CREATE TRIGGER update_catalog_timeEnter AFTER UPDATE ON Catalog BEGIN UPDATE Catalog SET modifyDatum = DATETIME('NOW') WHERE TemplID = new.TemplID; END; UPDATE Catalog SET modifyDatum=enterDatum; CREATE TABLE CalcTime ( TCalcID INTEGER PRIMARY KEY ASC autoincrement, TemplID INT NOT NULL, name VARCHAR(255), minutes INT default 0, percent INT default 0, stdHourSet INT default 0, allowGlobal INT default 1, modDate TIMESTAMP(14) ); CREATE INDEX calcTimeIndx ON CalcTime( TemplID ); CREATE TRIGGER update_calcTime_modifyDate AFTER UPDATE ON CalcTime BEGIN UPDATE CalcTime SET modDate = DATETIME('NOW') WHERE TCalcID = new.TCalcID; END; CREATE TABLE CalcFixed( FCalcID INTEGER PRIMARY KEY ASC autoincrement, TemplID INT NOT NULL, name VARCHAR(255), amount DECIMAL(10,2) default 1.0, price DECIMAL(10,2), percent INT default 0, modDate TIMESTAMP(14) ); CREATE INDEX calcFixedIndx ON CalcFixed( TemplID ); CREATE TRIGGER update_calcFixed_modifyDate AFTER UPDATE ON CalcFixed BEGIN UPDATE CalcFixed SET modDate = DATETIME('NOW') WHERE FCalcID = new.FCalcID; END; CREATE TABLE CalcMaterials( MCalcID INTEGER PRIMARY KEY ASC autoincrement, TemplID INT NOT NULL, name VARCHAR(255), percent INT default 0, modDate TIMESTAMP(14) ); CREATE INDEX calcMatIndx ON CalcMaterials( TemplID ); CREATE TRIGGER update_calcMaterials_modifyDate AFTER UPDATE ON CalcMaterials BEGIN UPDATE CalcMaterials SET modDate = DATETIME('NOW') WHERE MCalcID = new.MCalcID; END; CREATE TABLE CalcMaterialDetails( MCalcDetailID INTEGER PRIMARY KEY ASC autoincrement, CalcID INT NOT NULL, materialID INT NOT NULL, amount DECIMAL(10,2) ); CREATE INDEX calcIdIndx ON CalcMaterialDetails( CalcID ); CREATE TABLE units( unitID INTEGER PRIMARY KEY ASC autoincrement, unitShort VARCHAR(255), unitLong VARCHAR(255), unitPluShort VARCHAR(255), unitPluLong VARCHAR(255) ); CREATE INDEX unitShortIndx ON units( unitShort ); CREATE TABLE stockMaterial ( matID INTEGER PRIMARY KEY ASC autoincrement, chapterID INT NOT NULL default 1, material mediumtext, unitID INT NOT NULL, perPack DECIMAL(10,2), priceIn DECIMAL(10,2), priceOut DECIMAL(10,2), enterDate DATETIME, modifyDate TIMESTAMP(14) ); CREATE INDEX matChapterIndx ON stockMaterial( chapterID ); CREATE TRIGGER insert_material_enterDate AFTER INSERT ON stockMaterial BEGIN UPDATE stockMaterial SET enterDate = DATETIME('NOW') WHERE matID = new.matID; END; CREATE TRIGGER update_material_modifyDate AFTER UPDATE ON stockMaterial BEGIN UPDATE stockMaterial SET modifyDate = DATETIME('NOW') WHERE matID = new.matID; END; CREATE TABLE stdSaetze( stdSaetzeID INTEGER PRIMARY KEY ASC autoincrement, name VARCHAR(255), price DECIMAL(10,2), sortKey int ); CREATE TABLE document( docID INTEGER PRIMARY KEY ASC autoincrement, ident VARCHAR(32), docType VARCHAR(255), docDescription TEXT, clientID VARCHAR(32), clientAddress TEXT, salut VARCHAR(255), goodbye VARCHAR(128), lastModified TIMESTAMP, date DATE, pretext TEXT, posttext TEXT, country VARCHAR(32), language VARCHAR(32), projectLabel VARCHAR(255) ); CREATE INDEX identIndx ON document( ident ); CREATE INDEX clientIndx ON document( clientID ); CREATE TRIGGER update_document AFTER UPDATE ON document BEGIN UPDATE document SET lastModified = DATETIME('NOW') WHERE docID = new.docID; END; CREATE TABLE docposition( positionID INTEGER PRIMARY KEY ASC autoincrement, docID INT NOT NULL, ordNumber INT NOT NULL, text TEXT, postype VARCHAR(64), amount DECIMAL(10,2), unit INT, price DECIMAL(10,2), taxType INT default 3 ); CREATE INDEX docIdIndx ON docposition( docID ); CREATE UNIQUE INDEX ordIndx ON docposition( docID, ordNumber ); CREATE TABLE archdocStates( stateID INTEGER PRIMARY KEY ASC autoincrement, state VARCHAR(32) ); CREATE TABLE archdoc( archDocID INTEGER PRIMARY KEY ASC autoincrement, ident VARCHAR(32), docType VARCHAR(255), docDescription TEXT, clientAddress TEXT, clientUid VARCHAR(32), salut VARCHAR(255), goodbye VARCHAR(128), printDate TIMESTAMP, date DATE, pretext TEXT, posttext TEXT, country VARCHAR(32), language VARCHAR(32), projectLabel VARCHAR(255), tax DECIMAL(5,1), reducedTax DECIMAL(5,1), state int ); CREATE INDEX archIdentIndx ON archdoc( ident ); CREATE TRIGGER update_archdoc AFTER UPDATE ON archdoc BEGIN UPDATE archDoc SET printDate = DATETIME('NOW') WHERE archDocID = new.archDocID; END; CREATE TABLE archdocpos( archPosID INTEGER PRIMARY KEY ASC autoincrement, archDocID INT NOT NULL, ordNumber INT NOT NULL, kind VARCHAR(64), postype VARCHAR(64), text TEXT, amount DECIMAL(10,2), unit VARCHAR(64), price DECIMAL(10,2), overallPrice DECIMAL(10,2), taxType INT default 0 ); CREATE INDEX archDocIdIndx ON archdocpos( archDocID ); CREATE UNIQUE INDEX archOrdIndx ON archdocpos( archDocID, ordNumber ); CREATE TABLE kraftsystem( dbschemaversion INT NOT NULL, updateUser VARCHAR(256) ); INSERT INTO kraftsystem ( dbschemaversion ) VALUES ( 1 ); kraft-1.1/database/sqlite3/fill_schema_de.sql000066400000000000000000000106531450127457600212710ustar00rootroot00000000000000DELETE FROM preisArten; INSERT INTO preisArten (preisArt) VALUES ('offen'); INSERT INTO preisArten (preisArt) VALUES ('selbsterstellt'); INSERT INTO preisArten (preisArt) VALUES ('kalkuliert'); DELETE FROM CatalogSet; INSERT INTO CatalogSet (name, description, catalogType, sortKey) VALUES ( "Standard Mustertexte", "Kalkulierte Musterposten", "TemplCatalog", 1 ); DELETE FROM CatalogChapters; INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Arbeit', 1, (SELECT catalogSetID FROM CatalogSet WHERE name="Standard Mustertexte")); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Maschine', 2, (SELECT catalogSetID FROM CatalogSet WHERE name="Standard Mustertexte") ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Materialeinsatz', 3, (SELECT catalogSetID FROM CatalogSet WHERE name="Standard Mustertexte") ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Service', 4, (SELECT catalogSetID FROM CatalogSet WHERE name="Standard Mustertexte") ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Sonstige', 5, (SELECT catalogSetID FROM CatalogSet WHERE name="Standard Mustertexte") ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Transport', 6, (SELECT catalogSetID FROM CatalogSet WHERE name="Standard Mustertexte") ); INSERT INTO CatalogSet( name, description, catalogType, sortKey) VALUES ("Material", "Materialkatalog", "MaterialCatalog", 2 ); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Schüttgüter', 3, (SELECT catalogSetID FROM CatalogSet WHERE name="Material")); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Naturstein', 2, (SELECT catalogSetID FROM CatalogSet WHERE name="Material")); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Beton', 1, (SELECT catalogSetID FROM CatalogSet WHERE name="Material")); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Rohre', 4, (SELECT catalogSetID FROM CatalogSet WHERE name="Material")); DELETE FROM units; INSERT INTO units (unitShort, unitLong, unitPluShort, unitPluLong) VALUES ('m', 'Meter', 'm', 'Meter' ); INSERT INTO units (unitShort, unitLong, unitPluShort, unitPluLong) VALUES ('qm', 'Quadratmeter', 'qm', 'Quadratmeter' ); INSERT INTO units (unitShort, unitLong, unitPluShort, unitPluLong) VALUES ('cbm', 'Kubikmeter', 'cbm', 'Kubikmeter' ); INSERT INTO units (unitShort, unitLong, unitPluShort, unitPluLong) VALUES ('Sck.', 'Sack', 'Sck.', 'Säcke' ); INSERT INTO units (unitShort, unitLong, unitPluShort, unitPluLong) VALUES ( 'l', 'Liter', 'l', 'Liter' ); INSERT INTO units (unitShort, unitLong, unitPluShort, unitPluLong) VALUES ('kg', 'Kilogramm', 'kg', 'Kilogramm' ); INSERT INTO units (unitShort, unitLong, unitPluShort, unitPluLong) VALUES ('Stck.', 'Stueck', 'Stck.', 'Stück' ); INSERT INTO units (unitShort, unitLong, unitPluShort, unitPluLong) VALUES ('t', 'Tonne', 't', 'Tonnen' ); INSERT INTO units (unitShort, unitLong, unitPluShort, unitPluLong) VALUES ('pausch.', 'pauschal', 'pausch.', 'pauschal' ); INSERT INTO units (unitShort, unitLong, unitPluShort, unitPluLong) VALUES ('Std.', 'Stunde', 'Std.', 'Stunden' ); DELETE FROM stdSaetze; INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Geselle', 34.00, 1 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Meister', 39.00, 2 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Helfer', 30.00, 4 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Auszubildender', 21.00, 3 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Maschinenführer', 33.00, 5 ); DELETE FROM wordLists; INSERT INTO wordLists VALUES ('greeting', 'mit den besten Grüssen,' ); INSERT INTO wordLists VALUES ('greeting', 'liebe Grüsse,' ); INSERT INTO wordLists VALUES ('greeting', 'Hochachtungsvoll,' ); INSERT INTO wordLists VALUES ('greeting', 'mit freundlichem Gruß,' ); INSERT INTO wordLists VALUES ('salut', 'Sehr geehrter Herr %NAME,' ); INSERT INTO wordLists VALUES ('salut', 'Sehr geehrte Frau %NAME,' ); INSERT INTO wordLists VALUES ('salut', 'Sehr geehrte Frau %NAME, sehr geehrter Herr %NAME,' ); INSERT INTO wordLists VALUES ('salut', 'Lieber %GIVEN_NAME,' ); INSERT INTO wordLists VALUES ('salut', 'Liebe %GIVEN_NAME,' ); kraft-1.1/database/sqlite3/fill_schema_en.sql000066400000000000000000000102371450127457600213010ustar00rootroot00000000000000DELETE FROM preisArten; INSERT INTO preisArten VALUES (0, 'open'); INSERT INTO preisArten VALUES (1, 'manual'); INSERT INTO preisArten VALUES (2, 'calculated'); DELETE FROM CatalogSet; INSERT INTO CatalogSet (name, description, catalogType, sortKey) VALUES ( "Standard Templates", "A set of templates suitable for business", "TemplCatalog", 1 ); -- (SELECT catalogSetID FROM CatalogSet WHERE name="Standard Templates") DELETE FROM CatalogChapters; INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Work', 1, (SELECT catalogSetID FROM CatalogSet WHERE name="Standard Templates")); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Machine', 2, (SELECT catalogSetID FROM CatalogSet WHERE name="Standard Templates")); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Material', 3, (SELECT catalogSetID FROM CatalogSet WHERE name="Standard Templates")); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Service', 4, (SELECT catalogSetID FROM CatalogSet WHERE name="Standard Templates")); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Transportation', 5, (SELECT catalogSetID FROM CatalogSet WHERE name="Standard Templates")); INSERT INTO CatalogChapters (chapter, sortKey, catalogSetID) VALUES ('Misc', 6, (SELECT catalogSetID FROM CatalogSet WHERE name="Standard Templates")); INSERT INTO CatalogSet( name, description, catalogType, sortKey) VALUES ("Material", "Material Catalog to Use in Calculations in Templates", "MaterialCatalog", 2 ); -- (SELECT catalogSetID FROM CatalogSet WHERE name="Material") INSERT INTO CatalogChapters ( chapter, sortKey, catalogSetID ) VALUES ('Bulk Solids', 3, (SELECT catalogSetID FROM CatalogSet WHERE name="Material") ); INSERT INTO CatalogChapters ( chapter, sortKey, catalogSetID ) VALUES ('Stones', 2, (SELECT catalogSetID FROM CatalogSet WHERE name="Material")); INSERT INTO CatalogChapters ( chapter, sortKey, catalogSetID ) VALUES ('Concrete', 1, (SELECT catalogSetID FROM CatalogSet WHERE name="Material")); INSERT INTO CatalogChapters ( chapter, sortKey, catalogSetID ) VALUES ('Pipes', 4, (SELECT catalogSetID FROM CatalogSet WHERE name="Material")); INSERT INTO CatalogChapters ( chapter, sortKey, catalogSetID ) VALUES ('Wood', 5, (SELECT catalogSetID FROM CatalogSet WHERE name="Material")); INSERT INTO CatalogChapters ( chapter, sortKey, catalogSetID ) VALUES ('Art and Furnitures', 6, (SELECT catalogSetID FROM CatalogSet WHERE name="Material")); DELETE FROM units; INSERT INTO units VALUES (0, 'm', 'Meter', 'm', 'Meter' ); INSERT INTO units VALUES (1, 'sm', 'Squaremeter', 'qm', 'Squaremeter' ); INSERT INTO units VALUES (2, 'cbm', 'Cubikmeter', 'cbm', 'Cubikmeter' ); INSERT INTO units VALUES (3, 'Bag.', 'Bag', 'Bag', 'Bags' ); INSERT INTO units VALUES (4, 'l', 'Liter', 'l', 'Liter' ); INSERT INTO units VALUES (5, 'kg', 'Kilogramm', 'kg', 'Kilogramm' ); INSERT INTO units VALUES (6, 'Pcs.', 'Piece', 'Pcs.', 'Pieces' ); INSERT INTO units VALUES (7, 't', 'Ton', 't', 'Tons' ); INSERT INTO units VALUES (8, 'pausch.', 'pauschal', 'pausch.', 'pauschal' ); INSERT INTO units VALUES (9, 'Hour', 'Hour', 'Hours', 'Hours' ); DELETE FROM stdSaetze; INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Worker', 34.00, 1 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Master', 39.00, 2 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Assistant', 30.00, 4 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Trainee', 21.00, 3 ); INSERT INTO stdSaetze (name, price, sortKey) VALUES ('Machine Operator', 33.00, 5 ); DELETE FROM wordLists; INSERT INTO wordLists VALUES ('greeting', 'with kind regards,' ); INSERT INTO wordLists VALUES ('greeting', 'with best regards,' ); INSERT INTO wordLists VALUES ('greeting', 'yours faithfully,' ); INSERT INTO wordLists VALUES ('greeting', 'goodbye and thanks for the fish,' ); INSERT INTO wordLists VALUES ('greeting', 'goodbye' ); INSERT INTO wordLists VALUES ('salut', 'Dear Mr. %NAME' ); INSERT INTO wordLists VALUES ('salut', 'Dear Mrs. %NAME' ); INSERT INTO wordLists VALUES ('salut', 'Dear Mrs. %NAME, dear Mr. %NAME' ); INSERT INTO wordLists VALUES ('salut', 'Dear %GIVEN_NAME' ); kraft-1.1/database/sqlite3/migration/000077500000000000000000000000001450127457600176165ustar00rootroot00000000000000kraft-1.1/database/sqlite3/migration/10_dbmigrate.sql000066400000000000000000000050431450127457600225770ustar00rootroot00000000000000-- 5_dbmigrate.sql -- message Add a list value identification column to the attribute table --ALTER TABLE attributes ADD COLUMN valueIsList tinyint default 0; -- AFTER value; DROP TABLE IF EXISTS tmp_attrib; CREATE TABLE tmp_attrib ( id INTEGER PRIMARY KEY ASC autoincrement, hostObject VARCHAR(64), hostId INT, name VARCHAR(64), value MEDIUMTEXT, valueIsList TINYINT ); -- CREATE UNIQUE INDEX tmpIndx_10 ON tmp_attrib( hostObject, hostId, name ); INSERT INTO tmp_attrib (hostObject, hostId, name, value, valueIsList) SELECT hostObject, hostId, name, value, 0 FROM attributes; -- message Create an attribute value table CREATE TABLE IF NOT EXISTS attributeValues ( id INTEGER PRIMARY KEY ASC autoincrement, attributeId INT NOT NULL, value VARCHAR(255) ); CREATE INDEX attribValueIndx_10 ON attributeValues( attributeId ); -- message copy the attribute values over to the new attribute value table INSERT INTO attributeValues (attributeId, value) SELECT id, value FROM tmp_attrib WHERE value is not null; -- message drop the attrib column -- ALTER TABLE tmp_attrib DROP COLUMN value; -- DROP TABLE attributes; ALTER TABLE attributes RENAME TO attributes_unused; CREATE TABLE attributes ( id INTEGER PRIMARY KEY ASC autoincrement, hostObject VARCHAR(64), hostId INT, name VARCHAR(64), valueIsList TINYINT, relationTable varchar(64) default NULL, relationIDColumn varchar(64) default NULL, relationStringColumn varchar(64) default NULL ); CREATE UNIQUE INDEX attribIndx_10 ON attributes( hostObject, hostId, name ); INSERT INTO attributes (hostObject, hostId, name, valueIsList) SELECT hostObject, hostId, name, valueIsList FROM tmp_attrib; -- message create a table to keep tag templates CREATE TABLE IF NOT EXISTS tagTemplates ( tagTmplID INTEGER PRIMARY KEY ASC autoincrement, sortkey int NOT NULL, name varchar(255) default NULL, description varchar(255) default NULL, color char(7) default NULL ); INSERT INTO tagTemplates (sortkey, name, description, color) VALUES (3, 'Discount', 'Marks items to give discount on', '#ff1c1c' ); INSERT INTO tagTemplates (sortkey, name, description, color) VALUES (1, 'Material', 'Marks material', '#4e4e4e' ); INSERT INTO tagTemplates (sortkey, name, description, color) VALUES (2, 'Work', 'Marks working hour items', '#ffbb39' ); INSERT INTO tagTemplates (sortkey, name, description, color) VALUES (4, 'Plants', 'Marks plant items', '#26b913' ); DROP TABLE IF EXISTS tmp_attrib; DROP TABLE IF EXISTS attributes_unused; kraft-1.1/database/sqlite3/migration/11_dbmigrate.sql000066400000000000000000000006671450127457600226070ustar00rootroot00000000000000-- Columns already added in 5_dbmigrate.sql *sqlite workaround* -- message Adding relation table information to attribute table --ALTER TABLE attributes ADD COLUMN relationTable varchar(64) default NULL -- AFTER valueIsList; --ALTER TABLE attributes ADD COLUMN relationIDColumn varchar(64) default NULL; -- AFTER relationTable; --ALTER TABLE attributes ADD COLUMN relationStringColumn varchar(64) default NULL; -- AFTER relationIDColumn;kraft-1.1/database/sqlite3/migration/12_dbmigrate.sql000066400000000000000000000007011450127457600225750ustar00rootroot00000000000000CREATE TABLE numberCycles ( id INTEGER PRIMARY KEY ASC autoincrement, name VARCHAR(64) NOT NULL, lastIdentNumber INT NOT NULL, identTemplate VARCHAR(64) NOT NULL ); CREATE UNIQUE INDEX numCycleIdx_12 ON numberCycles( name ); INSERT INTO numberCycles (name, lastIdentNumber, identTemplate) VALUES ("default", (SELECT ifnull( 1+MAX(docID), 1 ) FROM document), '%i-%yyyy' ); kraft-1.1/database/sqlite3/migration/13_dbmigrate.sql000066400000000000000000000002571450127457600226040ustar00rootroot00000000000000--Column already added in create_schema.sql *Sqlite workaround* -- message Adding a taxType column --ALTER TABLE docposition ADD COLUMN taxType int default 3; -- AFTER price; kraft-1.1/database/sqlite3/migration/14_dbmigrate.sql000066400000000000000000000005531450127457600226040ustar00rootroot00000000000000-- message Add tax table CREATE TABLE taxes ( id INTEGER PRIMARY KEY ASC autoincrement, fullTax DECIMAL(5,1), reducedTax DECIMAL(5,1), startDate DATE ); INSERT INTO taxes ( fullTax, reducedTax, startDate ) VALUES (16.0, 7.0, '1998-04-01' ); INSERT INTO taxes ( fullTax, reducedTax, startDate ) VALUES (19.0, 7.0, '2007-01-01' ); kraft-1.1/database/sqlite3/migration/15_dbmigrate.sql000066400000000000000000000007451450127457600226100ustar00rootroot00000000000000-- message Add project label and tax to archive --ALTER TABLE document ADD COLUMN projectLabel VARCHAR(255); -- AFTER language; --ALTER TABLE archdoc ADD COLUMN projectLabel VARCHAR(255); -- AFTER language; --ALTER TABLE archdoc ADD COLUMN tax DECIMAL(5,1); -- AFTER projectLabel; --ALTER TABLE archdoc ADD COLUMN reducedTax DECIMAL(5,1); -- AFTER tax; -- ALTER TABLE archdocpos DROP COLUMN vat; --ALTER TABLE archdocpos ADD COLUMN taxType INT DEFAULT 0; -- AFTER overallPrice; kraft-1.1/database/sqlite3/migration/16_dbmigrate.sql000066400000000000000000000012561450127457600226070ustar00rootroot00000000000000ALTER TABLE CalcMaterials RENAME TO CalcMaterialsOld; CREATE TABLE CalcMaterials ( MCalcID INTEGER PRIMARY KEY ASC autoincrement, TemplID INT NOT NULL, materialID INT NOT NULL, percent INT DEFAULT 0, amount DECIMAL(10,2), modDate TIMESTAMP(14) ); INSERT INTO CalcMaterials (TemplID, materialID, amount, percent, modDate) SELECT CalcMaterialsOld.TemplID, CalcMaterialDetails.materialID, CalcMaterialDetails.amount, CalcMaterialsOld.percent, CalcMaterialsOld.modDate FROM CalcMaterialDetails INNER JOIN CalcMaterialsOld ON CalcMaterialDetails.CalcID=CalcMaterialsOld.MCalcID; DROP TABLE IF EXISTS CalcMaterialsOld; DROP TABLE IF EXISTS CalcMaterialDetails;kraft-1.1/database/sqlite3/migration/17_dbmigrate.sql000066400000000000000000000002011450127457600225750ustar00rootroot00000000000000ALTER TABLE CatalogChapters ADD COLUMN parentChapter int(11) default 0; ALTER TABLE CatalogChapters ADD COLUMN description text; kraft-1.1/database/sqlite3/migration/18_dbmigrate.sql000066400000000000000000000002431450127457600226040ustar00rootroot00000000000000 ALTER TABLE Catalog ADD COLUMN sortKey INT default 0; ALTER TABLE Catalog ADD COLUMN lastUsed DATETIME; ALTER TABLE Catalog ADD COLUMN useCounter INT default 0; kraft-1.1/database/sqlite3/migration/19_dbmigrate.sql000066400000000000000000000024661450127457600226160ustar00rootroot00000000000000 # message Create new document type delivery note INSERT INTO DocTypes (name) VALUES ('Lieferschein'); INSERT INTO attributes (hostObject, hostId, name, valueIsList) VALUES ('DocType', (SELECT docTypeID FROM DocTypes WHERE name='Lieferschein'), 'HidePrices', 'true'); INSERT INTO DocTypes (name) VALUES ('Delivery Receipt'); INSERT INTO attributes (hostObject, hostId, name, valueIsList) VALUES ('DocType', (SELECT docTypeID FROM DocTypes WHERE name='Delivery Receipt'), 'HidePrices', 'true'); # Delivery Receipt follows Offer # mayfail # message Add more document relation settings INSERT INTO DocTypeRelations VALUES( (SELECT docTypeID FROM DocTypes WHERE name="Offer"), (SELECT docTypeID FROM DocTypes WHERE name="Delivery Receipt"), 12 ); # mayfail INSERT INTO DocTypeRelations VALUES( (SELECT docTypeID FROM DocTypes WHERE name="Delivery Receipt"), (SELECT docTypeID FROM DocTypes WHERE name="Invoice"), 13 ); # Lieferschein follows Angebot # mayfail INSERT INTO DocTypeRelations VALUES( (SELECT docTypeID FROM DocTypes WHERE name="Angebot"), (SELECT docTypeID FROM DocTypes WHERE name="Lieferschein"), 10 ); # Rechnung follows Lieferschein # mayfail INSERT INTO DocTypeRelations VALUES( (SELECT docTypeID FROM DocTypes WHERE name="Lieferschein"), (SELECT docTypeID FROM DocTypes WHERE name="Rechnung"), 11 ); # Done. kraft-1.1/database/sqlite3/migration/20_dbmigrate.sql000066400000000000000000000004021450127457600225720ustar00rootroot00000000000000 ALTER TABLE CalcTime ADD COLUMN timeUnit INT default 0; -- Add a unit id ALTER TABLE DocCalcTime ADD COLUMN timeUnit INT default 0; -- Add a unit id UPDATE CalcTime set timeUnit=0; -- Update existing CalcTime entries. UPDATE DocCalcTime set timeUnit=0; kraft-1.1/database/sqlite3/migration/21_dbmigrate.sql000066400000000000000000000002471450127457600226020ustar00rootroot00000000000000--- Add a column predecessor to the document table ALTER TABLE document ADD COLUMN predecessor VARCHAR(32); ALTER TABLE archdoc ADD COLUMN predecessor VARCHAR(32); kraft-1.1/database/sqlite3/migration/22_dbmigrate.sql000066400000000000000000000002551450127457600226020ustar00rootroot00000000000000 INSERT INTO taxes (fullTax, reducedTax, startDate) VALUES (16.0, 5.0, '2020-07-01'); INSERT INTO taxes (fullTax, reducedTax, startDate) VALUES (19.0, 7.0, '2021-01-01'); kraft-1.1/database/sqlite3/migration/23_dbmigrate.sql000066400000000000000000000007141450127457600226030ustar00rootroot00000000000000ALTER TABLE stockMaterial ADD COLUMN sortKey INT default 0; CREATE TABLE catItemUsage ( catId INT NOT NULL, itemId INT NOT NULL, usageCount INT default 0, lastUsed DATETIME, PRIMARY KEY(catId, itemId) ); -- These statements are only supported starting from 3.35 -- https://sqlite.org/changes.html#version_3_35_0 -- rather disabled for now for robustness -- ALTER TABLE Catalog DROP COLUMN lastUsed; -- ALTER TABLE Catalog DROP COLUMN useCounter; kraft-1.1/database/sqlite3/migration/24_dbmigrate.sql000066400000000000000000000011721450127457600226030ustar00rootroot00000000000000 ALTER TABLE units ADD COLUMN ec20 VARCHAR(10); UPDATE units set ec20 = "MTR" WHERE unitShort = "m"; UPDATE units set ec20 = "MTK" WHERE unitShort = "qm" or unitShort = "sm"; UPDATE units set ec20 = "MTQ" WHERE unitShort = "cbm"; UPDATE units set ec20 = "XSA" WHERE unitLong = "Sack" or unitLong = "Bag"; UPDATE units set ec20 = "LTR" WHERE unitLong = "Liter"; UPDATE units set ec20 = "KGM" WHERE unitLong = "Kilogramm"; UPDATE units set ec20 = "XPP" WHERE unitShort = "Stck." or unitShort ="Pcs."; UPDATE units set ec20 = "TNE" WHERE unitShort = "t"; UPDATE units set ec20 = "HUR" WHERE unitLong = "Stunde" or unitLong ="Hour"; kraft-1.1/database/sqlite3/migration/2_dbmigrate.sql000066400000000000000000000034041450127457600225170ustar00rootroot00000000000000-- message: Creating document position calulation tables ; CREATE TABLE DocCalcTime ( TCalcID INTEGER PRIMARY KEY ASC autoincrement, TemplID INT NOT NULL, name VARCHAR(255), minutes INT default 0, percent INT default 0, stdHourSet INT default 0, allowGlobal INT default 1, modDate TIMESTAMP(14) ); CREATE INDEX calcTimeTemplIndx_2 ON DocCalcTime( TemplID ); CREATE TRIGGER update_docCalcTime_modDate AFTER UPDATE ON DocCalcTime BEGIN UPDATE DocCalcTime SET modDate = DATETIME('NOW') WHERE TCalcID = new.TCalcID; END; CREATE TABLE DocCalcFixed( FCalcID INTEGER PRIMARY KEY ASC autoincrement, TemplID INT NOT NULL, name VARCHAR(255), amount DECIMAL(10,2) default 1.0, price DECIMAL(10,2), percent INT default 0, modDate TIMESTAMP(14) ); CREATE INDEX CalcFixedTemplIndx_2 ON DocCalcFixed( TemplID ); CREATE TRIGGER update_docCalcFixed_modDate AFTER UPDATE ON DocCalcFixed BEGIN UPDATE DocCalcFixed SET modDate = DATETIME('NOW') WHERE FCalcID = new.FCalcID; END; CREATE TABLE DocCalcMaterials( MCalcID INTEGER PRIMARY KEY ASC autoincrement, TemplID INT NOT NULL, name VARCHAR(255), percent INT default 0, modDate TIMESTAMP(14) ); CREATE INDEX CalcMaterialTemplIndx_2 ON DocCalcMaterials( TemplID ); CREATE TRIGGER update_docCalcMaterials_modDate AFTER UPDATE ON DocCalcMaterials BEGIN UPDATE DocCalcMaterials SET modDate = DATETIME('NOW') WHERE MCalcID = new.MCalcID; END; CREATE TABLE DocCalcMaterialDetails( MCalcDetailID INTEGER PRIMARY KEY ASC autoincrement, CalcID INT NOT NULL, materialID INT NOT NULL, amount DECIMAL(10,2) ); CREATE INDEX CalcMaterialDetailsCalcIDIndx_2 ON DocCalcMaterialDetails( CalcID ); kraft-1.1/database/sqlite3/migration/3_dbmigrate.sql000066400000000000000000000007541450127457600225250ustar00rootroot00000000000000-- message Add plant Prices table CREATE TABLE plantPrices ( matchCode VARCHAR(255), price DECIMAL(8,2), lastUpdate TIMESTAMP, PRIMARY KEY( matchCode ) ); CREATE TRIGGER update_plantPrices AFTER UPDATE ON plantPrices BEGIN UPDATE plantPrices SET lastUpdate = DATETIME('NOW') WHERE matchCode = new.matchCode; END; -- Columns already added in create_schema.sql *sqlite workaround* --ALTER TABLE document ADD COLUMN docDescription TEXT AFTER docType; kraft-1.1/database/sqlite3/migration/4_dbmigrate.sql000066400000000000000000000103421450127457600225200ustar00rootroot00000000000000-- message Create DocTexts table CREATE TABLE DocTexts ( docTextID INTEGER PRIMARY KEY ASC autoincrement, name VARCHAR(64), description TEXT, text TEXT, docType VARCHAR( 64 ), docTypeId int, textType VARCHAR( 64 ), modDate TIMESTAMP(14) -- INDEX( docType, textType ) ); CREATE INDEX DocTextsIndx_4 ON DocTexts (docType, textType); CREATE TRIGGER update_docTexts AFTER UPDATE ON DocTexts BEGIN UPDATE DocTexts SET modDate = DATETIME('NOW') WHERE docTextID = new.docTextID; END; INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Offer', 'Header Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Offer', 'Footer Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Invoice', 'Header Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Invoice', 'Footer Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Acceptance of Order', 'Header Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Acceptance of Order', 'Footer Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Angebot', 'Kopf Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Angebot', 'Fuß Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Rechnung', 'Kopf Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Rechnung', 'Fuß Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Auftragsbestätigung', 'Kopf Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) VALUES ( 'Standard', 'Please edit me - Bitte passe mich an!', 'Auftragsbestätigung', 'Fuß Text' ); INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Offer', 'Footer Text' FROM wordLists WHERE category='docFooter_Offer'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Offer', 'Header Text' FROM wordLists WHERE category='docHeader_Offer'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Invoice', 'Footer Text' FROM wordLists WHERE category='docFooter_Invoice'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Invoice', 'Header Text' FROM wordLists WHERE category='docHeader_Invoice'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Acceptance of Order', 'Footer Text' FROM wordLists WHERE category='docFooter_Acceptance of Order'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Acceptance of Order', 'Header Text' FROM wordLists WHERE category='docHeader_Acceptance of Order'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Angebot', 'Fuß Text' FROM wordLists WHERE category='docFooter_Angebot'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Angebot', 'Kopf Text' FROM wordLists WHERE category='docHeader_Angebot'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Rechnung', 'Fuß Text' FROM wordLists WHERE category='docFooter_Rechnung'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Rechnung', 'Kopf Text' FROM wordLists WHERE category='docHeader_Rechnung'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Auftragsbestätigung', 'Fuß Text' FROM wordLists WHERE category='docFooter_Auftragsbestätigung'; INSERT INTO DocTexts ( name, text, docType, textType ) SELECT 'Standard', word, 'Auftragsbestätigung', 'Kopf Text' FROM wordLists WHERE category='docHeader_Auftragsbestätigung'; kraft-1.1/database/sqlite3/migration/5_dbmigrate.sql000066400000000000000000000060371450127457600225270ustar00rootroot00000000000000-- message Creating attributes table... CREATE TABLE attributes ( hostObject VARCHAR(64), hostId INT NOT NULL, name VARCHAR(64), value MEDIUMTEXT, valueIsList tinyint default 0, relationTable VARCHAR(64) default NULL, relationIDColumn VARCHAR(64) default NULL, relationStringColumn VARCHAR(64) default NULL, PRIMARY KEY( hostObject, hostId, name ) ); -- message Creating attributes for archived documents CREATE TABLE archPosAttribs ( archPosAttribId INTEGER PRIMARY KEY ASC autoincrement, archDocID INT NOT NULL, name VARCHAR(64), value VARCHAR(64) ); -- Columns already added in create_schema.sql *sqlite workaround* -- message Adding position type and overall price ot archdocpositions --ALTER TABLE archdocpos ADD COLUMN kind VARCHAR(64); -- AFTER ordNumber; --ALTER TABLE archdocpos ADD COLUMN overallPrice DECIMAL(10,2); -- AFTER price; -- message Changing old kinds to Normal UPDATE archdocpos SET kind = "Normal"; -- message Calculating archive position price UPDATE archdocpos SET overallPrice = ROUND( price * amount, 2); -- message Creating Document Type table CREATE TABLE DocTypes ( docTypeID INTEGER PRIMARY KEY ASC autoincrement, name VARCHAR(255) ); -- message Filling doc type attributes INSERT INTO DocTypes (name) VALUES ( 'Offer' ); INSERT INTO attributes (hostObject, hostId, name, value) VALUES ('DocType', (SELECT docTypeID FROM DocTypes WHERE name="Offer"), 'AllowDemand', 'true'); INSERT INTO attributes (hostObject, hostId, name, value) VALUES ('DocType', (SELECT docTypeID FROM DocTypes WHERE name="Offer"), 'AllowAlternative', 'true'); INSERT INTO DocTypes (name) VALUES ( 'Acceptance of Order' ); INSERT INTO attributes (hostObject, hostId, name, value) VALUES ('DocType', (SELECT docTypeID FROM DocTypes WHERE name="Acceptance of Order"), 'AllowDemand', 'true'); INSERT INTO attributes (hostObject, hostId, name, value) VALUES ('DocType', (SELECT docTypeID FROM DocTypes WHERE name="Acceptance of Order"), 'AllowAlternative', 'true'); INSERT INTO DocTypes (name) VALUES ( 'Invoice' ); -- message Filling doc type attributes INSERT INTO DocTypes (name) VALUES ( 'Angebot' ); INSERT INTO attributes (hostObject, hostId, name, value) VALUES ('DocType', (SELECT docTypeID FROM DocTypes WHERE name="Angebot"), 'AllowDemand', 'true'); INSERT INTO attributes (hostObject, hostId, name, value) VALUES ('DocType', (SELECT docTypeID FROM DocTypes WHERE name="Angebot"), 'AllowAlternative', 'true'); INSERT INTO DocTypes (name) VALUES ( 'Auftragsbestätigung' ); INSERT INTO attributes (hostObject, hostId, name, value) VALUES ('DocType', (SELECT docTypeID FROM DocTypes WHERE name="Auftragsbestätigung"), 'AllowDemand', 'true'); INSERT INTO attributes (hostObject, hostId, name, value) VALUES ('DocType', (SELECT docTypeID FROM DocTypes WHERE name="Auftragsbestätigung"), 'AllowAlternative', 'true'); INSERT INTO DocTypes (name) VALUES ( 'Rechnung' ); -- message Drop an unused table archdocStates DROP TABLE IF EXISTS archdocStates; kraft-1.1/database/sqlite3/migration/6_dbmigrate.sql000066400000000000000000000004771450127457600225320ustar00rootroot00000000000000-- message Localisation information on document level --ALTER TABLE document ADD country VARCHAR(32); -- AFTER posttext; --ALTER TABLE document ADD language VARCHAR(32);-- AFTER country; --ALTER TABLE archdoc ADD country VARCHAR(32);-- AFTER posttext; --ALTER TABLE archdoc ADD language VARCHAR(32);-- AFTER country; kraft-1.1/database/sqlite3/migration/7_dbmigrate.sql000066400000000000000000000002141450127457600225200ustar00rootroot00000000000000-- Columns already added in create_schema.sql *sqlite workaround* -- ALTER TABLE archdoc ADD clientUid VARCHAR(32);-- AFTER clientAddress;kraft-1.1/database/sqlite3/migration/8_dbmigrate.sql000066400000000000000000000053051450127457600225270ustar00rootroot00000000000000-- message Create Document Relations Table CREATE TABLE DocTypeRelations ( typeId INT NOT NULL, followerId INT NOT NULL, sequence INT NOT NULL, PRIMARY KEY( typeId, followerId ) ); -- Acceptance of Order follows Offer -- SELECT @item := docTypeID FROM DocTypes WHERE name="Offer"; -- SELECT @follower := docTypeID FROM DocTypes WHERE name="Acceptance of Order"; INSERT INTO DocTypeRelations VALUES( (SELECT docTypeID FROM DocTypes WHERE name="Offer"), (SELECT docTypeID FROM DocTypes WHERE name="Acceptance of Order"), 1 ); -- Invoice follorws Offer -- SELECT @item := docTypeID FROM DocTypes WHERE name="Offer"; -- SELECT @follower := docTypeID FROM DocTypes WHERE name="Invoice"; -- INSERT INTO DocTypeRelations VALUES( @item, @follower, 2 ); INSERT INTO DocTypeRelations VALUES( (SELECT docTypeID FROM DocTypes WHERE name="Offer"), (SELECT docTypeID FROM DocTypes WHERE name="Invoice"), 2 ); -- Invoice follows Acceptance of Order -- SELECT @item := docTypeID FROM DocTypes WHERE name="Acceptance of Order"; -- SELECT @follower := docTypeID FROM DocTypes WHERE name="Invoice"; -- INSERT INTO DocTypeRelations VALUES( @item, @follower, 3 ); INSERT INTO DocTypeRelations VALUES( (SELECT docTypeID FROM DocTypes WHERE name="Acceptance of Order"), (SELECT docTypeID FROM DocTypes WHERE name="Invoice"), 3 ); -- Acceptance of Order follows Offer -- SELECT @item := docTypeID FROM DocTypes WHERE name="Angebot"; -- SELECT @follower := docTypeID FROM DocTypes WHERE name="Auftragsbestätigung"; -- INSERT INTO DocTypeRelations VALUES( @item, @follower, 4 ); INSERT INTO DocTypeRelations VALUES( (SELECT docTypeID FROM DocTypes WHERE name="Angebot"), (SELECT docTypeID FROM DocTypes WHERE name="Auftragsbestätigung"), 4 ); -- Invoice follorws Offer -- SELECT @item := docTypeID FROM DocTypes WHERE name="Angebot"; -- SELECT @follower := docTypeID FROM DocTypes WHERE name="Rechnung"; -- INSERT INTO DocTypeRelations VALUES( @item, @follower, 5 ); INSERT INTO DocTypeRelations VALUES( (SELECT docTypeID FROM DocTypes WHERE name="Angebot"), (SELECT docTypeID FROM DocTypes WHERE name="Rechnung"), 5 ); -- Invoice follows Acceptance of Order -- SELECT @item := docTypeID FROM DocTypes WHERE name like "Auftragsbest%"; -- SELECT @follower := docTypeID FROM DocTypes WHERE name="Rechnung"; -- INSERT INTO DocTypeRelations VALUES( @item, @follower, 6 ); INSERT INTO DocTypeRelations VALUES( (SELECT docTypeID FROM DocTypes WHERE name="Auftragsbestätigung"), (SELECT docTypeID FROM DocTypes WHERE name="Rechnung"), 6 ); kraft-1.1/database/sqlite3/migration/9_dbmigrate.sql000066400000000000000000000012071450127457600225250ustar00rootroot00000000000000-- Columns already added in 4_dbmigrate.sql *sqlite workaround* -- message add a document type id to text table --alter table DocTexts add column docTypeId int; -- AFTER docType; -- message populate the doc type id column in docTexts update DocTexts set docTypeId=(SELECT docTypeID FROM DocTypes WHERE name=docType); -- Columns already added in create_schema.sql *sqlite workaround* -- message create a type column for the docposition --alter table docposition add column postype VARCHAR(64); -- AFTER text; -- message create type column for the archdocpos table --alter table archdocpos add column postype VARCHAR(64); -- AFTER kind; kraft-1.1/database/sqlite3/migration/CMakeLists.txt000066400000000000000000000002531450127457600223560ustar00rootroot00000000000000########### install files ############### file(GLOB mig_scripts *_dbmigrate.sql) install(FILES ${mig_scripts} DESTINATION ${DATA_INSTALL_DIR}/kraft/dbmigrate/sqlite3) kraft-1.1/database/sqlite3/migration/README000066400000000000000000000014731450127457600205030ustar00rootroot00000000000000Kraft Database Migration ======================== The Kraft database schema might change over the time. To achieve that smoothly for the users, here is a database migration system. Every version of Kraft has a hardcoded version of the required database schema version. In the Kraft database there is a system table that carries the version of the current running database schema. In case the current database version is lower than the required, Kraft looks in this migration directory if there is a script starting with the number "current version +1". If found, Kraft executes the sql commands contained in the file. After all are finished, the version in the database system table is updated. Note that the migration file my contain lines like -- message: bla bla Kraft shows the message lines in the status line. kraft-1.1/importfilter/000077500000000000000000000000001450127457600152155ustar00rootroot00000000000000kraft-1.1/importfilter/CMakeLists.txt000066400000000000000000000002321450127457600177520ustar00rootroot00000000000000########### install files ############### install(FILES woerlein_txt.ftr standard_txt.ftr DESTINATION ${DATA_INSTALL_DIR}/kraft/importfilter/positions/) kraft-1.1/importfilter/standard_txt.ftr000066400000000000000000000003321450127457600204270ustar00rootroot00000000000000AMOUNT: COL(1) UNIT: COL(2) TEXT: COL(3) UNIT_PRICE: COL(4) NAME: Standard Import DESCRIPTION: Simple Standard Importfilter for four columns:
Amount, Unit, Text, Single Price ENCODING: windows-1250 SEPARATOR: ; kraft-1.1/importfilter/woerlein_txt.ftr000066400000000000000000000005401450127457600204540ustar00rootroot00000000000000AMOUNT: COL(1) TEXT: COL(2) - COL(3)
COL(4), COL(5) cm
Rabatt: COL(7)% # TEXT: "%s - %s\n%s, %s\n%s", COL(2), COL(3), COL(4), COL(5), COL(7) UNIT: Stck. UNIT_PRICE: COL(6) NAME: Wörlein Pflanzenkatalog Export DESCRIPTION: Importfilter for CSV exported Wörlein Pflanzenkatalog documents ENCODING: windows-1250 SEPARATOR: ; TAGS: plants kraft-1.1/manual/000077500000000000000000000000001450127457600137525ustar00rootroot00000000000000kraft-1.1/manual/CMakeLists.txt000066400000000000000000000021131450127457600165070ustar00rootroot00000000000000 FIND_PACKAGE(Asciidoctor) SET (install_files kraft-en.html kraft-de.html) if (ASCIIDOCTOR_FOUND) SET( manual_src ${PROJECT_SOURCE_DIR}/manual/kraft.adoc ) SET( out_file kraft-en.html ) ADD_CUSTOM_COMMAND( OUTPUT "${out_file}" COMMAND "${PROJECT_SOURCE_DIR}/manual/makeman.sh" ARGS "${PROJECT_SOURCE_DIR}/manual" DEPENDS ${manual_src} COMMENT "Make the manual" ) message( "Asciidoctor found") ADD_CUSTOM_TARGET(manual ALL echo DEPENDS "${out_file}" ) INSTALL(FILES ${CMAKE_BINARY_DIR}/manual/kraft-en.html ${CMAKE_BINARY_DIR}/manual/kraft-de.html ${CMAKE_BINARY_DIR}/manual/kraft-nl.html DESTINATION ${DATA_INSTALL_DIR}/kraft/manual) else(ASCIIDOCTOR_FOUND) # Maybe there are preinstalled html files in the tarball message("Asciidoctor not found, installing pre built manual.") install(FILES "kraft-de.html" "kraft-en.html" DESTINATION ${DATA_INSTALL_DIR}/kraft/manual) endif(ASCIIDOCTOR_FOUND) INSTALL(FILES kraftmanual.css DESTINATION ${DATA_INSTALL_DIR}/kraft/manual) INSTALL(DIRECTORY images DESTINATION ${DATA_INSTALL_DIR}/kraft/manual) kraft-1.1/manual/Readme.md000066400000000000000000000047631450127457600155030ustar00rootroot00000000000000## How to Contribute There are two ways to contribute to the user manual of Kraft. ### Work on the English Manual Just improve the English Manual that is stored in the file `kraft.adoc` in this directory. With that you can concentrate on writing and do not deal with scripting etc. Content rules! Please send your changes either as pull request, or via email to the project maintainers. They will care for the rest. Every change that is done to the master document in English language will be translated to all the other internationalized versions of the doc. ### Translate The translations of Kraft will be maintained on Transifex, just like the normal software strings. Check there for translation tasks. ## Internationalization of the Manual This is based on the great [doc here](https://github.com/KiCad/kicad-doc/blob/master/doc_alternatives/README.adoc). The process of internationalization of the Kraft Manual is done in different steps. It relies on the the same gettext process that is also used for the normal software strings. To extract the strings from the manual, the great utility po4a is used. ### Step 1: String Template Extraction This is extracting strings ready for the gettext system. This needs only to be done once. Later, the pot file is only going to be updated. ``` po4a-gettextize -f asciidoc -M utf-8 -m kraft.adoc -p po/kraft.pot ``` The update works with the command msgmerge: ``` msgmerge -vU kraft-de.po kraft.pot ``` ### Step 2: Translation Copy the template into the nationalized version: `cp po/kraft.pot po/kraft-de.po` and use the gettext editor you like or upload to Transifex. Keep in mind that snapshots images should be nationalized. I suggest to create a internationalized image dirs such as: ``` images images-de images-es ``` This way untranslated images fallback to English images. po4a correctly translate image reference to enable the fallback. ### Step 3: Produce Internationalized Master Documents ``` po4a-translate -f asciidoc -M utf-8 -m kraft.adoc -p po/kraft-de.po -k 0 -l kraft-de.adoc ``` ### Step 4: Produce all Kind of Internationalized Output Formats ``` asciidoc -a lang=de kraft-de.adoc #convert into html a2x -a lang=de -f pdf kraft-de.adoc #convert into pdf a2x -a lang=de -f epub kraft-de.adoc #convert into epub ``` ### Step 5: Update Translations With the following command the .po file will be updated automatically. ``` po4a-updatepo -M utf8 -f asciidoc -m kraft.adoc -p po/kraft-de.po ``` ### Step 6: Loop repeat from step 2 kraft-1.1/manual/images/000077500000000000000000000000001450127457600152175ustar00rootroot00000000000000kraft-1.1/manual/images/de/000077500000000000000000000000001450127457600156075ustar00rootroot00000000000000kraft-1.1/manual/images/de/catalog_material.png000066400000000000000000002012041450127457600216040ustar00rootroot00000000000000PNG  IHDRx pHYs+ IDATx^w|%m=AD!凈) [@ōN! EdMGi?.ix=|ܕ4%([4@9 m}HDDDDDy u60y}DDDDDD C DDDDDDB [@,l( Mp.ȡ1/>x(ˋ!5/ާl+hz=uDDDDDD\\AwrvrBnܺ__N>Q^Ӂ6p- ͩ'9jsjakHy>Qˋa2P)PQ!>j;VyQ~B^nߟ@^#rp}Vd6.| YתFvy5e~eg]O|ݮj;DDDDD7*_[fgXvOvUYݖqoc#n\r+r;VZgEvu*܏+o1/c%8Zm~y!{]Oie@~O}V  }֑yZ߬ϬxGGDDDDDy[C}V? dܶ?f/2?_/cuUŸuY'ۮW v}/KݨfXO}2㈈`=ԧ2kT|{z϶|M_խ֌3 DDDDDT0y jFYuO|]ْۡu<`ZSۀqMQۀq 0+#"""" t3۞Q]m#FcԚkA xmDk㭎#""""jг:NP6kxVv;׶LmhQMߌ o371ejmorzr+PYumܧ'3Skj[0Q`պkܧ'S|m{cuq~`} d舘ƙ-Ժmo|ϟ:x_ۂY(6[Vy/}드TlXqfh,`>lYf6lوYY]Iv%""""3oj,3c,3c4ިf8>duVYz j[uu3Tj[[0QbԺ ם5Ų:@ֺѺfmO:'9ƬnqFU]Xu4$幺,cն@!""""g%3,~yiO몌ƪFm3瓜 YVme uYU:^jfsm׍jyGDDDDD׏ggT7aԨ&Ssu:Ƭ&Sf2g9nqF!Txm`T7 FeCDDDDD9ϟc6qq5mu.ն\]Sf=ΒYVie uQTY|i, TQAeԍ=悮Ԭ2>u6ce1DHMx :N+cm>,cն/.Yk*qq:te5\7cTW2u]f61:LYٞc,mzŷWj\P%Ա2>:๏rfgVå7VmQh[VbYsA]۲@$H-j T<7}MXAeFV v +oAknu;BQ^PW DMcE:&߾/X=Vy۞mCf1m{2_CDDDDT|]l\˾ַrXmunl4SkFmUv- tH=O}Qx4myneYP> /ǖDM̍nWRS:׀WۀQ@>=ey.ì执1|@i{!T]VWj UՀ늺Z35yY˂ZVy'""""~om8/c _–VŸ:Fm ۪E]Nr]|>Y%&cDMƈXWUfuO+'5f〬]9 ˗I>uFL@.ն*DDDDD䙷`khuAfgfzǐԱFu5uYԚlĬ߬nYNIQOWY FX-\<2Q2 iBKydAjˁר&.EA&jѧ+˂bg=(mǨ&u庘 ^=ƈ~1F uuoy݈/c _X5Īձ46~֕I>,8Hs/16DMnU-S6=17zIO!S wGb,YyυGF4[)x"""""OםK߸uӓ.^<+pe*p5>9(9Me.)Z eu.0k,On% An١ۘ>ODDDDDTHhaE։)].fU2h1L~9cI=,±:ߟ """"";""ZpdG˯!ŌzY#'0K;WDHVwʨ[MCr(дR;DDDDDDןui5`,_N-/AYs׌j/5AܖY_9sbY˩Ų5O`1y[ ѥc3w :W-E9 d͂ܧ[_Jlol_EUt/aX|y]}"o7"Ŷ>u[,vʨ.v>yY!EXljMHR]CQ'H-Dfӡ/%nAe-"""""*[CWUPl,ʕEۖw`XG8uF|y)2.RkębP LwF}j 0@d[a4ިdbY[L[Հ쪩k\G`s9!1x ٿN_qM3V EDDDDD]Wňg@XhڕEU1i6 ;xXy((~'Ž"mQSiZ7yx=wܖrM/c&~q@3eڞP6rNk?&цۏBeZȺ-_ W+"""""*ʕ-c9 ax8uJ{IVC殉%ѯ dSەS9&7CDOXr$m,aO+/Ctsi:- µTh&.p"T+u[ӣ[zHuAnth6Mƙs!DDD4McEJj*jרt{ BQ* c`if9E$Y{ف+ƈ9> w[pF_8u$aWme&I<69,3uMi @1JphG8H: eꨫgKз=NDD;7UޮvS7jը^E2k' 7uܳOݒ]Fu|v(̘Ezw;vIg5i B52c ۬Eyh.x;{mPugY!hg'!ylQu8N;H1ztZ6NjJ J _<^'w?B /Ʋ/QDDtDEbO?vJc#p/q׳;"uZ_͛ފz#&*oz ?+ԮLN'^zerzVҰ XWe_\{Rr>Q8y-_'OK[#"" ‹<.4 C0y\˯ԯS ß|&M :횩U=L d Ͳ5=oD`ԧ~ZzAWV,wF2ѧU'O}"(2`ӳo:t]8 =#\:8u'^ p*-o@8zx?.=ښ #y-k,kLDD d <ش1QQ۫;NDq9^OB*a1yV7{{71bpi4n:ӘpN2fX~#t߱?'$⳯V'U }axnc>wA* L}#nzdfAׁQ/u6НNN|,6B'ROO?g^Ϯ鸖kV'&/-X|p:iشwT2u-?zw Mom/7ڄ1"!>""j=:g>ƿ`ĩ)8}Kwރg#%5wjYB%]"}gYIRm~fh.@,ܖՐN5un4}" 5{oHNP$ es/e~V M1 !O!VfC%%W&ʕp!.._J(f&"QT4t]Gps0mRRSQdؽ?+Ȼ`\ ȀۊՄ_6oE6-{4 yloeofos--/R3 rMٌ>SwuWqjMeq&aM!8.n şu<Sgeَ]{1)d"NwMc71sʫֹ:+;ТY=g:.cΌ1xb i/)1?$&Hk,iL]jDDd͎]9iǮػ jtސ,!XhPF|!wwsN8#}u-IJoUq!?O3wӲ|Xj[~C_̱ؕ2 Կ) 9\C+@R\Ct5;i쮻;u8R[9uZMoeWre U<| _JOp,ONO}jJ,{ꂷ\?lFjSV'9P5fuw-*iz]u}Ḇ?"1@kف+t$@:+#mO'Of`g-˗`ԙ8y%:2""sDͨɐ,DY]0A$jAuYŗ>[6aK xZiTrW*Dg8KFw'ix6d0ԪvggY D+'_%d5 ý,jr52Izfٖ!Y%@Xuzw;cK2Q-+  +^g!~DUwYoN<c&zupnc׭k'DnHs/9KGҲ ՍqRΖ jFglSuBy޾5SiiH]eH<bsXQ!:ܹ  6J9)=_ey5Faɬ+r:$F}Pb9]]ՒbQ%2ZJ20s2nlF܎q~sxo45O$"""""*ld(ɌYsDnd#3`4Dx:yaFAX!~uIDzb4ƨu&5""""""r%Kmu4nTSg9}C8Om֌vd>DDDDDDl@j2]Fso5m3} Qאqp1-}-wX&r]/̲tD۬վ<#'$wN\X6:#2ƩQ9/9ʨ_Lf0:u"'Cae-v6 r;'Q~b%?Lnco~AB^Vw/*eQ"?5~ų'\, eс1Ӑ˻ņ_e5g j[fn+r:${9 1oèNfvjR/V'1N\PV90{T2b'/c 35`Y0RԹʬkr+$SlYnsf4ƟGVo2K"7K+55sUsDnd#s;X˓5G&""a IDAT"""2!sV2\nCs Vo;;!ad9e. gjQP$e+s&*CуWkj ugslyıĝW(9Ncݘ^{ *5<_W DDDDD7e&5[yB]GmƵlQkj[v`<-˓g ;B_O YRANQfCLVux9>-iڈ6SRۂeVkY]eurrk=P s|!L7 `}:qh{rzctD[~EGFYIUj2#Z՗93<&`eQ'2iR[,ۥI, dL8_bըO8!2"Y8)sT­h;8X֥tIԡ5~z-jAl쩝9Oc϶#J:מG݆5DDDDDɨRQyuy1?yAdFʁ˿KصUq t؊wÈQ.P3+~O<`nn͐iǨ

vd~Z'"""""NGjZ3b@F({3l˭v̶7Q)W1#*C26ި5""""""2g\U϶i/Z'"""""*Y<%?d+`gT#"""""*YODDDDDf=n [G'f㧳Nc" 2bn""""""3 ~Wn67_W q_•?`׋0uu("XOhg3N)Ls3F/]_GS0r.7<mbÚwпjLyw+AQ%\ *=pïíg>QXO B)Q7Ć]5U` %݉gpHۃk~ Z*޽1.#A5ѽ "|$.ꀭl; 4ږ!'"""""2$I+Q '`71pzbhiGbʠt]"#a6T]q8u&1 ghg$SZb"3B-8p; Z]ƠM]hhf]bq?\r«-<W|gMZ֒=QmxQ[3_⵷~pīHs$܎jGTY6{YT(]t]~vWܙ^%ZW؎Sp6rP=t >Ķ)С#q=g330g{ Û#1hݶzLل$uKۍ9ލ׶s=x۷E.Oc9pjG]뮂JǗC[/gZ*HCO7O߁[}+_Cۚǜ]P{$_P1SÐv7Rt؏xgcӵ5no }o[4/kjsc&t;cp+cнFVLO9B2?.E\˞mPuHA<㟟U~er7tz<>\Ľ7W)^BK`ץCx0gg V?w @>ҊJ4[k5F;QXy:.a9XsG i2Q!pu;xOa: /9ArIvu9 \"V4h}  ޼M; TmRC23'o|=wT(o$NNMm L!ickutQ^ &5?kh9+JR9n2! fLyKwr( lQv]U-ѡH s7:uh=Ì©'bӬ08lݺƫ.qqRwD[/iKۍ9}bТ#̗^="*bɘLW\!E"<&4jun,rýۣm1 K'ck4-ۦYu:.m^MڠEgzxhw>fPFǕ㭝És? ];G} QKX5},K݄W;8~ -S=v[*.l/lױS٥,lJ& _]?K=ݻ[vwGѴ#&<*9n^Wny.uA0jČp<󧾈鈶Y_co{=oxy;ރAx][>7SĐzvRq+V,^ bʵ@IR(ۨ;F]-{V^]46U=+c:LuxXi|7fV9a}|֬n@ya+6܌03] 3S܌Kb<\+j=wlf}-֯|R?}|y2_/Kq{wt7V 3NBF'j}p.} 6]*T]t\~ū%Pqxc}s#2>^-y7:o:.oo^@׾wk>Ÿza☥85 :GTqS Y~<\x}x}tG \ uże+ݺ%xVzo3M@ߛa92{2[LKtnt}weDz!4?`0jJ$^~DšnGqoa<,z =O݁UܯGu0~g~B6}v뼒|l,kK(Yz5i Ekc[_aSѳl;<_ O~uWa!5׏ZtU{5,Y|,㞞t^^n} WaÚe6)^X0fʛx Ţ]cח\]e 4C`hAn pwWbK=xmhvD51W\[SqcпQ,ŠEHQ'& 1(#\ņq]Ѷ}{m =X&۠O?x<6n(;nZ'2|[;FQA8Gϧ5F~"}ǾǪP*.=־ H=D|ƯiwLO!B{\6 t ^=TvܙޟW}{ǁQ56[q5MDY]Ů`"EmuQ BfՐzLw? ·ʢC[1<Q I|^?-ƽ<:n~ l ѴJIAChhX:C= G^[xf"菱~ 55\ ߼;cWmK&* Y";'B瀫(iU.M+rC;5=M\cCd˻dGX{;9[v6%Æ×[n-5;j#$N]C1GOX) Ƨ#ʿ(@I @Q4},y<>%i#/b$~;S $zQ GDx({d4"Eѥ0DG,b./2޹ AI:!6sz58]EP@EBbg ra]3BYDt~$/eD,&@u(p#mb>kKDqigwǃHۡw enOʬ^i(ѬϘ#ZUV~Q= E|`!tx^/8]ٳ{ 0y>{n{[}duh|g'2vDD–|? x=v]ILW@@F(?DyCrhś0c&= {^«[Z`ha0p@ъDͽܞH?A&]p2 [h\ |apu@CR(u/G":7B z@땇#<D }(tאx/bp{D4"/'Mv-4} VёEqc衛a<7Yg=0eN","y_:++OtoF54lpJXD$VtӁI7"q4*ϴ䙄04e2~uhҐ}9ߘUÖ3vN($(Q)8T>coL֗}u: "ݻңn&#K qw6БtIqCӞ[+vBys- vĝC/e/)Q~oEvH[>o{nZ\w⿄X 7E%Y#yj%H6Ĵ&G⍵3$+O$^n WC':/`{?$9Htq_s0lX!Oic/dIۇK|*'WyKϚ=Wn;Jm! 8/~٩J;tqgD8t^~tp''יQ vm,{@OI} MCȒ!L)/u:)~AϴD+ReP&O\N -1WWAJaq|-^/r#qbNǰʙyjw>IEJJ{r>-< 鯷1~uy<9._#i<| :t bBoqHpF|w''"Z.rjnңbhܢ|ǯAG n^Ut~~Ly$Pp)6놛Kܽh ?%F=2r[+`kU4}=Lc&akjQjtųə ^n@=3BO߁2u0hS<=%H~=+qH==6{_x 4B'1٥dg1s|,8g(Qy2UiCOp׏QX,q{KCYxTWCLGwG!=׼(V&tj6j10~T?(J]Sͼ$n'+)>(Z_zϴ-?kc~W%-=-p]-Tyl4S/`Ӧ1=\c_jyq7mza˧1a}p%7މ.V+inZu o h4NLŒ0 biM~~ s3U<2gVx Ү """""*}_Ł5SKQl>æ|3ލ(_/4}8!t]5:Yֽ Z+bZ3u)q+WCr)| +v=+hЦW.`p-*̚ϠV`OƩ?mp%2oE\K *߃vcGrcnUGfj"""""ƒ!Or7߮ޅ'܌`iWa?ѰE8<^)WK _<,Aw_ģh"h;!}} q s5gã6w7{$" ""REDz{& t{Kl u͕9Nٙg+pKfcΝՄOBf#G (v=arDDDDDDę,U3 76p@P+tLUa'yGGͤ]3MlYО"gf3pY9%1uZ6MvSٴw/}#~t""""""?pPZ伻ՁaXEެMX2XdŬ9 IDv68e+iovfn{ ᧎s&T MYx"[EG/p[g0g^> ֐tD]@6qdžGTxDYO ,4 4n"v#cJT `^ODDDDDD'v<6 vY.}(~]82tlf`/6!{Mɨw#}8/]cKȋ^ODDDDDDLu3-)}eR5 ̕C;},\y+d0"sF/#[6*52P4ȼ?ⳣ(F}LxDDDDDD$QcQO%O3KUqfwt ?ୂ1&iw1qxTFD|=}$ճ8e>NFPb$&;[obCLngX. :]xL{L9à$pO\-"""""?\L*݁@}QNevCj/GCP6u6r7b8b$.$)IS,""""""b$YDDDDDDNId;%"""""""vJEDDDDDD\+$ʫ;Wȿ`[4U"""""+%I;Ws$5n9WBrk;%"""""""vJEDDDDDD$)IS,""""""b$YDDDDDDNI$,""""""//%"""""""vJ_6+QQV zG)IY8ods\+$iBtXypl'&2(գ`T/[mm-śԠX(<7 ʄ_ gp/ qvm=˝(W2R> pt0gЙ`l^>d.RHfqXQgvt ?b9rF1eeCM_+VpK_ ,vۂ8: 5^ubڟs.ꊫ5YrF/ut.YD]F@>{aǸzCx8d.,YDDDDDđ?ӓΝ:1hz'Q>r賶'NjtĜ:{A'ܩw[P d0RT%-kY*:̻B2"i X8~Fa]X~?9ߗ%㖳b !ySA?LڂJEDDDDD)IѳG8c<ǸI窸L.h՜R`S\.f.BpKa"9.{L_ jZT& p[χn2ejբXZD"""""" %ɯm/4jRT:qsEW鵍`Ww,Fv(5(Â.HWkv]9qX׹Њ/а0~ڎΝ:W̹#G2b(L ?ҡU5n""bSaZ^Wu{O/W"C#7#f|r v=?笹>DX@E&v'`+"yM,. KJ:KAujJ[$”̙L0Es).͕7X;k A0~8\5n;Mޡ~/9d""""""I$%(>A$r%}Vm5ZDGX/`NM la< ;MgW4nEHh6"9i&Tִu83fY|c/FLXyLJ,'f|=}$FLe3㓵0[f-[q\-o9>ރzc7q7]Bu1e!kϸ 85;]1pu(rACI@lƹ:;WiDDDDDD*Ϫ*ϤID+Tvi9r4`8e^g)q#!cٹ-FRbѵ"""""""vJEDDDDDD$)IS,""""""b$YDDDDDDNId;%"""""""v.j:HsuN:W+!s8QOd;%"""""""vJEDDDDDD$)IS,""""""b$YDDDDDDNIdKlҹ(>0^j+Prœ[DDDDDŹB$#~ʈVL&|ڟOҩ0g|]=yW+T9 yS]L2]`ɠ:O +@W/e-7-a֛3`>$p%]*|[LOB/4oclЌΝK0B8>c*czKՠ}߷)6}>S2c\oNʴd]ЬqZ\6c†dDsiv:2zCof>&;#ɢ.aҷ z"RB6o׳hx1碝fp˶Llpvx[#|W=v#~a?Ưb/t%}>]PBNcΔj+leOq=ȆWښ˦"OdI a> 7#%j'ͳ/Y5b3;7?+kұF3hgRHd_!0'|;gӮ4b1O`O}:˷Y ypũc} e(rl:ɴ}vrNM޼5q4+NgwU?co"u^;1l劑3 F '}Dcx$:{L˂ e7z4EaۘGbub ~>iebsFqf 8)cBTV8Óm6k E@]/'\8tl{0o\V|f3lUl@31SY}hC6=! "ZEaۗTHu.ݴžl9,Sb겟V{୺C?Cd۝m[Ufܳ$t~ݾuնU;27L^#K6x/jwye4*ׁ}q1K#N3D_9Ǽ>YYsFȊ43Ӳ(фsq4 ʶeysj :۞|LӆÙI‚[|0͋y:7ʿ* f{Ӱxsе1k@ZUlM2Ӵ@ӶWY/jۖRsE+ie' }G`uXїص%7Z" KQQhoܾ|+^&wD^x3a 3'"bʟ,:W+SsA>y3;M}U?fԱ|:3y:.yɊ.]w# ` KdqRS헇tN9BšD_` ;ɟp|鴄+>%B^(ӓg̱_5=nS)]. y}y+ 0 G3 2yY=o=)c m-97 =b_faW]nY7jsyLIF</0nlaIUW5Ȃ-y`?q;2cuOJr*|^o Nӳ87C\X>uLn/*~Ru cTT#JeO){9/(&Wz {W"pr$Yg$38ܚ IDAT* }nr|c;^-GV|wa d.4y"82gjrLd<ЈЖfp3%;)Ib|YpBx*AB}mZKeW8%# rZ $Rr|Э,9"\˛=x3'&3{#T5|q3[TN-R~<_"W[ck0Qv@x +ۨ(yYSzБlC,b gbzxU҇;}..T#,x^gtNXx8aa.{8$MxGp7,+s7ku w7w0OVstȃL ΈP<NX;VYfI}y> l3zB$LIV&|AȁŌ^JI]_"87{2˨πiKw8uGX=",M^ę_ glK8;8J|:͆>aI&k4{\8ё06`Bi&gDA7dzNC)|f9˚G(412yzn N#,H^xzFn<G;ж?]2$3KX>goqt7neܨԛІn@|İe}BGH"D<1/OUOvfMp׉!Wn.7Yj<Kfbݤ K,ewV֧+ Q]NS) 9xؼ $̄)=9>K|cG*sEwSeel%~(NZ7e` Fc`>nHr9YW0xg>]ˆ4)*4H6mӴ(0%}؝62|,̹P=I=0znyT ABHF5n8O_dȢu|hk0GtS6Lw\Q;'( ٠0[rRz{cqxRwgh=Qɹۍ3:X6ngj}Htی>1q]ޓ=(y .:?B0qo BaS?p"`}̀y8=" ',, +uiC>YLT; pB#zգ,Ds,i< -K<29/ {w&WՒ:_TĈodQr܀c_J]8iF K<{3ni>C~[sTw>b@DžLٕ7ð$gwO&3Tp~=-i Ud])kuz|̄yw^[:d:8uݝ4~e\:vby_aNC_hl0Kj 5oZf욅#3qP> Ȇ䵀:z69J}y+<ǃ&]!=[gXJ7-3E[<2Ư2V`\i7zY0N[TޕNϟH2b,Q=ʱK1 7 ^}09ţpCHsz[NegL/i`v-3w޸eu-ۛ^Ȟx~`\DHlx[vskyce-j|O3ٛړХ|k̬unzz%zW11zua{F Y?r=$ߒt ;;]9q`qkv(8c3Ooĉ)rACI@lƹ:I~0VR˻fr~pK(,SIt*ϹHaZƛ\?I+3JB@*y6 D9cmeӻcVKK_9 1m1Zv"""b#7{XoQ

vnظi ^ю?+kмb2_絜8~ҧ}fw,Lcf\]_r+K6#~?t\&@W{.ؕqwj1iHc6"V B" ?5&Y͝xw׎.|h1awfB*WI_)/mV|׍5mcؕ;{xaK,vGY/2끜(> m|-n„cXeaX?¶>H[|LN Jlxȁ{1gLݓGy+m n+=D7D8Ig~=,=[BAD%80y)s7&yٻt FJFRlDY(g~SJ{68I}5i3&뾦F4~ YKU{Cf_aߢoPڻt{G1y ߷N7(UلzS%c=e1OƧżp>t ,%"s ,6I@(_k`mxR9J-O0cVE&3U%?[sZ|ыO* ńoʤqش5jޣKjQKk6pɡMߚ9<0RM3 fx1^x'7_iJl# [f6a%]Y:t̍+9Dcx$66],ɇKb&ywfkW%fXYlYY}Ԑ,G͉nil6S;Py1,dוoÄ#+Ukn^~&#{ڐbi0[*ïrKD8Wȫ@`sUcWخvI`io'.`z%۩>c1qg ZuFㄜ+&/% 5"V)z؈xp}?,OIivc)=:.l{Wy>ߑa&S&GW'+ cܮއ7;H` + 2fl}iGrAٔ*7}.q^zn.OGVRwof`Ac ׳DxQDn9tߺOO; <;.*IbrkySB Z{6,77fZyĶ(kq&*3Oa)Ҟ\?$=OʙqW?"E|ۏ$Id=巪нB h\qW ؿͤܔya2Tl{v >㛄[˛i鴯5O٫q%%0"nOZg Xo`oE`tYһjФH:m>Bt9OVG^Q杷7f+;?DhO1&\#W|33%q{:ʆIi2$`͘A+Xj&{p^%!  nƩ2hɤq./3B /[(O sP䁗{87b }.R#WuGx$/\r7IMZ%kXS3GB wtLxzzBX(*9=({a`&jrSraWNGrfeR "pllw0hH ]S&/(CKWqC:VY 0"8r}ғw)}R>;s95,cv;# ϩ2 F%OdϞgpV.'ܾ̮k3flؒ#WXDƅbeV3+?Ĕ>cgg|0?y~J/?Y>S"8:.9wj6+:O)-)A OS8ьp͞$3h>Nh<>inD$\ dzq>xaɇ{so@_#Y4Q,Rg≝MH*a< ,, <795Z;}^d^}\޳l:2[HT oRujHp`~σfc]5M<$Y74l17,Ӂ*w=m+>E|;ۙIʓ-g]$娆<09,Ԝ*-W݆|v]t iSS"/zz̸{63"^vwڵ_Lڮ70odJ 'V!3NۋojGʤN 3Ekބq73&{zryeA80+U^%W3/HZ#HBzoВP<ܲդԚCo#H(vQ<Ē#nb(+șT1q^ḙdl%}d9yxm0JTݛu9]aޞ#&ҺHgH/\߄>v7л8|81sv2$H[QeVg$CߧCҼ[/=۟= h~HnlʂZ!iXeXtр'. c"e^8,k 0`ɍ .Qn26LD?vWDȌo]Xĸuybkv7_ MɈ967~8{"L4fi^ġ[vtQFG8E<}p w$(N-ZomX0k2TF^;%V%bLV_LjÞi 8YsxOӉEGYN] <-x=Н>*4rGS<ʜ*u fެ_yhR5_{dﰃs-guvsÿɦDE۱x?-g|\ؓ2cxX/7L+ u:f̄Fg"/[q}8|FXtD9JlWY!) 'eVXW8WKSw)BChX1LЃI0gcF|= yv`xLmhm+ƻ NFK.>1iQ;AQ&e.Fcȟg076\Rd7D/0gm° ٚJF;~&toˑkD/Kbsڬ(63mgƒ jK&}*<ô2y{eϛ=4\1Y](0:Mjx`PvWΏ ȈJyd&_ch)QtNnifC^1  Ca C|8~oe<]}#iYh:;ERJmSov3xUb|`<<Ǿ=IALl.*M3ڢHb;-i!|m`+Иy̩xk6Kx}m7~L313gz5b]F 9?YNEt՞QRMP]Lcyu7 ݘfC9f0e8SN0(Ylƹ:Xyٗ\$ۿSY˻XLHeX>S2'CDnWgU#T>)h`ʎ1O/|>eCٰ\ ʹ7p` IIgԸ! ޙGS.!qDcV׍;rS[`B ld#UOf2=S;⴨cgDHuəR]=n~f@=_k# =޲a_㇟~,#ӳ%#83Ŕ1N<8q'%1jP!q2oF LF:#- u>/{ǘn$a§Y~3&K t6;Py=D$FB[SkvvJ뎋' ÿPrL@+M˴at쵁ӏmE_ti hKG!iY% Kel>a,Sb겟V{୺C?A_aǬ^zZV-AҙfU;2|c֚s{av+~ٶ5Z{Eq; $tkB/R" zXEAcAAE"R*D ];H6G&,9/ 2yvgSZOOoe+ohn"ѥ 2q0I8?A=lyLi| O7Fй'LMcvd-ÏLJt6}Gxej΃Y~Ve`+KǮ9:7d3!yq pbk=L[0e?pq]iV.-Sj=Z\^ =p=0M+vPOjٮ=nFj7*ۂέ2X9o/N }ݵ1QƘɬ[LkelۅH# -{$ga}m} nYB9u .\KfŰQJXՏ.P..`_Ɵy߿6u_a઄;O~~_ O03_/3pe-8y!@2>lw5T`ߔayqa?tfϼdQxEԝ(ÓoBmo@>j Z?G={x|W&> Ҝnjo~`Na-2#WW%|e0g?|Cա)p/G# u2y-Un6K>y2& ۲m6ǺK^&zۮpG=n1ND襷;v"y{O`t?_Ȅvs3Ds>w6q$~s<ʝ(jope i[u75j($5bKtI$y>⎏ee|9:B/[/`#Xw'IJ@Y:~C`G\s'RTzOwfc??ޖ*v R-QhQNTΫ S,-{o,UV!(X|Ge{p5`Dj׆ 60tq(C9cDx.v zOpEk69;틑D"p(HU4w"WPx'?3iW~pe+ }x'>]ß{hK3kEjsOLf+3lҌpjv}εֺ7ȝ @HuS`tJF~ϭbȈ :~ݒ"> &) OE7Q@[>~(Ǐy:[QI\WOylrb&pބ)tK$)8}"dΟ7q'$|q%b=ȗ/gC-mE_~ٱ=αn=?=!$pޱ<fffntpzDlMN IsU'}_>EҹȼWlq|?f5m+5CG욼:x7ݸ-)frS&3uۓRCQ#0#R 3- [A:Iw 2Of: I,\ﰝ`|ʵO^u*+3({0W_}}>{6#7 }H=%X0ϧu]mmd ?=/$=-2z> 끜/ru 7ޣU!9; 3xݽЋVEVpQQznKI>'qYL!Yˈ*GBSX!}UW #^\4Yyn`r!Υl%"43\PJN%ʿT6B0$>E}qf'S{Ñfi s>Z|Uٯm>)X" \4/3?iBZN&B &w6uژ i -}/*OG0;ROumA>mb/QBH*ޓ(H지?#cz#jrƝ&y[t$=فؚg/AL2w?:LT9 ʮ1鿲$=h6gy/o,Vмvg?_ɖQx ',go|A-# 2q;NvJVI`ƹ#gINir.~}L܉{~򵈡ݗʭcȘ?13ϳabTC9|TY8l?O3 'pi+E#[X"&`:NfY9ݟݎ8vm#W.o5._KDD.?ToZcl]F1#Zg}Yy =}_)[?i-}ʔNÄ0p_w9Y|9c+ۗp?51@\tS60c˷p^$-!${DHt8o\p[;Ӹa~45c'4dg78?r>=n<'1yk X |*Ja [,G\;TІO&|Pj+}9q ;qx_t\ g[E\7E<$-Xqz.bxp.hc=0O7[2/O{?YDDDDD.SH xsVo\hCdg[|q^?V)ӧhS0icY?G۴z'-KGfpARr^#VQ6'[HB*un1:RvhuξkiKM8[iWgʋ[S1M&6XI1)Ĕp.%aT 2TEDDDDJ w[~x Ψ!_ڮpmw*qqmwyM˗2ڞnj;ɺ4Rv6,5lml7Z7($XEDDDDDD, """""""dBE!YDDDDDDĢ,""""""bQHxw] Dyċ$XEDDDDDD, """""""dBE!YDDDDDDĢ,""""""bQH($X| ruh^=2]N_ûKDDDDDoO!v:Ú~8=ynRm͋z_ >u[wA!s?v0 ^%Yd{Bx4nX.6?=kH`$0^򋈈ߐB򭖾yS @\Y1.MnN87z?)o4mA1#-32/e/p1a/1699Kx7N:L[$&~FՋ>?^5&08֝?Li2Cߵ3kSyl7?/?O0]*(ߌBM]QK=jR WHk9U)F|ilڏ&3z~->n `HM!/|UǣL7NOroa'H${$7>(t_źtԇn~ޟ3$5ΖݙY-|d2cx)$D1ޥeǥy3=t)RE;v]RqX~_̶؊Ъn(>@dm%%v#Fg@@ʹ̬KT*`=lݐBFwF>cٞYZll!ܶo1['8B>CMt wp2 4 ӑ۳fcYU8I7 l A̔, 3LdRuƋhiܵjuy϶іü=~<>z}s>?q>13 +Fxw2._KDDDDDenx/ 8G8'"몿m~Ged]*)hV-QyS6϶w_]AÊXEDDDDDD, """""""dBE!YDDDDDDĢ,""""""bQH($X| +lV.yċ$XEDDDDDD, """""""dBE!YDDDDDDĢ,""""""bQH($X| r i[-8@bU/2v__;DDDDDDRHܧݮ90fvVo~qx`byY؋Z""""""*Ů[up>cſ~oؙb$pxFoMBzbS bUtz oZβ|f4*9QKGJrb9o'F<и4<+۾$| Vy OJǚq2"ORz]AV3 FX/HJ~1凝84Z=8~d Bbsqqc2cF S|#u43ެEPv~9lJo0r[\FG{2@ߑы>Ayoظ8Rb/ۋFyw;鰔<#mP*w: Of(pkh>BZ|ĜOSĹ>#3$:qUͼSʵwcҜlx%MjɈ"qNTĤ+YuF p'gj( ]B!& 7VϠq3axE?yvs|Ft܆bPmumS}Ï(dU)ĥ$f\`Ӻȕ WAAnw| -/ѱSGDbr%DDDDDDX ہo$1Y:bG{#́ity`du/?. 0T󤱌3ѓ_8q}ϧߝ*x-\1)$jij@zѮfiN;fn7.D+B;v!+8cHoP[EsֳeKSm uEFx,X1O Ē,8t;2VG'Ry,V9Րpܲ1YEѾJ=Tv {g?z/1:RvhuξkiKM8[jglD=ߋGFthz/㭯4`sgaNF/1׳Tdx"_bY2))X':|ǰxr]/݀MxCn44Zg{Mia?mmvd|=>9ݟݎ8vm#W.%"""""w95 ._ppZ j{g=.LˣmZ+ yϛטyh :VDDDDDDĢ,""""""bQH($XEDDDDDD, """""""dBE!YDDDDDD]?QcwIDDDDD/]/ړ,""""""bQH($XEDDDDDD, """""""dBE!YDDDDDDĢ;t{`&b|Л}o2n.L?Hp{0I\#/dé?mDDDDDDn clVpa`#8o$kWzɐՋ4E6T>G; #{ds".6$GXT[aN`ˌ'a1|fPly3e}y5C?AOƉfibMN`;I2.5Օ'?s?u^}EPw@{QHMxWi$e*>3_&`ד]^)n\Y=z"kE ,"φ ʪfڂS7ȁQ$AJDZٝt%{IPѲoQ@ 9GELJa_Y;{Iovx;kV*B)s-|1|UPݧX?q.˫ɦs_LjuA؊V@00[`.rgDY|m8ӝو^_I>:ܻ9o>_|/vW&.H]7^XNnBo6$;oظ8R xUKa [YӗR5/=FddIɌՏFWl+VґژPk=eMX} Wks,;sɦ;7Ö_sc Oɼ8350lHK#(G@p23g6 $e\)}"j5[mۃ'Z("""""WRH+I0 :ecgd0Ϟdu*6";ϕ #v G=đN#^KZTeFR nh^g"8N{39q.ky*7!1uqO, +٭,"""""•[$0+Gd͍,<V)Z03|2kp`;w  ۦjpFWBQ?\;Y:? 0<5*E} 'L$m@!6afaWG0 hL+zL0;<~*G(fǵo6هѨo|o.""""""7BfYfva:z4+t8( oF u͍D9/=1߮sUF~fD+Y,F 4i՘2y7x7~Zy(ݠ%M+[:,.D#7BU)h\^Bm TTj*IG7lBzgcJL'&Lq2`bK^8$}(-#-̞]2wwf9LzNNA!.(&:ڻ{?|([r~uѬU]B^MR"6a> ̞< Й1xޠS|3l4??Н+vՑާA`*wAZ """"""({L~?O@nJO_c;=l%ЦZ(vX4Ğ5U`$98#4kXjБN7Bɦ|>'ߕuוM ?o`gHM%4I>1._@n/_&3z:TőyF""""""w3!}ħAp7~U YďvvCYa.\J|-/mN[OM""""""w%!wb>W ;sqpLѶ]}rLxsVo\hCdg[|q^ݚM/:T'?>'re#od> K)$ WLoLs wDEz}̓a5g1vI:ũv_K"TQEb4yRսBE!V3x<]؋>mOe5[0"n!exH_염""""""M#""""""bQHp6M="""""""dBE!YDDDDDDĢ,""""""bQH+n_ ʻ ^'YDDDDDDĢ,""""""bQH($XEDDDDDD, """""""dBM]仞?Lcsy]o%w"&NeX;d!ϘXǤASM`LnNBd $cr#VBuf:z ӖËg3y*]w!""""""7wAnLjZA+1~TW9[ؼ!N`Bl L7;Vm!sSDC*@7Ʋ6}(Y?r/oLg"e$̰TkV j^OÐ;]nNTs7M⇩PUk)$UJ޽ OTV諦+أQ;?ƙlºNԯA͆5Ɩرn'F!jĄsf.NyXC !%h۹ټ ;6P-NxCjvn=˿t(Ba#W4`rDDDDDDR A; ;%U" Y|TJX:1`V2nrT|"scD.m?@ ,ZBASʝĞgpER`.G#8}5;+w.uSTVO4_ .G~Z_Tϝg7ovgoܒE70g=C1g<+?t{ZT; eoN";G<%rR{uɭWpA$"""""r7Ҟ䛤Z[@0rSnqU!:(X:l~!>5s9HpN|4#|<3Ctlo0ԫ|v5B >)%Ӷ1M(EvY""""""dӸkղm);r7OGǣ=_5ygg#'&}5]`eUb⮾(55vxDDDDDDt]F1iwvYm'`z]mӪe=o^cv+hOE!YDDDDDDĢ,""""""bQH($XEDDDDDD, """""""dBǻ fEUb∉.?.I($XEDDDDDD, """""""dBE!YDDDDDDĢ,""""""bQH($.U4;qywxQH8vthFjU݄|yo߈h&l`# ?I{ס;?)&v~=>T>9n<[5?Cx=c}>޾}ofv ,]Cu1Sn;{@Go<}M|M2`Bb[ɫӒ+&^ۓV;dfD}~>㮛>!>YWB0i=y'p3?AKb%?|1.>O2q3~wwvl{ "VYO%c~|+zۚuҨU'vo>r7uǿ}"kn?xn q{uߛ>_ňK{;͞=0/ʒ/>ɐw1a=/v>n{jθw* \AۧP}S(ytN{`$v(MYzpo ݃={o_B-'^^aw0NObkʆ IDAT3>gKIwlj٭~,I.ҟn IfgpH~9?e5Օiڝ9'B[aW3w~AkZ²H+ڵ#lgTP@SgQbwkgL|n:u/:nR7c;n#j## :mFDd٢: .^Amc^X r#L|D'-bQ6Xٿo}M1ֵ%~~Gѽn|~Kx-8<uO`KrȞt!R3uDm_?{wbX:m3Gk18P#عU]"lup__;?K[cԩnɫ{5uC.?Dz_duxٟ'N k{,M?o&O^p9vڇſ5gq5MyGr Gsţym=ϣ̯9{e~_B>>>nYoԡz8c"|nP|!vmόrww<>so>Om䌡O3%#FiGWR[;=7ϛc$e~u%o,5hM|00=$XL5kozPPG=+zr>M]ꕬe 6ԝ#Ͻz'~[t.۹~-i?G~){s-o<k?} ^+WsxlO#ulW~{1~p!n Yz?>O泮Nv{_p7Ϥ#ğ1tih*ytj ɒĞfـ12z$׸kEϏ w;}bR!?MAlsy| ?l[kOvG$vJ9lģ~0yZ _HPKA~'Y6G8ALբ|ez|8.x{nξ =wgZFѼ[ؐMb3aW^kɨ_]G*|m@*4htS9(H_:y 0orWn2}0cy*8h[q-S~3쾱D$ G6pou}i[(VH5W:oК6W|E'SKQ[4("ֶme,^<>66kZzG<ڂcX E+Ӯ-hڵ.d-,\Ϝ~w^<~Q&D$\jD4~a?PPP кἴ?'l&C$G5}o_/e| pݽ 熳`{oK#"< F^ ?b(g}ЇN|(hҿ̋W,ce5X,_UM,&E?Z5-Lg"> "-2 "ޟ T_'Xh EP NMe[X$J,`zjIiռ[2W*H%|+XE d99{T/Y@Jmw8!}R8ds뎔OxE?]͘9 |'g|v(& VcwGMeYnבh[W_*X;Cɧg,Ly)>m?lmY:nyOXPAye;дyYaa9`3$(dGym۫=ѼtXK&=>9%VV@րGȪWoR ˷"#Q.}c~cMdgڬUā:-(.*2o'0i@3qzn-ˬEkHj$&|;/WY{sȾMĶ͘K|:A|W<Ǵ;F΃OO1cUK۟YQoށ/V*1>/sD㳙8;(Ns1iL^'u:Q:zM u~/u]co" n]b@Ͼ(ͷυ_D2 B^п+ykHkV}:4,NjHE7;\wFWPps]8WwCEէ.?`8Cv)@br˵\j٢@kyeWkЄL-3eԊڢkn?V_9t*QW厶Heſ#/dop;njKxo7k:XB-bJu9s{l kO΋єz=DDjZDDd#mw<^qRSz> R*og.=JׯusӇq""""""U@oIRHIRHIRHIRHIRHIUfGsK""""""ՠ[$$)$$)$$)$$)$$)$$)$$)$$)$KF9_/05ng3seM?9fLⅱog߿H!/JϛΛOM~[#b8^`1 J!pN#٫\XCx1A:ywHVk`?2gС{^ u5up߀[QMxIx|&v9ڂ9 BrVS߆[H}DDDDDDPH%0|掚nލH/ٖC{Gj 7O`a^#S2,Z S?&Ҫ{܃M#X”c˞_/bmovhgbf1KOfsYӰ;*ˋfwsd!B469-inC{!S}d.{0h_1zՑL緥QZm{oF(ZHqNi$~OaI 'mۓ#1i(b-8qύO ۰|!s;7['5߁ JX1)"j˖{[6'F_ ~}u6&D314y _mEY |3363`Q}ȍGkGq~!O={(r";-owyrjuyя襡 n墛"Gh1OA6vDb1b1L~ ۾ ܒH,QObƽ9l5|5-f84ƈGbKXNPLQb|_-?}ƈ`:251R}7O,c~cPȯ{?O1ⱹL_~, 5 w̰/W1Ƀصh s-RAuж79=~"""""SHΡ)S%-;It|G~ۯ|‚C.nļ?YdE}=!g}}un{tk[g'wCqg+p#wpvMX}t~w!Ϊq3Ww2z(cu`.Kz=dK Ď'"=#_o-̡WY|uZKp[v`)ZkRڸ'5g1O\ymc3r-ݕ^Ѷi3YЖ h.KMѢ31 Xu (e h\rp/ yy1 Y.YI,bΜr)T1:6/;ppqm+csyk&/C*%lHkT__wŭ=μ-pd7^~*c;CS"ھ m|s<vQ=H=6|d?1csnǹ/t)SGNcmbu=u<ڀM2ixr}kEV~6vni| ;Q85N_]GQ#yԛcප3o\M^٥kR?!߅VͲ"""""R6XMZ#o1 WDhuPohT|2OvǙgBⰏiu4ږ/;]2h}Bv?.>o+?I0ڒWɠ]L{ x b&Y'9,yt Z@ls|f$7۰Uzm Iϼۅq*}[Z!ӯ}jn#@Gy57[c=6}3ol[ 1hZ&j+ev/'ю7ҼYӡJ~Wp1=65'ŔV!3[ Y3wqНd$d$d$d$d$d$d$d$d< Uc[K܂8t'YDDDDDD$I!YDDDDDD$I!YDDDDDD$I!YDDDDDD$I!YDDDDDD$I!YDDDDDD$I!YDDDDDD$I!YDDDDDD$I!YDDDDDD$I!YDDDDDD$I!YDDDDDD$I!YDDDDDD$I!YDDDDDD$I!9zcgu""""""1Q?qs R=q2mYoԏFֳ[BrMˆ$"""""1ۭEDDDDDDEDDDDDDEDDDDDDEDDDDDDEDDDDDDEDDDDDDEDDDDDDEDDDDDDEDDDDDDEDDDDDDkD!]ߟc`-(N|tFH}!| W<\BDDDDDDr@!9`9o'Vڱ,N5PhUC%ɘYqG~[lX/PADDDDDzmPJDtDx3,NaQGh]o҈Zeې>ynA\yyi~'%X6ye>c5lݏ:;M{Cypca0?<B 6e\UGwa?gmKdֳ :~~[vrѫm3Q|?$@ù͹wxoh^<lݐxb(| }q,~'eS-?yW3ݿxjxF?|<Wi]­nÅUv[uHKʕG9Lx%n FDDDDD$g3CAr֦rۣ/ X8HN?`SEn}9cv.3/~0xFDd^l>-}?ׅHskVϞ ``NՎDdoo݂MW|1S&JͶf(1,aO`Q";sỳIܽM܎NًyP;A7 IDAT P\'W5歩W%R>f_9Maԣspט{n8[f83yxt9:b`ْЪ-CFmh%)YF(h@Q"-hռ{Ѽ($$+,w?FV͉.k_py924}@-aҕ|z|lTDÁ;=d!K} d-(ZGG|lFъx5,[V؏u _Xf@ddK7p>6ƒ-JV-a|&c `i -Rܫd"!#4m-ai%?՚8B-_21qNsZha׼%q XibZҬQ/Ny#4ESir..z|5dZլ\]vT 7W$cF)"z _(~)g~FΦk=Ǽx٬ p'[b} KוYc,ώ]nйֻ >el/zy\VDgCe9`"""""QrSe07z;5w."""""r;5_:dR3$g*g]p{니H 73j]^m!9&l=N5٘7wtk\zծCr [v06EDDDDD$uvrsT==-Juꐜl>t}=ΝH.Wqצ*S!90l^\Iܹ*gn2]< 5zGDDI$,XB-""5NmӚ-:u"U*ܔ^l. _VK57^ /f;auwfϙED(**]8G k)SmnݝC5Le}{A/'""R-X-H-pb>2)^ak5Br!: ʇbSEDDDDD6faYd*Rl˩ əp/}ݱַ7TNJjm۴vK""R˴i-Oܜf&7gcSg<˷ƭsý fkɱzaN+Un=ڴn8sUQܺ;͕ɚ:$P>5w zmB(tY!nv>2?lg)3Oφ{;Զ[} noƙl""""""R>+mgwk;Q-$.XŅ˺ܱݷ[Jau._Vɐ^{v_ E3u7Dr3c㈈l&ۮf=͝W j6t 3vo;d^%+$z8@o1'36|\nݻզC}^H{{Qz@[틈Hd稰,ep癰_%:$PvAݟ)_Sw;$kfo_""""""vd n*s{o\-j"$gw1 ݋{1ؾ9Tfg*Ss{܌]ZP!9m݋wfnaug&Hٻn~r͞Ǥڻct ʐJ.=w/=Sl^lLjHiV󓹹h,-n6׹s[X|*jxf(EP ֈl웋|sUq'w1¸R8Uݻw8z""""""RKzo.ɽ2`+v֘yOPS78pܮl~'jnEv?AI48%6acPX"`1eCtn6kޭcq9]zw,""""" kawOj%(pk[{ge}|sN$fܱ͝ajQ!9lh3s:C d =S3cxro^bJgxԚ1Inn$v~}XMDDDDDnޛWd S{][wn\87 Ǧ fڇuW2$[X݋fָ?Bɋdܮ5sپl`(dnm?&3!G(4{5>Le"""""+k~L53vwrM7Swuy8nIۛWV!94͞z3OPn"y]_( & 5#4s9\gkPmnp6{_e|}<7,b% l䗄ufs]315Xo?ͬ3L7OիQ\_g`35{Mҷ7ce8ekkes3vk$KPn$9AٮdGssٜ] gG(=c3O|5ɜ9_3܀خcw{G;TM%Yl7cl7Þ{w쮱jU&Br@ͬ/}" nBy^sLɱy^n5=9|wfݽwꅩ1"""""_H'1@{3¨/bufLvnפlnڜΐP6]kXuovrwxM= 0suv6:M]g)ތ-.PuD=3$O_72/z_ _U3ǘ dX={cբӄUsfkjtT 7Ճ7_p55cw|ݺ]׹u5Mjd>\tW?а^$9 n߼n6/Cl?Ygo6}璱1wn7vfMs3;wk©YZ5LCX9OX害j^ԡ훹8EPP $Uy_e?w}[{SOHfZX0XT57٬M*$'ܾG<5(y;n0Cy\sW>Bl֘ kl?o{zV5w."""""U!Jknϭ{3LjKHM5ssíA5#Uª"$g#lIa_{-Nu4F( S3ssc8ܞaݞTkfaܵfn}kuZ{35_Ϸ. k=Ǹs÷Ɩn^j:$L/hҐkYcI63wݟ%13j^_Wssk6oW R|s* }3[l{WOUjDMg}L߾hTuG( 56aU6k~ys؛=o;6!Z)R [k}k|5{[75d3 a5; Qk<jv }pä{5[M-]}#1T` @ϰzEkͷHWwdžݳ'VXMIN%$]꙱ݳRDZˤSkݚa*,ʶoްgk||5sv:gj֨P6hA.U\LxunPjk[3c9c¤깲Y+""""1qsD*ڽuwnܷZX}ut5_*$;O~Xͭiswl2?}T{[X/\DDDDDj7:jactuwݽ᫇]zVMI>ES1}3>7{uڛ]{}0z""""";rF훱fuܾ۵tuݹ7zX:L:_D_>l{nߌSzݻcíEDDDD$7҅:n僧o~olc2uo|cTT:L:_ ;vָlzf5|=w;O'"""""R94w/(kl/ls]ў[wnswO5zYuJwlلȰT}ݾ[ݻcza*rƠ"+1 X㰺1swoTU~r29_k|cnjkl56߹ݱo^Q:*WA=/Dc 7c^S _=l&Wk2R~qWE }f7k\}f|kwB:AJ5wX/={f7c^ UEdrΊ4pܽas޻c#u٨̱"""""AX7Ɔ 5-3ܹOd*T&d _ (gݾoM rUF.!""""!E ;Ge꾱8sSsyLe&cU2=gERsWdmclu7DEW2u:ݺwݱ:w&2R!+sgʯ :X_p{ޖc_ {"""""RsR?j6wz[}0dM֪2dez :#Un]Ǹc'WkDDDDDe*&,lփ;z]V2dezLA 8_Wsts#.""""" _Hla}6;6lJk3]cٜ?ӵuaշׄmak>aJeʅtdžFX0 քmak|}5LAvkR)gʯO5w{uac[vNbLjHU$e{>۹hƮTf}6kR]*tvnKSl[sFX]DDDDD6aϭs׌L۳ld>uV],ǩl6ǷW뇩q"""""R1 n}5&۹e;Og:Un-]dfl| M&]?S9Oe͉*|*s~IDAT+se[[8"""""R]6Le2̱9U[UeWeM%f>L#"""""Cav}*s[%jsscTXU&@VLU1*{|XZcΓ~tjYԶPW'WT)8 """"""&( k$""""":Xy"""""R(W^PԌiIENDB`kraft-1.1/manual/images/de/catalog_standard.png000066400000000000000000001177211450127457600216200ustar00rootroot00000000000000PNG  IHDR% pHYs+ IDATx^g@GUDPlQw%h&5jQc]cokD]EE&~\}? '(=8;w{¤+2->!]>!]>!]>!]OW|Zݛ.1]qQF|2ӳtv,Z] \>+(]X@yrnAY~XejHfdJRhd̙j:ugx<}ObkѪ5buԑh]KVM=|3eh#s [~@ GK_u캘Wl-\Jsof(U\a""b kx;XbM4+IM*QOz:ȱ$ mZ|1g8>{U{jm+&ְF=,@VAֶk|Cya:YDĥiǙ{IɎWpidicY<#54b3K3Vr5\}WSe*}gOm4D|ֹoW~֭Mh*]uX3K JNH*!cfe2&fƔVTJnʕ 难~<^PWc/eH_P((-qx+NƼef6UJawX-v,kٴmoj>wxEF0捚8vr׍>qcAg e[uCDD^c\5O7 , U2n 39Yƽ~Yߑ%">g[4S̹ugkTTL"Cbц9tB7'f6/[[ ?\|X|ύ\adP*dh;5yg ܺΙk2G |L* G @ @ @ @ @ @ @ @ @I[Ih49 |rY5Yڧmʾ]Pi:sV-wz_R(V;w]O '""U칕v{cO򈈸/ܿQ۵kKi75U>r]YG:i3b7mưϤBM{ĴFˎ򈈄F,\jϴLިz߹vb!q1O۴lHߘlNh\c,oޖ . tEn/0(mV6.\]ޤ\#PNHWtOHWtOHWtOfe Pn r\Ӽ(q=]#k֨pwLW >>!]>!]>!]>!]>!]>!]PҔq75Jn9Xli&1-#Q9zx^EJcP19eDwAY#J-!Z,GuKt>!]>!]>!]>tvyBIe Y7v8-^ڶOYu~h}u8gXVmUlS\ҥ~֧o'n}?ܡW3w^:|Ħ'* |;v=f'9|аnng cU.WգcG΃pWV螟Fѫo?(:tҋqO3(N=//>u :wh'iBW 薩{xoi䍁 4-пK f}`OE!=xes<1 3/b>ʒɛҽ<{Ԏ)5AA_:hn?;9˨L?/s(Hv%_䛸@DGbMS%^WMx#:NCwL; {~t~fgS3AO>cNjO#ؠCkiFwr'm^R/WW~:gВ텺 KڹNe4zV28#&6浌Y9eHae?>sry%uW9u߾)c^#}ݟLZG0ŅU:z)mLeXmiI{90ަaL[4M?!>?v:PmK2ߑ=Y7Y/w2GKLR쭗NV5#ѴuzR*GmĒغg} Vф=M`znxi)WI woEѝһXgaYXj;4i씞 qg[j* ֨VѾ̙HܸPws!1ZmUNӒƩRF19q嚎F 15<d,& Օ&+bdLX@*{H孚ƨOKBX>[{JU4U|YFl:GDZ:V.e" 䖭'rKLԶ%8EZsQS[X""mjrZ9=rjN$7~!_PɱRzuLDDkUڹ9-M;KgLv\obm+՛oT2gFɁ%"C QrBOVDDNLL74/hW*+b^9! Y'51&fF)iܔቈfVf޽dlĘZ۲UlXd{_E}_-/f^ډc+Tqvfovl]/<͏vY3eXx'bLx}}/{׈/+Y54Q$$iKO[Z~*`wKQ)A[6uޑ ~zoe)4ڗuɛ!*- |`}o"iӎ~cW6,Գkͩ"r8Ҥov͢SگImEZa:,iSoHm!\G a}_oU<񚬘O^ֲUϧ{VEfqD29a\n~∕WlAj'>5?3ɾ˯e_\:L,-ܿ31;9<%wfD|c~:23ŕkW3vbdVc3gT%3ng_+vUhzS/+%=%Wi/ӨռR7^^ʐ9201#r^xkRPD|mS6tߧY[vۘ:} %ɚ_jhd`ݸǍ""k z4k$ADDc~iґ1ٜиY Y"־X}EJZ݂^W>=9߳\DjT)/F?YC.t̼n[fzqB\sBF{ͳ63%67mҦխuE o˪7I,X{/y^w~Q_\g~_0'Iɚ0oɉʸsv{㬉wSyXjU/-?qcAg e[u1F?5j4(cĤ+2tˈSm_g!nܶRm{# yRR.|֓{ϳDI ڱ?ҵA#Gu+HiV玪[@T˜$b @ @ $艕Nr±,-na2U*Ut%DAB'+}B'+}B'+}BЧ X'(]RڈqZw;ekNEju[j/ϋ 8{>8*]-rݸGMsqZD"[pwmkoѷ[oJMj~ѽ;{6t |ѫTmxs1>݅t|Rt%%Fx?[3GwV{{g;eSn_u1p+w-ٱ c%-X2ЉҢ>5^78_Lj[IΥkw&liQEp QK[8Jl%DDNϵ,E!.YS2'IIH6 ql^X&o\C32: 4'$caܨk~ƫMjn_\HHGlqtC_߆gO_ K&*gHyZu7ɫxvilW/J}=q(>{&0*GVi m%D͈),A%\ۣEo~=b+Gk0 @ff&IXM:OZ{6Zk];&tϻH <՟'sě6ڿBf冓YAxWΈ%:_/'"҆C$/2J'[2 7\X(\ l:i{9XLU<%a""CD #N>hF,hWm=s/m_f"jĐ*nv]]oӆҲD">_f7lWrt}BM%ψKFR$iWj0aӦq r,50`sdo9- ^n>Fo.p<Fy1"SK]e'dz<vb{ҝ۷.-fzB4ܝ;g6T\;p&˺v ~Z٦Ij`ћ~[WO]K版>{^Ol3nG65,h_ލ5̭qy9DD\v~  g8>0X>b KZ=Q3eR9~\2F~UǓMg_%OG[olqީo䮹~Xio\=/!Z|ޜ{پ34޶`|w/$'ֺg'=0W9 z7Ⱦ[eHPGb}w&/c#+G;L#f܂#=x@w;##Y|aFDoWڈRx#s)7{QZ""aNQ%׺,[1+0Q@Έuu0Sj <|^u+YHزnd1/V˖VڀCI6eLI9FHd9x_6U;fn}Uw}ŢIHΑC"F.ʲD<knX e sgoVQ2SS9T'"b-Y"">?/XCCyA  +Z\nn.g0I XN1rCD 0H$b""b!"bqAa d,Wz;r8R=R#^ky^+M[v2s-Zq*r4Je^a7Ug&%)e8NKDڽRu]vHne#r4(w\qʕӿu3/SJ`coj"=QqѱE_e| A%Gkc?ZdID22"VKD 􉆵u}T־3Ŏk am>} ܹsVx #;Ɵv{sP]kI[uK:.R޸#;|n2b*2gD^^#tq/# k)| Yw#2xiR9Tm)ţ;<r3}ҁ1wv}ð_z} vE֧kCqoƷ13t^}SM=ھ8FHW R@q5z}WtOHWtOHWTwM-ܮ>Ue4~<=l/1Ns5zum"tDDd n9lSuMejHuk|HowUͭAy1nͪKkW3wk2=d Aw~&o~.H|FV;@¤+2tˈSn[ZV@`,S45+( >!]>!]>!]>!][py}>D+B'+}B'+}B'+}z'zT*UJJʳgϢ233;v(~4#w:ɉ`5((ڵC B ?~<33E>>>5yyyj> mllײeKSS̬AtЎe:uSTkVD 3Zu]q_[xyk x"O;4ǷP\DPUtEDYYYyyy< dd竅BP(`UVYY.\y^wM"Хku6mm[R9ZMmRn/Mg^M4i{a9:/M?~֥gcf>CzTk.kyak`zi'6};4У?z%~SZ]lYԱ~:]6h狅lQxJתmYxiꑯu8xiU쪬߸in&;-I2ѧJE6Wf+ED0LFFÇ>0H@ 2Q6M *{|P6D轻;tZ;y\*a)ϲ[ݽ}bٖt =[6um0̛^-7֑]nijyo Չk 3ڎ^}][4m=rhݮe>ծYt(RE2w[yx4j-6r؎^yulס[V?]U6ښ}Zhkm!|Ȓq=4oҸMvsjvaɱ):/[իeMG,8%"MnC~BߎM4im</Mou§Է+jϱҕVSuaFLs,uCaUO?HۈOޭ1\-RЧm-~ۙd t%30Fkqi7mسHpB?ow^~]t-}c>.^uiZ2{oInn OV<`DӦ5(S|Eetڹsrss籱aMi2/]fLhY-*&dYn 6hn?6pcTGeXS7M5RH"Vk *wNLi6 cuWf- ]]ΒȶA#].97??llsk!;o_8S01k;tp]c oj`(;C cU&āK$pK"`M6^D+z`Yֆ8㹸Rg/~W R!LwBYU'M=:w뎑Ίn9dY&+6WjnDn_.nтݷsƕoiW:]UmS ڍPEN֠R~sskprF+"344D=zkTڵkgddlyB^XZ5J*0{D@tּ$vP&Og;x~˃W\صa6GzXCkONSvZ}rܯw_zƑJgzռ{T~兘NǑCs Mg&<rBv*=7xY9 EM2)Y6+ޣ|XC,JK\sVGUQ(>SeH0y9)X{G۔5i^VDos[yfw#j&.UL*u)=qJ9?M9sUa:vo>U'.z6uWj ?ߺUUMȲ  }fM"2329ݵ3""r t[akabz-AM 2뗅9 Z9A~.m̨fWo'+ڰ+B![:{){trdzuP3J Z^˶<BSom9;y6/6ܰNliĤm_6sRTmkjrkۿpῆGo3H-Kʶׇye.׏#"qq 1OIybZ]~XcP/w$صbaMdM'-a™=$ |j}Gf-84G ;azkqMPnnv;OHZIf.sy~>_KPu1!=bacjƷap.Xk7lϾcq"gvN`tEnQs-tK ._KMM=x𠇇GUg 2'!1-&:1vSF7nlmm]vzTftf +sdd&7 oSGۗ[}] ={VVV$j:pSBHWD[ZοV+0OHWtOHWtOHWtO' -xWlu }WtOHWtOHWtOHWtOHWLW"(}%[^.//"2\u޾;s)| -./L spކ6JDd" RfjW,3|(|~bz BCCkK#xMVdj쓬\KLkXWaP#ŦM]mM_.#ßV-WcVfNRѿUmz50W+=.3٭4S{Ɔ͎ NNNpJ,M,M tV"R+dhmRSQ'>Urֹ#+c2K(VV5on+"b;׭)"NLN\ƒT!iwc*ژI4Lu.&6-ѕqfN%[PF,e''hM%$PS@fj")mƣT;xeL|caӦħ7H*mQ k(4&'*` .;,&"Jsgs#FdDA""FZc-ˉ<(lhAD  u+ "@jiR@{&>&Ƹ@q;"ڠrRȻ|Flf\Z0nĨd[piedr$5mhWJ@/zVR4؛;73X8uZXBLRMeUWY1p(@Bc[)V$ K͌ S3r8,$v0*6#<# ^ib<1ݿƧh eTVr%= U3"SVr=.8Fgd(^l,D$4NgL-Ի/8ş:')Y4eHl"y*4_o CDEiܪ90ؐYeQ8ڋ2d*ywjǖncYGJ![XSDs,Ɉ Ȓ4RH2~IO V5%|nxl؝4ӎVrʏT.T)A1Dղ>M3٩ ?Z ^Gɉ+l/שVDD$31TɉxUJڬ NӭGd$dUrd'!U⍨rUi}{ԧժrdH0Lc߲Zc~~+͠A+ b[1Q^$et;64cG *71ʈ*uQL{x55S #i`k'@]MHր"ՖpI,]yzxKaE%.S[%V'fe:ۋX"21sH/c\H1r|dYYv-b[1K84~ DkM̍D$* έg`XF(:~VH-IK+NtJ#"Z&D֑"#Ek\͂)%[+i(N֖2Gk e(r, `:DT3-ؽ516Hu'Zadl[IֆFl@HD3kQbHA^M5R+ wd2 [mF$ЫaE/f<3<RE1IVHWVfIecRqN/r'+犈5b ve d,Wz"HR+CD|ϩؠgsHSNhhk(R%މĸ<3PۘOW# 53'"^:GksyNJLPΐF=6AbU\+-1R+GaڝLsӷ c pLGD.Z$TkX*F)ZڼtxU$-&= VD[)Yb(?=Vf+ebX\Y8֙MJLNp.wj+g{rCVlh`h_\F#< T3"cCKk S.ހ4 N ;\KyFŧcXǡꃤsJ5ψƵj )+=\eG'syUBjd`^:626:5&AQ\pd-ښ u4?HT)5\/7P$9H`Z"%0NcK䨀/쭪:'1GiYMf"I`[PRe&p|)wz+Y&QwcsD$01rjb!g|W,v$\Yµs[=|ℶ1 2[7yݬ7sžY7.tz ~*ZLP^8Pq ;b{T02::;9_%"feGk i禪Lc|p#CImǩ* GPddWƸaRw&*[c1FWjctFP2l}aNe;\e-;PnWQrewb>T=[qij)Tܪ #$<4q{.".ddݗNϒ̉=پ$e]d}n&Nm{3V,n.$RƦ+bj[3晎DD<2s\KCq""{Ϗe;G;/uP#4<:J&c}vIgb7{_]ӱ;绅̚SGˮӅŤ\oˉHa4eIH LMBJ3&W'<68g<6hfnۡcUDDb[/g qOތJLRieu%ީ(WيTd!.?x$;,]njJ-mpd,87<:(40ޭ3ޱgݨ׮v/3H7[=8S%"\#P)ix{_o2,_gӻ\ZHewX3$cb$]Dcʨ0Ѩ6L} Lׯ-H,9]?rg#sKR8 l?rEDD;㋥ɱ)EnIHL!""&W֯[gDŽsRJH0d ̇*qZs"3 N6ݼ=rB/D(L2b8HV3$Sf=V!f*zd)qH4<]>4,>~IoKDĔ*E,ȴK3J%78q=60DĔjUMY|}~[êcu"rcӦWQ Ś{ys)昵8ƴz4M$ lAR`j*:P`VUY1\^a0iBA2"J,ý߽2_pau_<G E`ģs'".t|T",c\$"JƖ+RJ $m3ss}=3!q1_HD쓋P8 7-ՕGIQE13j:yLV-̇$"So|5P1Rɂ/1TgsT|ͭ+(1?2xBĴ`KE3K( "'ks 1NDR75/Lnrf`$<00dgo ̐W &$I˫ٶ]Uw/]R(d{AN/JD$Ϭ:\rq ,2bWX$+CׯΜv2s8 %օ`y-t9>mc;{PXSvqF2;ݶոtLܹy~\Usqy7+/$V}<)W/|>EDt&w8~퍖8S[C/gi ]>D6P[ED撃U-7/ĸҔS}Ĕz} Ύ+}8)t֒njvdoGߪi+W^Vnjziqya,{pg2$| mS[,?yFg>1h/p#ZESh;3:32L->"+tBH'+tBH'+tBH'+tUdݩ%őZ "]@:!]@:!]@:!]@:!]3SQN$Eq"hm}011!E&.>5W 쪿ArЈn>8]1VQ]sa0йHq92"dܼ(1AU[ϓ O4AƕQPcnweLtco,+2bS sEf 1f=۴K uiq5^bύxF F$gZ:nyp"耧sRH>3w2uL[ 'l̩[uGK2cIJƈ֜ѰۦɃK^uYqccrKmJmɐ"GDDekFmVADg=^!l-Eߙf13(V &79\%Oo0 K 8_>:~//,Qpdw]G[3 WaRߙ#>Ecɹ,mUVWkGDD$W򈤕*)K&;M|'a mR:Zds(әHe~<(]NJ*軽9iSoϭ?[SjBBtwrS\ jgs&.P_pjluoxbl"bYYU{?)C58>*;PtڸgPU:[^ihvX:x@jiI 0"":ذ0cŠbDLҩc1NŠyL⽸3_Iyՠ$"Ufv;ggJ}cnsT(44يuf^%#"թL$KK4 D/0!GI-E.|\ZYrqT",JHQveVޛ QrȘ7$$˕p @n~Y6q2 HAФʒD"ŖgVEyvGbwib5^ JƗS[l bE B~Fd"Nt7]d<\j>s.K)UgC=m3`'[evilE 䊻󠌈Gp\GSDNrz7R &:=mLi6*\䜘v)"2wjGē\Lw>dXJS3)t 1b2k]QmG:.NW$JD$&)NIf޸*@a#uTIߢ//EBdՒWa?dMmnXrJЖVoZVσD[QfedeqqFi:UW0$cDDjf^d:mVn9 g 2Xf3 i`_ IJLV {ػDHD$PrӍ>O kKַ\boj~o2B%EQ,<7X )dbx)IDD1 INDdx*#CQ/FD<16=>8O=ӓQ+[FDR,JD$wQh,ɹ蟙GXBD$Ţ#!n֤,LKChs1[g#YxPy*͘2Pvm$ tߦ/1}wsy(L4:rq|}H]y־zMwI> \w^=>ژSy])WN^:*C#mj#j4:Lu+`-.IjY$Khdв:]>Hi=ǬzIQnNP󎊞֎$TlwhrehvV\SuYjS]Ԇcx/!YSyȷ:[x4XJr9zvS.L>u'UO 2Ѹ+6ߊ >N3%-,aԯک-RnjWTyV) 6yzZ SOCi,gRk;Ʈ iW+SKBj0v^HWtNHWtNHWtNHWtN`JzuSτ7>~.KcN qezhD&WY%uRg'NL9vGzUiOB־6nizq\^pqĊޖnIG?q){jԚG{+dMN<032N,ݻǪ"h$8S]5&9-,S%u{ ]ΉɅP)5+GOzJh,x8Z26s_w[f'[4d4(T#W<&uCIb}SQvN`|;$>3Su회G| `ǸÙt%̯ m0)n5͸*<0-<,qΰd^%ԹXT,s~JC#{Rd)(?d;Tt%Iޖ7"bƕ>>4]H@S{fT*gbL(+QN-EVT"SEDbleMM 8G}3Kh5+/g2Pn0ļ.=7G6d+C75O(32MmXAW3~ncmMFLmrsW's8ߡj8SeaD$mDͩ9t^.ۢb"zs\J2)fO}\\xYQ&kJiGD<46|Z nkQ5*Gŋgʉ(km쉔4xׯ7 +1n_\MMnR#@&Y훢:ۆiYIzODBVnY8t\&k{񽛮 yZTQu>svX>D,'FcSoHDPrdaґhX,XdjoΫ񨳮ئdD{wRͺ0=S7(d-is>2iglLm+qm%D$wWMۭUϿT&S*eRta7g߷Jstu/)7g,>n"V RV '"Ӯ 9i˹ vXzPJb'%#;jNM)C[&ک%k-XwH+r2 l@TLYG]pww80dU\$c(}uFC"hT y{ IX_mq@^P6{8u9XB{n^9YaTyG>G<^t4_i:}ȽގƁ@2r!2{ﱊc[J'c b3;lw+uMN,T"R!I)s--ܚ+M{\j"IR׾MO,2I6p2N{of:'[o's2N}>%VE9d- ش)=cHmfg^xUdr[Q\JDaKN;5q9D$XrSs$I9i2[5<5.##͙ ̒=Ȉ'cdɈɉ9q9LRD{ ") E.L"D t{mFc)/W31g^}PLJHD<6;6~o,P*Y0,%ƺG1eJXksl:Üx[l[#Yʤ(\k891^^q""yIo԰;9I1WX6f+Zn$Ƃ♱͹ٝcWDrԝ<:}h r֘mM]Ì9H ꡐY+v_9LpA,wȸiCa4LG31"۝\vE "MNyIBwZDD,]^=Y/AB7Õ/ݸ(6rNrj*[t9>mc:j;o+*Β/nPJJ&ΉmF:`\b\crK]vkHvv_ IъGBNA./l/R7< x"0jOXHcfW~ZVt<)y**w$W(2&g}p8* QXUrЈnbꂊ\KZk [Uri`v:_YZegNb|+ӓQsVjRUl[7ff)=v>bڜ<`ĐWj`b0eV1CuAEb1cDj67ծLW@贘mb_ פ4Dqh}ˑ cu[|2$sg"\fѾ쏚6Dhf22̌&˸UguTWE#ʶi{.XwTtvXԔZuPKDD2s˵0\TP+!qjn2^S-gn/T["Qm5N.ڵs c3ʢ9&%1Q)q"<gd_i1e+ݓcSYA)gg&ʹ8YdL.8(zC^v5JIIٸr(F& *e(H+I1Ԏ*J\9i |yr˛FDĔYGO,tyۗ  ww6a6]rxoVt*""Rg4]ZF5#blz *U*O֫/l7 Dtز̣ ބKX,VtɹLs͞L}u6É\"&/&Υ$tu)dl=2&$Q\ 3ZK[g3 ;5x`X#"b{djuy%v*[N|ޘHIbDZ_㜈ZzBirmy&H\Ù\&1<4w'\桨DDY9!gRr'.JcjLƥ$'bDDK l8|?C|RHF̶ƝiKܥx%(_ްQuڢ#f yjث/kpT,t_6Ln2z5j"ZxcBGLDDX݋kc Wi4HŵMr2`ԌHLa;h)90+ϳԳ {al(2>hV33o}&bLjO&DW'b*N'pi8]xlz8$h2rŕ' ,sC}#ɣPxdf 6hܮ3D-K:G0w7%X((mnc|/r9r+M \boj0Sm^M̰ni|gA. V]hxir% 8i]hX_J}i$"/.^$7s nf1ggOM\ZJXlt7\SbD|w9q6ϩۺ˴)^M0T߬Jbrw192Ze. 6M%2FLe'+ȵq>,ֈ^-vS.L>u'Ӊ59ՕԎ3q|mT[}r_fx~N:3/MFD+x֙AؕZx ]=f_lN-af iWݑ+SKBj0v^HWtNHWtNHWtNHWtNHWO?i<X%w޺“;>gVJrCљ Dҕ(&z^ND Y/LJD㱸J}j _T+t,]jsc_ݥ "+ON5 InΫ9P|ӱ;绅̚SAo0)hl5uj&-v^R{:=K3ovj4-1Stu)V030ܯ*t HI/Yz gj26uayVӌCY)8zUyPڇ jxT#xY% ivt&OL{MMƓeFif[ R ߾qSu.Kqi _gcOF~i\?!cGYrcYnR#*#Dby7ĤTLJR{~"jO"v$w{fb\86AȤgmBk/+8hVnG`³GsDģ-'^vkE_w䫈ɒ'?aQw5اVd' '}]h:**35س2 JF(ٓ9;Ta޺nOMd4di"AS^8t3'\[]\[j`"vH(+4=  W}Mň,$z&Y ̃pqL$xOrnth!ƉgNi٢ |`/"ޑpVs'J)B[}+>3<$gFL. ּ\w`p!Ɖ'#}<;okaDD$Nuc%c;< DՅ˓CS,#J¡ȉiBMKzrLŐwF6o!8kLH #[ݝHZzKbqbT1qGf "S;s3Ɨ'#Ka'lc]%-H˔:HuHYXSvqF2;ݶZ{ufko.DD1PM ! Gs[R1]NYLۻo *96t/JJK^b#b=w.Ҝ]uzSIt4Tv7_ $S]l;W"0r{9dL2c`$z/T-ط/v| ڌCunQ"<|g)d2h5w{_CJ_0N 1` O8l8 UK2 ǥZ ""d㲬Sr;n^h&I12o [cRj+lMM'-v^b}eG%4_;l.=[WO_[xOқ҃GBNA[4$"yٿ/|}M%|/^Kݯnv+Y?Wxo>3RKLR#9߹ty睥zk}3ra_T(&zB~TFF]m J TV /-`(e-;Sּr2_ˈk˕?~'w rˏBҳXX7g@4xtd% Juj͕_!SZ۔7qɠǗ$rQ4dФ/1NH((>S2H$OܔJ%%ENAH'H:ocYlpm?g/ѿ:n=?_IHSݣA0| $\nqO/䤦5zR銘󅆊/}F߰itj\_jOD}?҅~ Ȧq {tgRY,<ӗ|OcY;ߓaC*eߙp%+o)7x/ DD;x_زk,?v"kop3Y\zlK5W.GbK!Uί)ujI]< tnZ "]@:!]@:!]@:!]@:tŗ^Ə[ k$ﵯ/[ܫ}h?}¨d?}n|7XZHx Kݰ药~OT{(d/R7cNW<믾_W?k&9_٫]pBn$M7^f}粷VOă&HUJw”~n7568xe/^h{bw^0SkJp;tRKҿp5ÿZ>_f>rJv+4駲ƿ7{A,gwdEUj~`\^Ϛ~X/ }Y{0N\ ΆUCa"KSo{$Ejx@edўqɲ?{u4WND Or#%/~?yJミ-۵MJj %roz*H8"Q|-R \$""fY[Qx,d/\?Oͺ;y/jKw?_F$II""V1/S#vx~.5_F^x s 7$`vjyWzK8_Tg>~"ɱ+g@:!]@:!]@:!]@:!]c1;8R D+BH'+tBH'+tBH'+tBHJ׵QJx,jyTUg&Q&ATSs6fZZ73ͺumP`feLZ䬈#d*ZN8 2a@zK%}Vȳskzgw(F˿7rj`=KΊ Z~4b{ (q9q~rV|О%\23zcؾ-+V*ݺ&Eؐbl7t*KօI |Tr\ӄE[;G3 bt.ЯkbNv2n՞'CY[l{Jտq͗0Z7sUC=PM?}QznϹt{;x[7zв3vɓ]Dp[,GoI>3kW'?NwGz9tUsi [sZ:YK=1սA%UDjSԦ!5eǖdʓ]9d߬+k)Z/tU T[0ծ15jA57%$s'O}Tº?h<ƃ8uʟ$YxEDDudװ}皛l}3IҾZ1oh[r41%m]|n)78޵Q؁ FEւ Mn s˦vPcDXnS=+{Y85*S*:(WhG! J֕)z)W6t4]8EA-N >*}NW/?Uil/rf,8(Wv])n:>'nQ>d}YݺV9?\]>wkoo JFmnݱsuݯ΀N4qg["Wl5{V۽*9WӪke ;Zz,=#]}k@ۧ*oQn_E_Zοz0~@I)Y3ȼO-qqTrvk}ur~ @YG]艺u' @O+=QWzT* VvIkWD]艺u' @O+=QW%wr{.l]7YSv}|_Tqj.(@E1dUi ׾٠,} Pf]iWcX0T)e,ge/W*v}?K<v쳫C2oY 3W4txt=Z˧SYV9^_|iO_q/pbo4XMSނij*)W-\sR,J5]Zћj{usOkNF-/9&,wӻU /`sפ4ig8 |ӗ!/g%˹s-[8(ˌ{>?=Ns'L>aǁكvx+,I["")G~R5矈ޑd=6}""ڍk>CBn7zȜ{g/=53"Pkg ꉔWDpٷDzC~oOn|\|;g޲y3s/MKմ:#Bw&1crDDĚ[epiKخkCkW-Z؎OFws-Ap#~ܙahs 3Du_Fj6Rjm[eɊF :Ԡ}WwرO !Oݱ'Ƨ+5~{<:!~>"b͗؉cabh";~׺g{|4.ạQD| ӌ5dnEj4oč+v%᪈X77Lrq3sa(*ik3v҆ - [Yym̙=HDDq0^dpr6*Z~AލFF{uScka]|jӦ鎓}J; Ii{#ATZ\fSrVMq篫nA1ݴ%CW}]yȒ{Ŗvb_Svڮ9 kh0Vm}=n{n=٧x^;""{wa<1iìiu>.YiVR:Q+xUU5vLvXV͚Yw/w5"V<[eGΟ\Koҳ!-5={}wdu[,iW>sh|kfKnZvYn5W{~}G1l= )/_JUDM<qu(wwwt"^+1)"m݆]=cF X/wO>cENӲoPKa;99nswͼr,dms3R4rseQ1j<=,*"xO'iRg{<V\i\TV\86,1ju E_Iα{9M&kسKS 4'J+zإWEsb.ܰXs/?b;:X4XSO˰wSK߲4|&){Wn+-+v7!wmXW"j~z-0Tn&RVާKÿKN2>ףNjs*O}0.gu5x+KZytܽ[szvp1 b;u2.4!X=ǝҹ}ǮO5+YĹſ>F]v9식5Oq*=FOu}U_•;-b_5}aQ22lgemnYb>^:*=* _ڠi?x: ({ݢ];bCs̚TIG}*;3eogu' @O+=QWzD]艺u' @O+=QWzdg;!z6))JT`{ CwjTQWg/\xLVn{)+EʕTGɕԫuaSvQRvAjDJՂ|cjƊ^(#,JA=QWzD]艺u' @O+=QWzD]艺u' @OmTwIENDB`kraft-1.1/manual/images/de/catalog_standard_fixed_cost.png000066400000000000000000001261151450127457600240240ustar00rootroot00000000000000PNG  IHDR}B2 pHYs+ IDATx^u\gA KAl_ETV0[1;E@P@'(D~?^gfgfgg@!7!Bya8B!>p!B|B! B#!3 GB!g B0A!a8B!>p!B|B! B#!3 GB!g B0A!a8B!>p!B|B! B7畖fl5U5Կ̤(8ﱿHQq1 I+a:ɔ=Bͫ ‘*7edfkc,//{௓& p!oM_8B, οu?/B%hp!BW`8B!>p!B|B! B#!?15n֩O?~eHğ;}J_@,n!{)9!='%Qc^soxf[ !Z >#eOO=;*ti \ʷG=kpIZt@Edz7&P/\WV"ML?#m:d(ku?E\{Q[#Ʃ|cI{ ʟ8ct@wN|4̀B5V|H;.;ySi~ֱTCe^GbǖMh!iҹ@>:8Tngn C@Icw4a14G񣧏=}taF&Co&Š=;h uj" i qbn/M!*x22gncgRK5n.O'C'#f#9?(11t`ddž5Md2ûȑ)чLHоs62f7r8ŠFvk7vXu]xT`j+E@e̮iw|wfAV~J؛B}c GBgT83 ?>{Sm ?&2祠5 OMh;9P9b"a[)3>UPW{{虵痾=%HpIe`0 pdqn`;+)zԯ|rҸ6(ug|UsŜX/ ar$]2h͆8L)cW׸bR Z?@<ֵHYC) 8 PIF$ *>qS>GMY}씾"Ζ@>hԵ˗bn=GoK/(T2x[O OX6-D@ߢN _"(ԱaĤү,/A }'}n*}|{f=e ԩB9@k+KKL-"Mp7xMo/IwkwNbFث+$^~-U4v-EظU /rygm^Fyuo6Jm#ktȽ|QM4 3F|2>Yw2mz*qgǝ9*?h=n{-e)_{Ks&OL__8bLLN*IO*&:ٲc ]=%]'X8O_0MgUm]2yqHU!m=}ѽQK70YeppǶm!{tI;XɑTƥ%duR#27yϟ/|` -{ݏ_,JHՄO~z}CH_׊zwԅGhP)O}Zre:X].4[@K˴Dz'*tC!Udlv'̻s S;=6˖T$cNۺTN8vG*TVP|e=g}eb<C'F`t**i! 섻 ;XHT{)0R6I>6";VwX^DHHN@*tԑb ܾJanTGFn}4QRڿ  N&ṭc`"Fu3ɎJZ>m>AWFXX2tm]@4#cgOowo$@09u{RNUud2RLY[kXE=;?`(siߩ{k Rwp0NMJ95Sko $--y⣄Uyw6ٲYsCj&DġƯ%h­ qaz参=F%I nGRL^6*@i$'M:fFE'QQѬvirB0dwb~s]Y:i1Y4 sq!捽yݺ\$\r"2BU*)+/K @*H3Qb$ɔ.Pu #&͢;s *߅G%m|+$#e,27*BKWTBZCq%U|q`n:UI*op s"٫O-;w@zAZ"]wƯ$Ap ;QlJĺ7 ZJU{2 $QiZ߷f#&ўbJqܜ\BAIj%Ĕsr)qW;|x Q!S}FX(~] Rftv)UA @T`0(m秈3?/*q_s>$4|'ދ@g=]?vU*I2 J*Ju2Btc!-/>xX)tVH)ɲ2$rs NwgxyˮXs'H0 ~B\RKqTyi9))%)j:`pbJ[,^IfWx`c :O ‚BD $$H )IAC ejе4?m6S4L̽wh% )))Y[F׹е7ױRDJ^^fHpz$î񓀽O;0B̾*{ǭZyYS5Uh@gȚȒ\AS?^_?cͽ/H Yia]=tkPI@{m16FRR@gE8a=aaFM7.έ攤H⩎}R@[&Ae~ygꆭvjńQPPGEG+5rXwxmjEz͢S3l%GXPڻ"h1P|qylMb*_sbhX<~rŔlRXAǘZ5Oθxj6W"fv(P5f.,e*vp>D< Y (c;bRDBѪK']>i!v< !ąǧ f.?pG.^J1TQk$L{m#V{[׷"䋫$ظT3#l}xnaBtڊ!&-t7oWH [EٟW\бS9"~k>j)p!B|B! B#!3 GB!g B0A!a8B!>p!B|B! Bٿ9 ÛBfMޮ "2ꆖ}Oj*/E!?f; O?z||7 B!%;;R 0ZD(|[rȥK=Ecc<]t f{Bұ>I=\|XHi>%'69Pt6NŊ^+Pe#!qٕF=Mw*NtYRnIzi RIF$ *>qS>GMY}SOl2 !K,m;Q:gސv+zY i/^}^"n5fFbϋB!~̎T3bښ) BnF\Zi! F.:+2lt+TգWw\6"2xM;w^}1ѹ(oD:=G?Pu (\HĭS35WTSםvK(oc:ۯ\ vҞ%g*T•ߓ>1N z*3iզ 7_J{^B#aeg3+7C!T]Rc׶9?GiۣY24* )ebA$-%w'em%A@j Ï\vJ$0--[Wfgs `QBHF$9ZN.?X9t#A>m9B *lBc$ t'.iIi5C!P/0N;yx:I?1ҽt w拌 At=H$RFV H$$$%tbBRZ_RFQ,/AavNFe$UܭLU`0(`;2P`Ԯa̩x?@UVPelRZ^ bQ5C!P#Ai]vF>q#YiE=vI@͍SQ4`IIy5vne5vS.z_z޳>iqCK~N {9B!hŚ8ş#Ά'+JVWQ&"V2 e?tK8LBLTöq"v{oz$T)6wyŒlkJOZqC϶ﬤfxA^t~ءS bG h6rGkWWn1mQUi7xJ| B? _ĘuMmAXܶ*lP}!BMǦ&&?y=!P #!jH^f͛BgGB!g B0A!a8B!>p!B|B! B#!3 GB!g B9!='%Qc^soxӛ{o$w{;[I'>7PFsMp.Qۛtz2&ЄX8׼kyM;{.2ؠƵw!"Yv41|/CfV]aWGN-#N܊ :H;zO;zk؞8oF"T!/ 3jW9-.Id6k{Vr~3b=vRcE-\sCvN>}x3j׳4̈́!kc :0L $ -'%LM{zyK IKPj^A0 yq%AaU~7| CSSjxzXG!QJ3Q͎ =׭dj J,T ț45xCs 6 H@\ڎ'/gѽ[Bm&#_ɨFyo:?jY?;kc+Cstz;u`E/>e_6Am\<睊+y]Zغ}{8Yۻ{ T5p=Kl6"=/Uyk=B~##/߼F&S c We',~Rj9Vr$qeC#"n'}m_( ?/ٯ;w3*쐗PǵIU;gX}gBzq)bX@pF5s&tNyH}ףY~GCW>M u=ߜP6xv(8;xrpi'nOvA2_ ^m}Ԫc#:. qz#IH[Ma,l1̵;RڝL;bB-?a}7 Ii(|AՌ6yw6ٲYsCj&DġƯ%Rw>Т*:+1(Inp;;0z٨!io_\czL֔uR#hPw=΍|_8'u!!k>'ŴBڝ3*d[V^i[7qls#CtnGn'FSd(ܘ?E_ZDXNb$R̥q= EBDWVW6|AAM@wLOJ9,mϱ LPqoMG9_{qtZ& IDATλd$I)ɮtZRZyI gOua )IYtYTqf*mB<&La[T%"R ·Z:x}j]_Uc?ڳX [)1nK((WbJJb9GY0ePYeQ3sG RդQRV^8Eѵx|_?UQ4U*S)ʭxwpTc+%@i{7_>zhͰ]3:5ЄDWW /o+\B L~RwdhsP;vEFIBqJ &_"+mHCH?ʯ#I Sd.[/,u624G=3M&XTUuIIEэ'B3nLQ99GB!*;| O>,4Y% [~8E(((Y#uۢ@Zv~_Xr9 {N6t"܄W *i 4 $94HI K(i^wyYy$@*iƼ+*㫈ښ\;v-Vݠ+yV HyfOnʳ%Jy&RS`И&:w|Q6̾v\B gGߑ;(]_!FU[O_E"bjo{؍;܆4V_2jjbb iq'k:NOJ.8U(G~TOBBZ.JypJzKrœLHy3p;9!n:mΑE;cJ7zA]Gq[E>9w~ ؈`gwHKZ:E2{kk+בF {{?\01i:[ٛwƽ(gǁyJ={0/cgͮ׸+*S7wwvw^tAH1MhY$ͮj9u-߾΃^wXa|}֔Tp0Z>t!GLHt5f.sKn2`5YܐQJ8߮{=~f"4+CgNƻuv3*pHK.f]Lm&OQ= #Tg:-ㄪ!?/MIOcbͺ𦢿8~~W=BcSԟrfGymF).3mBo_;;1"/X:X #ZB H GySB_!3 GB!g B0A!a8B!>p!B|B!w$=nE97! 8j-*m/yAkI))Ss#cVLl-Ңge޾524M;?񘤑ъ/TxWFFx# I 9cB-hI9߾...Xi)))6Ssώ BMi`Kq!B|B?Xs?W1A!B6;B2E~fU GB!gXBFbo#~s؀Ytՙ6NSZ5'_mJD%wAh^q@tyN(Z.IIpο<ݪ堝qک!m-m{Y;oӭXXYZZX9DL3]&y1MoW̬#&R-9h&RTxIzw>xҪ˟鷗g!w^ L=2j-kjJ<:3e$nm#Y5{BDG}jX#ӪIo^y+MnZ8e l:̪Qh,B\-o~ZO5 H$5GHA7'>04{FJB9)fK+3xTVqC=`(vtPMDO<5; M]v6B$/mKWL2>\͵uiw;:GS7T.о1$նaUًO IAǘJvL(Vg~±f0zxp2"jxf)ޥn" DIVrBri Q}z , ˊ =DKl[8CCƠyjېų/.0613fU7 z]rrrqsW y#fi[^egև$ F0Yfht`Y7He^kqٕnSx;iΊu}++ x/PI 9:oa Z;TQrvBMGfnoP9~16m4u4iIb]{Eu3QA@7b=gn͹z֮$"k&jeKʄuΟO_د !=_WU'|ͭN^~yף ø;jieJ :zPɁ;dv]Nxk^ccyNnDCQ5EeX5 1$ꍐފ7gR츳m9v+xkcs8 GlkͰCAO;//Pz$C[?Ng> L11S ܵ;. c,Bm+.]v_+Y{]yvW/ Tgٮ9^xfz wgB#np1{<8?04dP=VOo9;WO֣hb*x ׾H]]};ȣ!7ï>_{YХk7q1sQ_ l{`Y&rmӱXJ}dt)To/d}VعU]>m9Ô'~}@!4Xys߯|s`޺^q~cZuަe-=&]܍cgReO.Gt!B4:/:r1C֬|L@a&L ,52S8@}l1DL˜I`mR$!ӧivMT[?;/d*N?z}d?=QoӯwSk7ËmG6WfIk*CI]BWv0WmQmk7t:F( )ob#Gj[qX/;) )k3н( F 4u:Gǡˋ ߹ %-!JHI֚m+ez::;;:s8S'9B/XHhszA-S I&2s- kI$w)HM+G .}$!iY(n;Vg3Qf~^ B_YXޔ6G@syz}`|WBs l'E:{DWX@غ<ԧ+zMV&UrsXu;40*-XHIqhN~NBu$p[tvn)e/m?TYMV{9YH@URK~lXA*.K3*VTTZy5/PZWr2&$hj񑐑dԤQ+T^N>+UO3deh f{CkiwRɞ $vj2 da~! FՊ Qxd[3Uq#$ IwqdCO8)bęgߨd7lԁw!_I)%H,#cWuyH)Yi dHHVݎ$I@k̈́txQA!@JhhV !F${6e<?--yR8)Mܝ"L=O!wם֙5wUc(ZHUͤO;!nz˦w߽l`AHv3*;RHI҄@*-.`HIٌ=׶!(~1ck*ZzvIݨx@[F r2­<6F!f~ mO' ( N= )Iɥ@;t9 `IIW}T z/Dsetv<ݶ1b'S7<ǵBHJAXR`hZ{-Vپ[U5k[gz$;vӠ_#^uޗҜ2,+HRKj:[[åV"5BN@wpφ 22 թ;Jb}g"NN싫}m!^+i)( c@g%K}бVzzB ҏ^\RǩgFQTi 'FHQӕh],|ѧY,hvQқ9T~\}x^cHŗw}YyrmD"ɩ"<?DJ }|K\ }֑vF =aTFHsR E5xAj\H(ulmo6y15w/9:UEٕF)e'|>MQbR^}.To)aUqcMq89On>l,!)#Y9>5(xr.E>8yO>ϏnzjX(B| ;\n-m]]zH~1RF[w߼us>oXuI> t+6|Nlzka0|:ԲWG։j۶> zkƻepJ5 7E%CVܺsR%j|+5دD7B}0s_"Vh`RF_xBMgsd~N9- *Ҫ,QIe_Z^*K@HXy֢#&EY1tb~=<=KCHGmS$dm922V3ƶ]&kVZa#ieƝR Swp}46cڶy{r1Ŕ<|JYaQ-VoWQVBVqM zARDї؇{\ɯ2"/7'=17›%ySʇkKl<9՘~qo8ow ΙvuQW~wΊ^N4h񻥍P޾R߇nYYY65]ܻǛsN6***cSԟDTb}y,ޞ P'^?[AХCv2hA3ks BT,-uUYFCLlȪ)]q2tˠscS4)}\ך j.#"&vǛx1Z{l8Z- S f[3WyB. B菁B?ޫb B B?F"C*#!3>,dgg&0 r-A 7+QQtEE%)%)!MB!EoJmڼ~&>S HJJ ߌB!T۷oW\\{!!! f p!ПMBBNp++B! B#!3 GB!g B},#-E[j3)߭Vּsnnև%kN:m:vq^v}-d=kE8=Ӭi)B?J7c[B+=yE *>ኝmւGZ·[/i{휳=s0/vi>ta viYA Q OL¶>u'͎0 IG0gR]i)B06<~H14h-)%{wo80e\#%k&]!KߓJ~sl\پ.J+7v2ziṭBRE&Wl&E(\y.T[:Rʸόszh @[b *q8ߧc7,ߪ{ot7)0UaA35*6]5v2EC%HNGXkԟaTh޻h  l3ʭ^CjEa=h/wZy u5U&6>9ͅሲU?e$4O6!c;{Ø{\.@^zNCTP `$K}93hsM*ٞ=׶ɖ3inKIKB#̌=WAxʘޫw^Iɹl;0VFPXxvv_޶9ZY,:Uºz*>TB ]o̴ +mn.BFWW9 G'Ms#;_eV1iZJJJ޿/..w‘?!j?ekW3Rn:_eQ 9BCFuc:Yi/?Pki(YU)g_OP0jtX"e#:0$=&|n4Ko]XeU!|F0'!,"LP@2HMH =e o<״eܪ 4/l)B Pj.wFji|]/)2;ݮ:HՈD2IC0Z}@mww@ )i`RVIQ_@sr dOC**+@Jjiɵ6Q^ZN@"CrDDEelABXLq3VOePi4j^7_ [B Ñ#jʼnQ=pޝLd~mZI7 n3{9FTnVN% t[iQ(Y  *#5SH^^zN>WT|JHSժ BD'$r@U33Zy82L%ToCʖ"hC*>!!#E$ŗ3wb IDATEi0*|P, k&Ʈ䮴SJ FdK8@qc&S RҒ9fq CNSUvvgP%YIi eX|Jb9]yw_v.u?mݼ^X«2vEaz/ER`8#Ѫ>v\f:ᘲy@A V(sLinn~>Ǚ0:}Y;ܪφ$kGbuEKtt:s8o0417`~Fa]?K'ss0ƀxl|_KTCD|GGGu"UyP\K}zudf7d%|oR4jj]yi?iLY(-ǛbE.tܨ_!`sx1TME&::@EE@}>zljb›%C,*>3 K-JOOCysمn>1d}oY;8*<!aԩF"p+ϟЅ!s{mO=B\}g 1 :@Ju0N-VcELce@hc܏zn_] 6̳Im`;{%A@ڶ-&g5XHKŇB4!>!Ǜ I M naa6oںe^/iI vNYsk_;RV.q\ðE ^?x֫ $JRJRM@4 $7)%+U_ɩL;=gaE6AQDwsͼiۭ~iY7m7pCEeMmca 9Ϝ9 |y3c{joiHY2cnL$&魌\\,p ]Hǧ 5[0oMx R9 2rᄑEHѷL潃9Z٠_;ýu5n{/W0Ow< ZSUp9mg}پ̦]E7o~ak$ZN2`z%$${G3}=+>L u2W\:>k?R}pqBScёuLkO:MyU+jwۺuۈ#K zʰKٳ'2O~FG>"!@/f/KY@d# 20SzbnX;r bH"ݡ* 5ЋTʊrO *Ξu8ٗv3DFfeͳJфr8Vd_A.;9 nNNN=|+KY@d# 2 qD8"ÍЋY,#G#WJqvN#Ћe9***ss䧹`z&d+S߬'@oc̾.SRGwׇ?# 2 kG Y;QEaz1ɚn#=Z3a?7V%jzxhĴ 74{Po};?ˋ>{>CdDD_`ݿG;ZgjGqz|?K8w1w7>.؁XSII$]ot]B^LkD"H%COLո}uyѰwo%4ξY[,[:Rw߄^vy2*, ߡXx'μ? |-򏶟o =y"֐|rt w-Vy^OJ9۟Z|_/ QEQ|B}Q;/(km{=g l]Ysտ&MTλkVtH(wm%/PgtTI,ڲS_8+ekߜJd9/Wucg ~k ?^X p)/0t ;DD$o#eG k>Sppw3T'%7`{YE~J܁:mMqt;53""ِ[*%αD3atzRRO?ӯ!"bcĹp1"IxbVA`kAf۴_C+fO]mlfq:?_gl1i_ٶ$cS[y*>%+\uD#VbH\\ߒ1f"x.Ӻjef~ uJ"&kR`m% ᜴\S >c'@$˳*ls56bJ\l9( -Uy'K WH\ɾ@f#*H(Q_׏jl;ˆ1b1N=|67ȇ)ƈ;^yɼGfToTn}ji)M&.^_޳Um$y.m;l{j.ѡq]yǍn]KKhm#F/˳gϞ9p056&ƾaDXO\zbtD8"C 35ݡǏ*֎@#@/$z"0YJ(𴯀Yg}i7C^l@ddV< 4Mhh\.N#ЋiڨMMMprS @NⰔD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d=Gnsq})@6ξ-Rnye+:pkGKqD#Ud  qD8"C!G@d# 2 qDvJ/k]UeѾqueH\}s}\U}n\8p9.7\& qD8"C!Ȥb5pMS}/cЮ@ԹW5*'7_x}%8CDz=uHs"s@!G@d# 2\VS,W(K;g,M1ٗg[϶ڗwN(ne#Ǡd(嚯78Q\9'碛$Pw㙾t޹rLb}ӹ'&cCN`g'6u;!Tf @1C}+:ooKNzH![M\2Kpg<)!"8aIZ]qDDԸo;F"$!~Ʃ|T#ɽBbBUsyw٧y׈ɏ,zdP}Qn`2א `;U$~zu3>L_#!oȪ ?RVܘUap 'FN/N7nR֪!sxѷ?.+KWe?^CN_čJ?'|, m̄5`ƞG4;l?]K1,x{'n?zpD"i,+n_O`_ck,ovqѶQ큕D^3EߑΏv>:{"n:xO}y@VPy`I)3۲HG)TN\/xeW5?(r?A<8|m _жô]r/~߹q帚O;#oر}\ofX$pm+Y{#$D7K?-?3-ð]ϣkn]}%듅KE;]1tv{A};G~_*""Vceq IJNzȊNoܱskyV\j;,S;ҽφ~}}+~.8z#/"uY؟>;:ysDDd¤QcƎ35Vj9~dҽ3CU<p˴ݥLo==;"vM Hs KTT.[o RqcOYMsI?<1~'yg$ژg'N>i%"b[TȬ~X5b(gSϘ[{~i(1rSNoFFD)G> aZBf:1Y9徙6Lwc 60rQ$7-k9XpI|%PSYȇH8[^9k59Nnn啌<\QQv8wRu\_=%bӟ9Uc~z]Vj3&X~RW?P͓*ukNy9UVbc:Rg%kM{} :qǟ51b⬼v$""k60f(u1qj|:}e='}v':=9'3W'j{w_=t%5~?3r ԻY5tï=/d}JR¥R}tk/ΚVxϜ2ttIocOF5*e!z( ɢ\蓷ߺ{bqUϋB]۪.v9 O2]m=?̓uԉ}lO^cEz0;lEߓgDvlp :=ځNF}%OMUOqOP ںzKt(=}h|})\,+n_'\xG~]0?AXkځ11 TOLDcqD#?l/8wN/FG@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2}AO1YO66zT,̉+B-E@YeJ"y輽|Ǝ-Htq"'hCVJDu&aƶ#$@8iĄ11>DTvlח1utJcԌBw/y"Ѭ0CFSôM-[ni_Zq9ھ*~z,q𐸘nP IDATVJ""yЧGmp-X,6ms,f͚ ---d;% jSޜ5塵96N;8s]ӟ{^g?ôkȸ!qq cowtE4n`_]Wͷ1۸ȗ#6F2;HUN]V2(ȼ c[P]>"8Ǵ6}܈/^O}%rKs̎ɉ 39پ#֜ѓ»kAroܷ '5@?Rn%{a]|ȩÒFT} .{N j Pd/Xd% 5"5G5h$+ V8/5}ܙSǏ=jQ!%sŭӚ9r >NcDdk[9c)f""rO;aرS>UfC{LD4~i2챉I 64oCDIվC1ڜ\ K[8_]t{nGOΞ4n쨱f<|ǟa *+-yxؗvCQYY tg»7ȉ#""ycw͘4a>lk3oznSE(ן;W6:?龯J۟:Ll}Ǝpӽg "IK6co?lGu&O&"}/ӄQc';[mCx=`3jƌUѩ"ݣvWZ~Yz73v촿=U_h)hzmR^@D!._ϛ͝1 S~I͙n#sSܿ}/(֯ow?X䍫's.C(۽={.[?xEmۼlVDD6gߧ;Jk蚭[WUE6o-ۓ3zJ}4leUW'd'uwKK>_'6|.zW5흗&^mO.=uńU ?>j$"b;V~\6zKHxr~xycS; >[_ʢm;ىK}>aА)u|8cW4|oyv?ܱmW(kW uvQW~F^GYB 2m .ּOWd~qg+[_ĺIs3,8"l]9 :)9xvo|aEZR'-Vݖ0|-ύ|zmBn}zNR!-[""t֣~s#Ft}B|ʪZ}̄OlbFJcXb[NN{k-AzmcՈsyN]7@'Ψ\[}◵y3c/5|]/:u0 W$$ 2]bfHHςV_voߣΊeϾ2r/Fk%Bgshۈ$p;]rwu7qs佚θ,s l) ۲|Ó<]e]|KG6e}7$0ᶥC{ddQH$SNꫯ+:nݺ)S&+ʋd}Tp65 _5osxP)C͒_@~x͝L59=7c=ڊHEQ'޺{∤Qf>,su>URhrRGHTt!{uBfg}ھjM'xJP}H2gAQ"'3+*Qh#9۷\,g J\eg{;׶F WMDDPUwqS*m?+r38L&QCܕݩ]n1Ş:[l%1.rX}"e_jH->qXS@ I.|c)Gb;lh9/mP >Nsl_}GwG(:z}\ӌ%a>Kށr""1IjOݛ60Bĩcbk&xDBEzF:n0355dIZ{"9Og&N&iKٽӸvW50oͶR"2VU{]c]|gg,cBX %7؍'ɕ jn3JXC޾}gML#! !N=tG_G.[lR"Zls>Dp` Ez^3+3!se=lPw VD YZiSUX rrDr}X;TNjSaaQ*PV;'n>^ȑP]T58=Hw<~빈cO?Ӿ%xhe2A>46!?%t),ca֌ a:9pfGҗ=kM~qĘM QtؽGS,A{Y$놵*`< `1 $D)oes#9BN&Y0Z, r&p.'Sذ$enN֮l?b`d̕Y8"b-"uSyV i7^SoeC]])Q#BԶd.=mWmADDĩꢣvZ { z$sϖ,k=]%uƘX&=K^)%aO4,BDуH抂` k8PAEOg 1-F"3$; T4}DQ0?/*'Z* z1 "p ѺMAԡ 'ULDĚ NB\(A쑝ZY/y2aDDd.Ms?>9ıdGG]1L۟In/u55y6q֢o^ҽD'NOR퇧%%&նmŚr~\ra1"cGN{h7H]_+.D| v4RRPRڨ<- 3ygD撓EwIu>kYvA&Y""fn63"^ei1w w(9q`%"T9eT`!""Å A84-3X"b3JWg[RTj l)!"bfJd+?baD$kO .l'S3kn~zK )m VܡA{t5UV\>6sm%߮&9?ՄCehD*e??vງ >@[[9̹bk?y>< }pyfɪr=FT~*e'˥uU׌m`L|ϩ]3[cP{eGLp TrD2aǏm[H":TAeGu2OÉԽ5-K$J]E,}{99ƎҹO|" MfԺC5 d}X$i85=Ǚ 6'ktCC8"bbIƼ;*Ǐ sW7*B(8"&k{JqjAIn%"]"rGn TbLnۗ]CCK/p`IּW*Y,ʧ,}Qduy3i?Z*2mpZq>2:B,& kmȩ=<eE%;^yߚܖ#5mڤn\HNipR)AL[*{񃙞x ?sBqכnI[53o鶅Pp{t#ꠔ[$Qq{ȱLjw;k<;,x^P{KJDD-opgon0`xh&aç}$q}0녟7E\7^¡NE|kT#"=@ɚKBl#eK"XzQ+/:zвKm?đ 1@d# 2 cсMO5uuDD)wJo~ |JųskGj //O Kw3p-\ƍ P*4ߵ/grUE5JoǮ%h@WkcёGJjEԝ8]hb8 /tހʏ:_m`N^}C/0CENfV~E}UzG ro z.8q";I ~"Kvq9v2[OeG:tw`Pxٗ]#4Eg$TH=n3brPs"e)aN؀ Ec TH5 Jlj756q=K@q\Toc焑!-cИ'}ب~ͬ ;N%'cUޑSg$U{W'爵>_m/ ېv'oΕh#GrJ͜?2&בgMCF 䈘,+Diderא!tr69֜,[xWDLL8}_VA\!qZ*3WgؠA26f*Զ=+ؚ6rx6jIdF T]tL+-:pDn}|8sO\:N#NN>V7:܉="5Ufw;)?&f)jb'OD)`ZS[ʣo+\ Ijm V8'JĬVAl,O(5YJ) K GG\8:Ԯf轃\tݥDDs9DubCΉ}9NY} #۪Q`)8"zjOJٟa;m8\ KR"bm #:*R2ÒF;;pB-{58\.ZI74 AҜHNQ[ [#bFR{PBǪ6 ٔVw1C1115%璊LT o>vJ$(i y5_5nj 5&j D\o0Tc.8~(X> FVkRXbfCC]0:mXsAzfBG~m8Z::VsAkwqQc̙Gl+Gx*8nٕxc,3TdfWԷX% w -uH$VG$?SXrVX;\Y})q.>^ek**lhXaQSWM;S~]=|`2b$9c}9.#ힹѴRUOϤN=4[LF.zʰ`--k}noqMMM]n8pbN³:o""XThs-+lm`>UTl2 Rm@Ԑ(I}F٭x1#G*-(*:C 5ێ+w?~ӉM#\'}^tC+,4zGG kDĚr5Ź &&w 2[VPaOޜ+F$ RY 2֛9dL#ϚrwnǚOy)n\Gk. 8wxDrW/7)Q8"͂YY-FR)syn>3,_Ciߢ \~=e&PSPL~qZCɹ8Sw׷f[U)&,GvLWK#'O)=j\"ΞNt;_kRYPsw'~_AeŚ O7 >!VEM$ؿfCǨ+2S a'Mӌ'UUP]B~:X)" R҅o*)v bR7¤N>{6d ye51yRS$$8p}RdREH'.Sy)cYa8_G #OǏM0m?SyAcQǝ&O?۲ޥO_/>^Ι%&"Em-% g)G-.ׇvhJ?Ӿ70lͨ0YH_#sQslV VKSRf+ bwqQU ۰/o [[Y=.-O?L3[4-ʭT M%@6YdQ@a{# nLW=ޙ{:9̕N?xzP!fgXw NMP sX$.tԣr{kѡr},'ԧ`5[M3Ds !b,}Oݮtr [=ݸ3Jg/?-k!0*VH"&JODĘx8V]JΫDA]79V""BZ˹6/Ǔ$JGDDBOW] GDMuEyFڒg/a*'"NS]Z1D^]梪z"uE2+KEW+T:Gfw"+ΠR(@xxH򝽚fC\O؟&Hl\%DD$v ORq)>G2< RSZ%oϰ 1q %VcaGDtzJ;OX pw I]d\1 1l]g0Z#FSN g8vUQxժuDDz S3*+<#sp0ʮuu#ur2])wthiIչgϤܧw-D. 9 222Ilֳ_/v+E~,#iTWY4t Ù/P($& ͳe@#q9(2bZʱtBVB$ +5Jϊ-"̈r/[8pv^Lx8VQR;+KfQN2P$ {%>NN'>@SfBQi\Eg#W9ynуYo|Nk+^F<ֻqf @'md5K]"IJN&АgBryhHH@g/ "uwL qL qL q&bqMMqT$bqVVpqv,**)G$bqA e]]pf ;҉<`\hSDx_=8҉tR 7kGGGGGGGG:IrfEE [V,p3sOUlycaW_ܵv_.'=(ĕߴt9>M]c? X{Æ4Sw b5 <\`ܫe}w g.yqyHR COrU9's s ?kE{-ȡR5$zX?OsiG:`>0"k hpq{طq1ـ/gu)zQBߪѱ 3uϙ+?lfܳ-qrm mzu qoYZMZ#x/ste5#`3+~ɺtfeBW|?rw n>1 ?sA\KҴ=QqR|\ q#z%5B#{O۳}GEG={~ؕ8tڸn2"D!&_']YE>4(ж'==b'^aLjHG~q!Le^gc>Ii[ט6OjOE33=#%*? B_Avч?:;@** W~aXF5`#ggP/G<0]  ~nLΦ9ӾSsѣϯ^yZY?/^:Ʃ+m'e~S\vLj}X!A=DDqqynC3+y/fRVYi/qkEd7{u5=d!,o`+V5\NP F ,}vr]Ѝ(&"kb:ᅭ}|8Bl!Kǟ٣X{n"1l#>p Q7}ED\m͓6oU}ON8xeܓN|]_2~w |=mƕ?}xn [xD%SDd(*qOv֟]:>ؑz83HOfm*F?9 P@{YGmk˿Ռj/t8_9}G[ W@'$ 扈ZڊZ I;OqŽ'iZ.y#$ 9kgf<@y#6M]QsM%!~1d\ȵw7xUEe;<ΔE(k}&RIM70fOA>ѳ>EfVO}ҋ;""b]̜.$CVOKD$헭kg<9zccxMHm"uoe劸QK֦j#3WKr-XIY= gM*ް~iykwђD*f{}hƳ|D]?td\a/?9sXvu}ٯ.9Z™Y-OwIn!1ݷhIp/n:u׼񋖼Ӝ!d|&g.En 3WewrW}}LH${5G#F^Tm7:2i s[+uy|ٺw"|'ZghvPHZ^UPXΓ5գac>>7IvE%7=-g yYżTtoigAeYWv7xUYok_SU~5NJ1%"bV^ҭ9eeJ^l֜9]&} BЬ""uiϒ Ϭx[1mx#̢Hb }Xd`5Vf.e꼳G,-;eK<fL/%dH}eߎW>c-I|f՟_g9|vj9/v[<嵝ڡ^<ʪCol{uAȰg#{ ~mvӋ v\>J43SuO~}I3Xw#DN>D皽b(rM mڸN801h}qm4@{aDS#>pmh#+01ܬv;6y~Ν;ccwܘ1ƍcƸk'05t.W73fܴgwlۦ=޸3g)}7O,:kovq yZz@i}1joϿjЈ+?Fȓ~|9W+v>xڦ|ʼn/)N6.& fRԀ([;[{;訨U~BD&zuiqڏg4͛o% ̟oV>+ol?mmg~P2i[R,` 3<عC|W7wnBBBcaO7p܎;t7M޵Wl҆y"iZ߾{hv*Ey-䓏? []ݻz~yyJ%RG~cula ixh[k;i}]p{s>}e٩슍mHmB_#^ϥ""*0gQ#F}~Ee^ޘ c yB+=;O5ri\+v| 29[/sD;?X{6܄#GL}S\lw;~İFNEkcZ)0%F3{Λ2lV&%$iRGG:dl{asYdeeQ>}nL$AA9{7+#fTe{dΙ?򷸸틣 W]s^fp駯8Xw ?wzuǪy+|EQsw`/_6̍%"^}pOݽoO}ᴖ+sѻhظ=_q=%>u.%ܷk鈪ڜahq:wW_λRѼ1g &pʪ*F|bT#\|{FLEq 'nL$ ƴM1v#+3?wԧ㏘=BmBM b "F)({N8{nh1# 0!ЙH)mĘ ^\p2-j54}mpwxy˗{yz՚7f϶?o˲m1d*o58E~sX|g_Nrv%= Gje4|}}R/FE {͝}\Lu"?QNU-u尡<32(EUEonfa}>^澿pGk׭7vl#ibTcLW!wmٱr5O"4eJ.,Qub! lḷmhHPY[ JJyrhZ%(V.ƥ웶5};ƪu7>ƍ>}/,BD#Ϗ\ѯ U:0q38K Smӏ5;Vߺgႏ^ctlqDu*/Ѱu4lh՜ٱ%Ia *ySQ~uZ:kމV-8UQڥb=~?nO2W[]иkHߜ+̮8u饌:=:Z-֥{7GӔyWy%/ʯЉlt!B|B! B#!3LGB!g B0A!a:B!>t!B|B! B#!3LGB!g B0A!a:B!>t!B|B!L;p%%%Y,{_*9%Yw2Ƞ(Ic B!r/H@AA{_'337zzBy5S"/CS!EEŲ(B5FHGB!~#!3LGB!g B0A!a:B!>fq3|`sTZQbʹ㼱ߞ; ; Syʪi*-p-yZSkVpǫPIFX̾ZGґ;z^3BZZGa:3dᗍђj=:eTB7`wec~2y 0p`>GPto[|&ͨ"jeW^bj%%;,3u`}}RؐS`h9N/G?\S!yz7棖 *Jo-wXKî% :u 74J]Y1>ȎT'OƳ,~{|ϼa~}*$f2q'ļgBlfyup8m˜Yqgz_@u;n0Piq-vng&l?|D1i$ FOt":nZK8aeV%)!EY0\߼E^]eJGItЃCP N}Q߮l~:#&⃁ų^;J{=f@?{\0o^݋[<(΍ٻ:x=ٱ/2B{t6 o/|i=g5!ƲrN滋&ncY|!$ qk-qƝ~[1!i8|\0`:Fj+;=z׆C"Mّt]=I޶z*Eg:~j.ۗyuPn9k`me;vni%m8k6s͓ھLPד}7;oPgZ rybΠ2klD? _`h.,A Ę؂NrNk@g8"! DkgT^ '*%^4RznΝE*mve!pm㮇e65'ĻXfEF}.sm-+""bh[ԗf!fbL>E?D `]%u%L| QOJIqVX?T/@qHj3m~U3a; ިJ=TIRY*=hzPY)Q*OlaXL7 X}D?G CMl/Tibv) P9Y9L)λ3#͟;AWA%_^Re+*O*+) Č<.<'x"@} \;@ߜU_@(T~n ))-%sBع5~7!޲}s_\޾ytȜ;~2#g!---g3iA ]s1,9׵#5:7D@vW{gοl7\_}NQ8o,%'Y94(@dgJI Fw%Іe̱Lp[SZ#Ԕ:9 μٶvKCj$@^X:'@k힃=>PYIJɈh{rvSH_W!gd  &:=4 ̬[%\z<5|XfGt'HP$wwa0ԍʿ4)#[~2?{zޓ+R]GMq/3#NYa~x>8QD(INǤUj.,& ))s 4M w2.8s]f$OiIb:+\)B,(7VW}hʉ,Ai׉44-jf[ty׹,"ËOW߉FncntK>f~~s߉3&`:j^3>KC(B5/M4%fꛗ),*p->oHB!&k-h`vpҹj1B!~;e:"loѦ~QBBI0A!a:B!>t!B|KYY,faaw%&*[z)WT[vN΃(BՏN[эF &ݸ!eefqoh_MgB!RPT(.)6#!3LGB!g B0A!a:B!>t!B|B! B#!3LGB!g B0A!a:B!>t!B|B!_NG*G!P4):ﲏ, HFrrRB?{~guN%{BKwtB@B^dDJ!b1dc *&.d F%3խӜ/MYp2s'61P1tvb5U$GGB^f1%]|Mseڹ\k N,7pLʌo4w"*VhӴbAu1y\Bct UgeH ml8r#Jw;w^ϡ_P x)}ǕgDAkߵj&+]j9țggk];vA.>.D<3C#v2|C#CW5dG`pPh𕽣J o$ԧS L=q=ļM id'FD6JܱJJ"Bَf]͝_W;SB8 tE3~AA]@PCn҆DS3;}Rj@om1 {yv^@ʷ3,BC̬-3+M~B@)򥠪Zwd]:R_aA k(v}-',Br})H.dRRkB柬h?$]Jc7$% y#5C @$IHJIqbBJF/)@ӠT{|9,?TzTS PE<){ 3osPrʬ@(W5*(!Bӑ*m?b縿0c"DE^$ dT~nAT& Af@eePdJtN={( ѹ}\Cw$$wF*9oSyfnB5{Fwq )B!wBHXfD!GGB!g B0A!a:B!>t!B|B! B#!3LGB!g Bt>C[ո rG_;^74g2'QηsF?xͼ!:cL0Bz+@K>8s-1%ܻ!k=sTs c6/ri9 ]G2+߾ vDWq=ZZkʫ#T-ێwn ytr{c5a~|?D%'it MBB->% n]Tٸ EHXXJ@{={t&[zR"3Q}z_#ީ|\ht^ JD+r<=\W cw{ԔB *m`k: J:6ڳpsu%2J>s8'Q.$dSN<;kvu>]̾߮WlkՅ{OޟwjZv$#W!֎z(9#Z[yoHۛȾKߥ7'pw8sol[y٬i=ƞNxYy0Yg^[/=Ҷ};i>=c{RR=.֬Eǭ)^8yv6=;~@2$5ϷdtDoG++; ["8Գ<%tԝ2-6`ZTNܾ,z\2^#%'2}/)SIǼ7Ҥ_DcB#+ϨЇz0X1fvwZqyr_Y4ӥM+?riQ'z؛8zLtd ާSq?^sS?SIxg ␲c'*9.܈ ;4B8d|d%{ED\?8N&t6϶= (hHt s3zFONeR CM݀[4*8F}_~p-'ȩi b:\hvTֵv_ vjҵ9(M7ZL97ķe1Rgɬg/q9V_#NQ1]PӔ;}oyܯ*bO_(qǖ+)}P n8%@|IpZ㊀ӻwjTع5f/ϒEk=wVճ|ۊu2;3İAǽo]SGW)Rn^}QcsGy+p{V_Ϣ.ڻq MwK˖F=6ō㑜J yC6.B5|i"g;u56w~]ilO-XςCG (M"=x3\RRCCGz29Sh93H;w >W|խ& _ t~p"QU͏ UV2-@}C;/v;}K[:N4չo5 l]:<} W (ܬ@J9Y@9j:<6vLj_t;8;r?U<1'xB΢wԋþPs='MH)Y)qNA*k/P:v`]\瓹{wq*/7_XC gW#qCHH_'4`bwU=Q& - Uu嬧J ރ NT|֓*KEDC&Ps:xL~ (Bdk!͝g 6w `].ߙEriU]}E!Kއ=g m /f'#gާW.Wk4B5OG*׎/d A_nhnae7hL8o⍃ӓlFvX M&g`{~2s׸hsFq17.*zwWZl2`0E=m8ȑ-g9ٺ!]o$piEkq}:lXu [%4cѓ=m߳ӏF~ip֓m}u36fllđÏI9'pqCuwj  N׺r7'BÁ{ƊgtN^_++{;{ ]yu)CŒ´t6֮9eirE`h{Ld3NCKobk9 \~g;U݄O?0B5y`b܍;ۢROz"ɽ S|.+gPܽx#CCh7_?x^B@EẔKo  ,]v9@|zjfC!P7|J^Yo֧<&E +8.X:Pɩ&hRE+g!ο7YBƃ5!`:B!>t!B|B! B#!3LGB!g1h9e1el8B!ē8j!&%`X?)**ހ~n[)ii Mӑ1 ٪L^qG3%"~QJEGPRRހ~Vzzouu%%ݚ;-(c"!H]Ia.ҸKKyGGBD4]g~R7)T B0A!kC*#!3\;BφkG8:BOHShVt!B|5!`4N4oпztl0uqq x3iK kyө }\m_;k={gn&&!Ԩ~t fi'r]}Uω>0ͼـ]/Y59!LL=?N%uymNh(M05֎}U L=~CBuFOGGY :~7ǿw5{>5N_`v͋yCA}mzXqV+c*7JFU[;#Nԓ{A$ƶ@eFrzCR}F$_hz9{@X"~G3YS4xOh' Nh{ $ԻjRP%|O'^}Ǯ |W @,tswwswweml1j $tod&.k埮o6ٺ]zZ.6W| xfE'6Ldge>zMȧ c93:( i=t*UN1s[C(neS*202@} αiP}肧vwppt2{\gphw{[g?Cz;7d$ύ ,*30=G->-$ɨDD6NJ:e=z)rmY]Rj:3?OcEEacl^- W8 tӋG`oo By+W/O5ng(]},.ݸzvYGPJ==g3^qaϢmXO"^u^x"ڍS57t3s ;ige.R/\2>-N:rW?F\`4'`> =]t>*;QdMPzyrـnms,86;蒍/;.9#,`P|f)GBnL^5' [x/"q>jr.^rרATEǘJw1d1d{@ؑmshʗmߟ+F؍K{3n ~+tˡ\p5WB|q`;->zFԝ󫟎y;+Aݭ\gP3ˣ !W{ Q$Dݍn\[HaD# ,>&qG1hVLJFx&*" apd.Bbw%Y29#APªF.s?m"0;D*=] gP"]ʜ΍U3N]`{8($D/f('Fd6PoE|14P .NPn6e(-La=טv}Cj-8i{ fmf&@zkHْ@Jl).rb[mg!tMMkf ?<ۚcgײ{ A$Dz6̎u[@tE&O-ٳvfNe1 S *ʚݙVu 3JSotTڥF .!dW0H*Yk!^SyP1ddɼW)kjص$>oڸMR!_Wn+|hvCR\^^:$4;/;O\Q*,$'/l`gg?2if9eV؃@GCk,樝j-_EgUW\aZKʻ䤬 c嗎]M9DfQFݻ5413qP9+E 3,w%N-ٙ9wWxܩ|zi)漲q<)h&~p!6c l)/l#5o/ @JˊZNuHJJed@v?BG,xIiϭ9cBZV rs(P!.)]oYocD^?w2rBWYYMe.I-L4؋lmpx q?Hu$@T6`v~_8kZsj\ MPgȜѾΪtrnKRSRH8Y̷?7.y!"Y`'Gp2+hYI/eS|wrQzm*D9"@W~xlgg-yhB6s< @ʨ~I! @{b6RZ?{,s >&HW{U?6',\?y}!@e&N9 TCBS (J\iRޥK)$7(]<~}"!%+UmrE#&%㖤>>O̮Wm-L&";iķF'3t=a9Z w)~XBel H믿yf ڰ<+6|` 6(~ֳwHjt @ز)6b?)`M< 差o[&޲bJXNjyR_ 6?_ͫH/!{uku;MUT1QǽK-҅Y,(ҹodDI53ճ@*9-Y_}le 2cM[J =Δ(9vSMFW2{IoѾtWgƙvSNR{{R.bl7j8K^׹6.>tc CXD,'EAҨ(uQ8;UO 30z#!PcرCQQ %%uB6IIf;Qå!3LGB!g B0A!a:X*"Zn#Bng׵sݬG, ̇ޜι%2C}MMުc]̻Z}Ia<`I.=և}a~Qs/׾AZ8?.i= _]4E7cn|s>.z~f^V={8ZzM :kg< DT~ҲtŀUGs֋RJHg E?;ևD`‘qwC7[?Ayqvoi:w+ލ=ʏLZIP_.;Ew#$kk9v\HgcokdD6@YU/V_;h 7՜ oo=iջс:',{]N*v-.E$ڊPo~6]CFʺhQ U2]Ty~oܻ}nTsEvZ- }x3"5̜Wv4]:{kѴB!mTqQcv0(Xwew su{orBͯsƥ\R\NLG@ݤ}Z9~B;i?CEL(l1ûgG),*\ZRBHuJxg4xKNM½sų̃x}tUԥ RUK#ŀOETK=MfF*n-6lh5`ӦګԾ4lF>?uժq$OЫQwbno~ĵ_[QfDM?t58(`BCtv"<5 $uݦm:w#ȯPQkpA) DedGTQI /+Nd++Vv e%:7+`hBBZFr?RNYOs2eUQH%Ŋ#TAFfI)V=,,=1ōr] Q1D*/-#ED0]VVFJ|h <~0ڢtnv.\b瀷]Ƭq~VG=~t{GL:Ykt-?wv教W{V " %DCL{=Ƽ(,jԃǣ(&]0B>#;G^l bT,YY% tIFZ YWW+NMi鄼<| vgMN*3--#+C0drS3q aK"HIYQQQ1Q1ѷǝWHMV%gr#hj`n%ce?$֬bFCHHәu J:l8} |v=i!uܣ8Nzq#~@= մju=f)Urc t/^rC~BU~Q*?koSrKY쒴 d*YJv1:kǞ90 {UmyZ}{ @ IDAT' tǐ]{v̀*y:ۤ΋L*di멉҄Jz^̢WO\OkQ_<7%)Re9l`\V%_{]$֎r= j -Qov{S!UیFC_ ^\XsbѧbLvv̲"As>^9銼SGU38 U9Ӥ.B:jƍk6 Uږ#v.wV$E5CKZĢƂF[. xY!c庑عfI_˴RqLs ,ݶnA߭Ŕ ZR6]$&^2uo:TXt厲3.l#wansg#ƀWmc$)ֲR%-v(Q|\~A~*xu~ݲYYLB@DA۴-#PzsubV|e(T'YOueYUwZB(8Si}ʣ%;Z_G)=Bn'!rc !ĸw׋#zsGxזw=QWWUD.ۨ~wo;#e5B쐞Q_ʽ{FÞJ&+5/*SA]1A_'kj.繃ݐɚw6o޼fjm6hsFG:_L]_%d::gjB61qIO<9//{sSm3z}Y9b߿N:B}~C#oy/d=afjbݴLjۯ,ީi $Jzg(4j#t!П͛)Snݺ%o/\ȽЄ˦[1woߺ~r]?ȕ+~ds`J2ݵĀYIqjn3lп'!P=V9yviVZҾ>>ܻr#r2ڹ:5 $]歧~)Tghctuq *#./JRwy87RH5wH')g̘n~Jێ?]8TyMǺ#u̥%j҅M}$Mvų~0ت!Ǜo}|}gL,Zݻ~~mutF >ܸHWOkhRe’uG׻):Nj"L޲@ϩk.SxGݏߺJNY<ˬ</Ɠ :;oǧ3q )usu"zٜp!mb)SF"p3Ǐ!m--GHm*IйcUت  Ycń4!c?{ŵ76]i *'4㍦ݘ77EM)rMbLnx5ӌ-6,"JS4mm3+~UgXTks7[i9u|HIKy$'q}\{܇m'MW}xƢw<<Տ>6zߧovCgC;N1Ue=\ eT|HjD$sǎ)\ozpWڵ{ȑ֥DÇ[~PkWq[CCCz+0:7EpC>25a] צ(G@`#Зa'Q۰v&ÐDzBU&kS(䕕..WU^VY0fe˷JRKR늞8}}Xf RήWHGok'\wX C!G@`# 0n>d2e8rypZm]ѓG8qUVVf Osd a"חENy.k# 0z]* kGoڑFG/C ~TG@`>dMa.#ƍ?m5ɿat^1xm­ۧbޙl3zx=lh['aHz"@_ۓ5lٟ0,4|jclo.-mbFF$ÄD"_>\鄻۾M.C[(C{/9uKfeڵxkf|?k{k7gTdf>AvV܉9 ]Y"1?6F~3 qfM^E(cMfȽ/y$/ QE[QLluQG."sٯ+xk7?.~/ČxzYߵ_DOϻVpf+~K}J1.˩;?uk9^]iD3?bvg_ߍxХtRVȈؘac^g$""q.!F0"|iG=[sC{hFL6nw&21Cr u3_wnw<)aD1kkቈ$C[ qޕ˸Kz#e}Xum<ϳ޳e<1N D<#b7sϷ oٴ_ 5c+gMYk¨bFxy/>>uZCǦnlm6[Z8X\ۃ_5AvLK4"j%6-#Xl$"{G{IVMwXg"b,`..=m8J!)=l878"N[_i3X x&k-]#q=s0:}_xKOyRcx"xYKo?cڦlx׍k>yr FF>[XRUόf’5x{5ziLf޺Ӷ7:*KOm]ڍ;[d] н1lֺv=rHR6 qwwʑQ֥W 5 0L@dͭ(FG@`# 00SzbmX;raH"=* 5Ї) W */\PK{aBCN[W_RRuEOB>>,lpssu\Tjg׫$#з;,e!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0XoQj] Ѝ%z.غ}xv D̆u)\z;$y,^UpIoOXA!G@`# 0 q8C!G@`!(jRUWU)lmKSW`]v8ӶXWMV0`^u#Z 5B!G@`# 0Ll]pL&S~~~Vk]75B4 ?:đ|W7WuԪsYW\k3DԢ"܂4-1!\  q8C!Uk.ķ%uE2eu%luy׸M{q[o]:| I}_f3%5wP+nC } ]\?Ͱɸg4_ /~x.w?tjy XS3D=Mu#1#Dwߏ?hʼ%_*Ք=Se+Y|l]<1Zc]sDCƹZ,QLa%RƏjuMzQSƏBM#+~ŗMS>([""G_j{XIO.~r Wse~̨Gϼ`3U&}y Z1ޜm>['3ܚUev2Y-Rg4eώ֜_)gn.5C=t\+3wd\9s埬%?{@Sn9]Kv~]r~᳙.ua #T[\9G޵>{ K}~{}J/rMr!? z0H$L+]ԼWbO eVx|Whk٨_qJ+W e]CNڱXɼ{k3Ci̳9VyAx+-:r0{!,ߜ&yexcgvf_ܓkGwdX~Nhz" MI~m~S?ֽ{6̑bCIp :z߳-[>{8XDdqoIӲsq2 sކ{_T?k߯+ǗYIr;iaokuɷ,YK%GD]YwܽeQ|^7qOIIh7+;feb:7lݵ׷[r}'~eb۴"='3CDD]NL0fCzt.ćg(XV9让IxmkTJLm`\r!eF}alGJ"{KRqe字ǐYG>8+@R7߽hv\&1m[9,#>=:))P=}c< #4}M<#52$Gfز$v|U[f:25d=q5ށ*X!KfڲĪ:Tsv].`W0*{UfdmI3j&ZW-YF3u0w\|{-_r켖1Jn oYɪ,3 +TmD,Kuq#W/9kM k}1Wkj:L\ws ^[SɆ!UMj˃39::ܱt Qr~åKD\mU ODD܅*Fmt0mϔsrɅuN~m Qz_"0گ.b_ MU5m7ʇMKlMYu&"PWpjO4ybA>*țk[|C|,Sw$_DVeoWSm&2Of2צGG)lw}eO$+Cv*\s㎒VnKMԘhu> 6޴m-j/s6wO ])=@ϻzUGOF(W>sm8y⭗o^8L/Q YvJǨWY?JDgҪy$-!S3ʵrqϿ37Lb5BD+{N(i6<öDD6c^{:^u[LuaGeUO}gѝ֘l\O]ak./-?[>w$sToۗ>?WY_=:A@`ˮұa1֥p2ewQˢ_^~G7`/?|: 7#GS"#Kޘ kGn= 6o.մM.FG@`# 0 q8C!G@`# 0 q8C!G@`# 0uAo15rZ||@RлL&}IeeUUUDqѸy$&DMz0qdG\/ih/&zcq37}w3r gKO߾}G\lܐHOO"*?_zߙ2e zqdKAKj IDATy%n8? SUqܼ_x Y=08F%|7z}ܰa=5XwH[OsKO9_zpyHZvWz(Lĕ|5'~փo9,u9U;?:fv<Ϝ9\uEou7][tou[Wi/nbWo8̵O_b.j1r׆*hStCZ5W|Z58ݰDDE*>t~|OOED߽cigGDEOd_qCFGFČ#'OUICkdھ}3gZWt6s-mmmm ,~W-g0.ݙߐCoXϿ󻺔KFEGK?Wjn̻su9tWkZ-"_N:zU9teᄂ.E:y>!>~_RuEg|KϽq*f?WsoJ\kUyYX߼yh˯n*e`{Ub]nbS<яf"UbR丄7hהq;ך]i_,3cʸ ko%GD̕w?OΚ:zԨĻ|Zkf|pm|j oß=?)s^ޘQ- ^`s^`k6DDX9#g+82e{#~xr܈]u٢#>7kĄĉ[Ϗi\\Kqla8݋"*V?GO-gۮw,qKM\W⹲l,x^4En8kS'&~낉Kc{}?|oMʊ{&Mf"m/o?z .Pe'Np >=VQ|l()1F_=zm cu׫qPZoIM-k4v=2{Knu;M\8#Η{v~5[eۦpLQwߚ%m[;}s%\7//wY_\q1YYoED !]#""2mXSvZ{[I7Z]Y;$s3{W }]UU>?z2s9_lCۻBgĬ_n}^<_skZ= C vu5 ?;'"|»?޲(qeb۴kۜ&yexce:x=:Ʀc}̅ SGw׭EӾWdǼ󾽻ox>QWum´[vUrDԟ8MRŚhÐ+.ڧBUۋCs('11c()>pd{FL6cgt0 -^PH'M;b]> ]ᶖ w/f+했mH#s?! 7&Nj83!c|ўdES[v^M~V=r05ONJ31Qs-^.X}bJ-D`Y堻' t8JfW%_=:2&nԿW':1Dm2wdTmxDM5UyFg7iz!%q̴OKJധ֢]!gEƚsЋ::^l"1˛/ PcPO{Vgsq.H-YM?nVy=^nwT3u0w\|{쭻ES~T=0غ2啮.ݜu/k~w^b"⛳|n˱ZF**1P1e2dWIj.ޢsMUMW\Fv#"xuyYueLb9)sz#'t&Ŧ:>q:>g+< }Vﭧf.hF?j/6hF?ky?Y"(ߙ-YQw-qt7~)֮z-^=LFLaj_ejoX"98;&C?{bܐJt/_~xØOdC'JX!x!ꮰ^Or/Duya: -װv29n|̿S0_;Uurn۰'Yx?s|>^=*)-!aٳ^ ~P{a ) iIyx楟cC9W_ `/"}gh'rr<^j$"SŮ_5;nںqD\Kʮ;-u*h0Ī|Tf?]$}(9/ ۷/""'d.|xS}mo%su>`Q;;;D=,nÒ[xb<=%gO4D|Kt"2vg_]0ěKkz ;{5S%yi?})D N5\uk(=}RI56&CV׫qD3Ӛ"%") eEoEJ/&7O 2_d2eaC:Dճ}lsm#Vmyj>噃n qI^Vg7UO'>sL|IL7'\Fune{ޟ;i1>Y ]t+c-ݱa1֥Vr5Rq üy0‰e4RrsrgΜ M=͵ٺ8}(礳Z޺K|SGKB_|dnOp'?P?>Yd]0 * 髋kU$ Rb gK fFtr4f}Ќu< HU""|Ddn,>_'#(q)rR-%IM^*gPy"Hޡ,ߜowMaNYU:~G3*qT钺V}cؼVx^/ =.ԞZJ23x` E ]ǏnL(/ږźnMw.zl׹I45mT.f"\Lz\FA1#w nY$;n0 p0DvGy|a,.mi!22ND|2$[RRTjќ9[/jU>)2n +6WS8r|Rm/7Ufn 1!^ם9t(5_020B(#j a"]Y"2=B=~747$6$d"2םIJ_Ww:ϸÝDM);JG]7.g^N__r@i(K_[ѹ 8ǰlacrhyXJ ^!bvtGn]'-_|2"Z|/Dpl[ffQ`yl&b<,)<e+2.*e _? m`;avJCQQqGT/7՜I/&2 to՜*kx1XĸZ޴cێͼ7<òƂo,ȫvb K_+`"k`DFBDv':^pű-i]03&U@\dtQ0.:Y#(Ki /" -\]Pܠz3A12mHF*Ao䌺V"ek[gc.px2A7|F9~2xC!#Ie>CotzWnNj#7\[sKvjUJG,uZ|)|2vq$CF9]Ӟ1 {^  1wS-O߾qÆE 0swY-V/AC١/^zpqx\Jwبqw/Z}+9ǥN5jtA֢V\yy$+Wju 7JeN ŷպ!|>|R[sؐXa,<}NYTd$R#"u5-Fکmmx#}y !=oLey۔ɭҙ345v:36R 57p!;xQ-NL*u&xCZڒLg}FJxSk`&2W\hl5D Up[irS3k݂|n~(k5sfةAztoc'VȻX.]4J k}";\~>’/,UAUih47:GI†>;Kk"TmoaQxH-kgRն+}:j=DDdq r&ޭF(5:AH (I?X6:XSyAُQ{^g/<ڨ73X cו䔈|FvMo?gܨ&TzMcX\;!jxF&_""!8ns2:3+SyEv!L]}uU:>,&ں2Go]jy /Rdw|bU=pˎ);v7}pF=|_1}h?>{ggmν5v3ٷŇwj{;r45*2Һ* =H47U漰XmY2St'B#ż`bl$m e3YzN8e^6 q_^"KwcE>s%RSՉM=K??λ Zeă̍x5|?񝮬8t͛rgIj~u4ynOrDkĴ>H"^&"F;]8'"qǏΘe3_^Œ%홯UK&3nwo~OnM[33롵閅Ppzt3l#vX$RzFwo'/1Mp;t Zټ8NjJ1MDDLWGvЋ~i4!""Nz+TGG]s+[L7O8q, 6K~.ΒH^|e"Zl""—/[f D@pXC!鋏l?p "|&IsE=x"CQIgYHěLfKqd1"k6y| lڞ.7 ܂u~ ""0\cJSݎ8%:}8]bc)zW4b}k+D'H&Px (mkbΨk5i+RclˑT&may'bE99EU-&aLZ#Ie%Uo:om6󮦛 XĘAl63">]7`Db~x3 Mgd|ڞ*1kկV7[C6RHC*,3GP],&"u𨡊3+Te\J =PwXLmC,C,DȤbU`|KKo_W?2Fmp5'w^;]`$R=xbgk]$b;\̑BDDFBuqf Ji.lj] ml"%?.Qd0zRו?9XUYy1HrGxw˩3U[pL*T21RqH*iDD$x OsDd75u CV8hcgao:_ H%QySU.o1DI[ߠ&MǏe_ŽH,ڼJ!M-ZWo悜 G9:OM}Ů~'Z͜٨kozFGRlÐW='FG.hBH=0;2֘y^dW2k9]5"T5dX瀁;0†>;Kk"Tmow_?{Xvln-?[C\Es'oK5p?"VP٬]$]UhXуNl?m%jﰘjo?gܨۮ+"9=cϖfV 4FDCp0dufVTv˹벫t,=}XLYp32QIB9i]z0Ypk5޽ELXMĸnb0:C!G@`# 0 q8C!G+w9][_fܖ~.|SGKDU{V}{_p1z6xPKoJE);*vRwW9},ZxhI<~zJoGv-xJb]HU""|;_ym錬VXSAC]e q5'wkiaC1AvVGUdfT6E2{!Ѿ-z-HlgǕ;hD^{A;XY~5qne\\ԢRE;]5kf(Gz9tNtTZI(9&AkΤ$8 O)c]e=~ ġbޠ7i"&Y22מNNp Î5453V-z-]ոMEzw/Yu-#'64CTy29Lok[6&Pd~e;E6s)iېq#lϔjt<"{:~.p#KD|s^Rr?WWh>aCKj+jѳI;D|9e FF e}kz_-gҖFIvVcFN檖D$wP3ODV=Rr"?<۞%"Enݢ ܒ^ $D\ma yEJ/h{)|ޓy^nanOLD|kIsI^ SGcK"&;HEb¥OKLU%pggf ]-W,\|HlW!.q![ \F2DdL98bB;sPj*a@W#XqV =f]MAv)y q<`% +LKIݩ.rKo(T*JsSiNNAewQlK6m !@B $$*M MQ/EbAA*X bE,@CJH!ig/RH$|_3sfL|ٙك8NPW.45<Юg1"$fSڧPpz5#N=>Nuiၝt˫[u 39bBjzUuK=L,t،' EL*=(VPO˴5|4lXPw3dDDT藳?:nˌUf:{Ebqxxgiw[ qv;>@,u}}2#Vz:u@Dc\*DuLdeBPqz~4qenvK':tWέ܆uu񯭭jI>N)w% mQ^o_sHf웷?ѡ"b@"a8+a=ICzطQv_ ۹dV-2ՊyȤTqfNr+tj}>gykOo첖O"D t244eڦhRaʂ ),l9"WW"j~侄of#es#wqer[ϸڑ.lalCNdžc\zẔpU>El<x^ XCCCCCCCcnBZm;{rRʼniq&YYXZ8W< \+vJ=/VkaсYZXhZ{qL qL qL q#R*JҸDG:RI$/@ǢT*SRS(%5k. ¸Q@REj#BڥKJjHGhrOͨb8ԖC 6k:"}K ˪4Nlfpۊ3nRG`3s۹AgO$`W$8 EKUDCª2ϧi=#tHn &iĺS^VI{VUL2Iϑisޓ8,Bzl4ZU\%sG^!RZ(7W?hT~r.K|ӲT5V"Y*ULɾT̄7Jh@E喞>Y)3e!#ƌ}8Suɋ#_rM)1UAʢHKDkeN(3~#=>ݵ<82b@DĀnR ^{{p*Xt9\eC7`0'$4|R`04͖#̥ )S4ƋerkG7;Ȯ[]c1 $ڌ8k'c$%"Y|!Ut>eQaM$5X*E qbL"2?:Ke".HSfLYn\vB<(s=݌KOFf9 rx{ؐ>}Ko6k:Oo%3lt,$1)LEqR(AAa\g #?$010101Jƥ*J&38 p.NE%ewL*uqq2.gGny77R{Y&8&8&8&8&8&8&t N*,q=8ҁR 5`b#`b#`b#`b#`b#`b#`b#`b#`b$YV}"Xy¦+S® ! ;V}&=6ŕrÞlѸݥ;˚`iQ]+w[W6eFmjo@'ZغjE:.!m*V"xPu+ rt1[ג(݂e,_'ҕsA4XM~gs r.t3nqWa}׊O xs 9]&Y/ u{b|pPS:x^V,qf(Hf-ЦƬ^O]GxI-fƜ+I$^kXr%[mQs"[ㄏbK_*I,&~>o{\ֽ׳7G+_+"""Cz̟)GW;ST-v22K ~ޚ7z t4«z;KITaw ,|! Xu'^txhpWoƖB־wz,ݟp6vjd |>ʕgy֬?>{c{ali#|7t[~!=+s7S]*­s@{}C] %eQЫxSDDq<0358@G猑zOWb]\ֆ9ӿssǜ[ms?.{)H~Ytp⑊G}{J:Ob\ڥ{]{ {bf/HJ#""!Y>?45fճE\7X[OK&:?u<#v-n VQX]yzT~jjIH(le_<]zZ )/$Nb]HU3~دEf\(6&{Z/kL.ѩԂ(^9o~UزGG++)xiΡ 1 lp5E]^FDd= ZsqZ֐s1M% 5>X)>~^7rH(9mo 5"o/Gۨ{]]G-_ϹY=Jgw+sIzK':71NIj^ 37+ XU'yg.3u[ihlג\ZMw3c8>2?tdT;n/?TkNʺ*_]rH0VX5JF $B^;\ݘEFD$T{mj8|JZ *jώ !+ ;OzDDe~ZunkgXΒjx {""zrosn#+r~w~pI~_SH=zmCwӟ%'&?zW /o6tݛ!-G=i?;o5A x9*s[\rrӦ,y6̘;_{%k䃬h:!ko{W=2B[7_~+-oͺ՟[ܧY&f''gxwZ~i%vG8Te|%7w 82λfYYڭ]r_~hhJ>bƅ !!!!!!!!!!݅8"_+6.]krqʔeHjʸhr .<w!܉;3wqL qL qL qL qL qL qL qL qL qL qL qL qL qL qL qL qLLl\^\UUe\273lmmm\ADo4n[q$1)ýqR%VVVuo4n[5&juvvVjZZhqZXa1f\`k~;hܶ6 VGGMn -RF2V#`b8;ma4"@tٷ[n aGİYm:D+wh0ƶo߾=::##Ə;~x㌛v-S#X Nw>qxYۢ춭ug3s֬b7OEum-]BކC[c\>GmZ^ +Z˯W4Jlx1##">o-T#:zh͝P)SwDG7jn&6/o͕듖M~y}^7xK B}zQ&LuV퓗=xБٜ#'gnpcQ#F~կ-6U$n้Fwyaَ5yΏʖƤG49oE ["DTj>(P֨L?01=|U|s;[^?awEnOFFf@"۷$0kffM1{F: jP]i {Lő+:mp\{W\67̵;IܯW2bG|뇂ȹ;/_S:?vSf1 {w M^k+_H "_ܺC=iɖv,Y !@~ʜܜ9s?Z@$5jhD`6g e]xJ3Q#oOܘH8iW(sp'^3j~FS_% 7OU'-=~RB9N|sjo s3qiݟ|&QLa"ٱIzR9j mk^0G myues:I9m cS؉Qw2-j14sptp|y˗{{y՚7g϶?ovYXqJc,UEon9AL3$0õZ ??ߋ.FF}; |ק IڵlFFD:UtDZCY18FZwβZ+pcDM)ci*TwP;pc]8'fZ6m QԶ2hE]'x BC0ֻ ,68qsfϾ^q{ﷺ.Rd0T66bFKn|. SH{>~DukεjpͿg̘ /8;:1E|[ A[e?G_۩TY)NGnƍ'^o] po9|\qDu:/qnN\FuM?Ъ߶)Qi "iv;ZKIXX~@$ R._ꭩj 3#闵۽._R浥5VGZXec<;f{4Yy\V^wt[}c=uN%At2?/.Ǫ>g2m]r<5k=QX7kbb{ ST?D{=ݲfM\]&Y$R d=MF \1bDc㨹UV%2s x? ;Ƈ֍Fper2:t(22Ҹvر.]Wl4c;wDܙED>cƍ106]qqǏo\-@6a2% >F]2f_|KK0Kv.5r%"/kp-Œ<:l#7#3Dٽ>C{޽WM~ѧ#|\|}UOLVj?nxs(e֝Oղp^Ո7ڥ8O ܱI):&963`Hvsݨ=k=gJkW$4uȎ-Ic5=w}s5.ج%MZIϟ.Wh6`x:E1]ihz5CD|U}}"5{SN?JJiX5|H3}.Jԛ9u9\<}j{iUTAumZ_ ȾvA:\ųftHUݥ;<>Ty%0Чemf,;O=|&vw-wDmS>9Pp̡׳˹WN*5jS}S.|D7?ܠ\σ/|zy,ٴ~LC]"Im9eu3\eǽHO۰4nƺM\\1$&07h4bRj[6m]l|&6Zz!+|=AF&A/?m]=a̮~:ykݡek|V`)#vp[eNn:*k3fn"ڥ'&mq!kϪns/\y:cCwOn6cfU=:0ӬmBZ^fxWSJ}龄WnZ>>'qDD\twxmܲq^Uyz17νp.ѥlj,um~SnZ^ߡ;Y߼ 1AN1Zyar^S "H!*̮8m EoNMn版xiKjki`-k53Qa]1q/B:(Q}2DD@m`F-:(^ slvv 9]ߚW0ȞUh֪M+v;ןwMwm`Έ j62ztAza54O}r^T[ENrkʿ o("ΝOݡ}%1hn޼j럶O.w=<<ώesJϒ=D|ͰZvk`q*< ZXjr$$LDD箰;f[צe__ʹw4U'FT]G5IևspDK9WҠOaҰ}EcMD6~0rBWSS=d [jp6irC1,!6QT;gXeM X*p^$H\QףallpDu}YV+eq 3D?o[$ܛ"^DH,Ji RX/wOņg2.)!Q?9[> PXvK;fkn{:h3D|ҵm[W[)Roy+89YDc+g2q/?""H?=">+'hpiLt~dkH}^ZfƼ=h]Н^U)̓6CD\RBXΊ 5Z-2w<&""EBsĭ[Qэ&<&pP1֖AGQ ./lM8[ʵmG;7ihS[-.dg:`dvNFf%\bBu[CqO<7mV9Ҟ\WeݹiOW< p/}yî;9_Aa ч>^ˈ1tlV36,dq(פ.u'F۬liC8"5X#Tx׬Ѭ^z3ϒD,EsRDe:]ټ~Ey޷\Fr +oN|۰+ۅ $cܼٯ{shaƒܦ^&Ow3B!u>W_[Rk+{DDjU,{MnQ"D-^ h;=IX5ui%|􅠧=gFrjZXp؇Fy̦V]+c|>l; cD)ik6&7e&]Z:: /qyD^]]SRvЭ+Ɲ'"bM]M\ġJD;9:P:vkxF́ F;wF576C  >wΩftv΂{*_i~~ FZf\GimR»sihX9njUm۽ء[uWڃ&vҞ NݠLݞ#,Y±4pC8""Y7x gt4i*.N&&!1I;ݺunݺʥņ҂vV\rwVVʥ˕S.P-N%;7_&x".ݡdPgd( ?TE񢈹ptD6.HWy(.~88laʥP<'kq8CKY~]R4!!]Km%moKGWrJ,?!EnnE%UlLӧO+ӏ(LLMӕK q8C!G@`# 0 q8C Pt8{%J+hX@@(!@]JGǒ,33+1)aYX\WdGXdDr --TxQDT⸔(xT^©~: q=b#P̩XTv7U @cv50?jon̎d^߹ {S c+ՃO tq\^9Jnj98{oG'D&9o \O>[.]W{zra]uwSպxoYV}7k4ԳOFBx!WwBۛ^KbI'kF{y8ϓkF òJSӖ5ƴѭ7=;yʙJS׍_n1DhhZoa\(IO296C$KQSҥ"ybBQm?{<˟R("H Ryc|ǰ,+D"!/H٥ef-; ^p4"c.Q-=v ]>rqp%muu6UxSV6>R%gjtO7MZQ2x1r1KD|͓tmܹYx!7E'=}@W^7\͞zyb͚NKoȉakqsqnidywzm6]ٮ>V]4Sfݺ _N2#.ҹU3뱔c-&\[΍[t6CQl4de:|tVNnPd[:0ENaku9a w+oطsӦͻx- _<FP #H,6HD<$2?zxdwGǿ{|qGHϓ䟽P(޽yURRݻw R4D`ąkr̻7ޕY6>.8b2|f/f Vj0߀c vU8"SF/pX}}p {=E!$gy3Ak{K0lbO͛dЩݞf?͑"|ԥj:||;shx}ҌVcv =tӱc"->=-?v|cŸy <0i~J Yޒ#!gOl=ctnyn?}h̛k-Wyߙ6TYH~'Q{/{'(/|UeQED$PFՇCB|Z'm[ɗ.GFGb R$&jKM)1R">5>7|f26kPN#w9'pd1/̫7hڠc*RF3{ik_AZC@mxDxrRbvIrRbxDxE[[}ϖW53".&.9lf Q8ݶHԿú{4G"j"rwZLlm ߪED*p^$H\QMIg=2m{,iD]SSXallp}537x2 b֟sp1ύu~ Z:x6zgQ5\.mnNDa2kbf_KJQ*U)Ⓧ**$7,q_VYٔsJ${+Rcyr˫:XP21%I&Kt^g($"O˒:<ɤY<Vn9ēg(&o?Jo`kkakkKDb}ϚW@R5D"14dG|7m:^*jC$@ /)_F\Q1 c?SpOM}Y E˭r%Cf{v7FYDDD\Zj:CD"Qt "⢣>0MrF{dC 6rRJws'NWw#".>&'K""CT c`/*xUܛFr>*d7D_'f`$Ό c%"Ғk{G)F4b445(!3ԣTh^cڬa'8T1) }}[[ǏDTHƪV]ۮ˓ P$4 ?LȜ8.1!IӺ'CɉHbM|g)m:/*ߴY{vKK{vxXR{9vw^ #>M#s2ˆ]Ck} ' /^U黇38"Mӊri6*ޜuM&g*AHxuRbsY/&뙛h3x"VCCMۢrEOg]NC__ή]e}||q4=?Z6ЭSz3> 4Dݧ3<4{ݭ4Fl@4W@<ڥk_@YLkg>9qoH^UY?Y6s}F9_շgXr1bwSy9^MعN"R2dТeA+Wsq,k{Bk4m7rgt*aLX9"tvo'&m>(%o({ܣK2gyHK볺:CqfWWE:F-g{sn$$Ю|>VDed Cc1]K䌁hWV޹|/UZu漊iE;g_D >/P-&!1E7o֯WWFviAeFU+~?|ll l]JCIr)X}= 劂\zA;ޒywnLD\}Cޡ*H. 㡂J })+@ɢptD6.HWyGP5Uv0R`;\y['kXS9fG+>hPT#Pܩzl܌ IDAT(FTOm(X5QVfr,MMU*qRf1)P445ŚYEGX300`Y6qD455briQBN,xtå 0 q8CaY r(4Dj˪824,kjͩ7Χl\QT}&SA"ŖVBCOq@  qDx*  q8CK2ͩI*6h4`bt$4:|ƈI%Fqj?~Kϥ+/Gr0j2 Ux.#R86khWWz \:q?sq$9)GGxOsvl͵I-z9i`{W q蹔r^eS{9խ׸oKD~Ztqm©V a2"R|vL7r5N2CsF4>n4(yQ!.336oh&܆<xuWk7GGwp¥Þ|jűKN{{rO^b/R6l椭04쥰C\{Å ""uWut+RL[W׻:)^8Ÿa~xCSx""ŝ'$.^".‰^kb{-+bSp<C$}y-lՉyeQf^DDɲ&r""8D,'唷 )q$ah۲Wu}nwX0jhh3Ҡ.+e∲oj ߂VV7lީc_eGSs >YЫd0sምfGDSK}f)QO(ъɚ)/=֬rĒLJխz{kQYui͈7y">ArU|3>1d׾'ImrڂOO-T3 >_~k?U| *uquț H/*#;k$"Rӷqh=kZZeGxXOƥk/Hϩ-aU)cˆ;*~a.,/"ʽUdctwk#ޭ͙|O·O8iWDnˉ4NڳU^KdKW l19QZ7seR*LBbrwqfzuK tZpGcRULk|Ur3\ q'Z*kʥߩ$Rb$(õ#༳r!#Å#P!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8Su1d*@pMQ.-bjElΠo)W@1%b(1U} :B; řO(A!G@`# 0L)nr;wSSS+~u:v+(W\I#-meiff\񫋎~^reX\Z%dMjjj "Ddnn^*#<+%v)# GJ@Iw(VJ{x(q$gP˹)׳"9ϔT'cC| 8%_׳[5g#٧[E) @DDܷd"ja<5q}ӧhT>g{>JDĽ{) m:e~᡼%Ż3qiv񸟸b,}?P(d]}YV^|vvO<<찏C}~˹ #wZ8 Vހ!">fmJG0a5 Rt^;%IgjoT"odz }mY?`.F.d6H F]w _ĤCsVT^(_Yp,qao+kZPk|cDvY57,Kj=gaYNJ M-Q/đԈϊK}ӧ.5߻T񓑑\JDVM4/tmALjO ?p~b25~+N85ΑX]S e5X":(g{Bſ~_4|̺Vȗި[F}jMHmZ5UZƖrk6 [^AW;HV}!bE"S;y:ju8OceΙԮl52o㲴5c4(=ś"RX]FZso{CyAe-}c||͏ v$6\yv~>.k&D$}i 9f}\1lp`U 8~pN =.Լ NivjcCV im'yv]]s߱c{Bף:c9rK`OOO~7t]5"qvOTjA|;x]Hȣ+6&_w288ئX"FұTgNowyWNDDDg>AAǗ|R#qG6 _WGBD=Ll!꨿,BDChPk'ORxBߵ%bl~QCL~&$`UMG3Dp^~:`q}3yb5)I'|N=s#.,1S=]Nkif/ͽ]Y͛:߽Ɏ#u˾Jk1f8<ஶ:,W[{zׯ?Xۻs6FT=w-nUWS1gDlo\ƊKWV5j̛HXOϧLqKr4eܹ& XF|.|,ZZIws3t='"ҨX];Fe޼+t%_K+tXJW[KSť'(s.=XյKf-{ݐs/W;[ğ+gmlt" z2dkFDZjd'QgHtú6 br:`]zTiӤAYQ%jf޸<}b9[df f\/fWh̘X+<|YcaWNiulX^_݊ Lc71jڽc9ѭ`Щ{1K֍K|}W)|Ry@S b4˸4mQx66յ.K}:FQoő/4Oz$?Yf?߭y.HX#q]$b8ˉ#yY8cb3ޟ]ei< y"jn7wZ qdjn|Z){*~ؒ\m!"^+<=ъ+==T^]y7){OpN~;s'E\L\raٝBM/x%".>&>ɖn۳gUMK版ՕHs)RcyE\O6+jblBl# l`&|uK/xV${z]#XeY~8=>6ou+) io6Z9ÚEf?N78zt{C&-7ަ3"&#*s$YQ ÊԴ9Xr-å:`_H$Y#&D|gh,E,IslE+#_0韗bVv^!{Y.o}(|'#m1[~zšAkT9f޼D4c1/P/o:ׯɧS"DbiɎ-grGEPbY޵Mvp򘂺1 s] ^vͺUvV=" XnÒHddb# ]suz'9%c'/49nٗUPĽ(wт_4<@D6o౥f(M򷪹_*q44G7aZkM\Kk.~j+~X|&nPʮu';?w`LX9b>Q霆Sm7j[%k5_?䡜T>~&cydu:.NkvrBswޏ44Lm'Y.dޒS/3DrNc'3P3yΪ=}%5r1wm4Ӣf3[#寕}Z?2mIb#wIDf7tݒn7Nݓ]|eTԩMutdG/ջXOˬ^׶/|z+>1ڤyyA1`˾Ӎ7׫\xIﱗ8.\Vr@ tt-u \#]zA; q@h6o:p&R^+?@'k( @DDjH*fh)WSL&E))ß(R%>ԩDb!(q(&J%9}b\I?Ymff\@__@%=TV:}}}[ @8%=HMMU(455(Jz!|@h8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0 q8C!G@`# 0O#::11ʥ𫋍U.~LBbrw8IxxzZrtut*UIJ?:8G@`# 0 q8SS.~r<"""-=]~i::ڕ+U۠8a^D~i11OëT\~4QZz:@ djjSJO#!ؗ IDAT?q8C!G@`#] \R{>},$U.Dz~k^Ô^T' Qː[vM\&kb]_:)/WȰ5cбX3]7:?57(7o_mY|Kig ?:޼BPdGT$Q{EL߼fFܻgb -TEϏݖ9u]S&2j\XDen3a%ҫ䬴ѴšR.8q@GT{k[J;&8f *V]xsPD +k3bW+u.ʦ+ݎ5$Z^4ńC}o NJ%=&kHrDN.Fl z@&'\3^Ji0>mO;9aX3'=V$n{='N::~v=V*;~/*Mt!3f+F<(&]dh2Tpk>ݾ88.j6k4BӋ@Q|+@\ԺmY$?>Ҋbܼk{޴]/8=^8xp5%,kdӸmg%X}ULHFg8bۉ ǽnE=Ll!꨿v""CԆn 97ʾ Cur@&._kc-߯n֧.p I :tg >h4GD'YIu3/)3'U1o/\R = _f? Yj?'[T繏H]csZ J;O̤Fz! @E]Ų+ke,u")AiHH4Ld21IHed<sν3sgro9f_cAh8>BSh5PyR` s.z;NZ~˺0!Mc:!pQr=8HQ"e% HVw::Rm+%&Y?KBnFtyK[wm<ΫKGnL \{ݽ6/)~ڵ)yygR>ñ蠥.Q?pŭW( J0K>rrw`D4=oe^ώ]6[nLKLNILNI~BofZ U9|X].gvSu20v\N 4-(\ d?m_i=eç&;0ڞ^cǡpL$)>~Us=\/t5;>pǩ3E]BXI3b $e,a&\d#k# Р%#ӧ=G 4 DBK2kSI HXށ~}2~"I1 8Jm9n޶ر5g#26f,ï{h0dM@8!G2i?H.P-HCCOא4HxpX5}hصD{gg\l%GVP2Աs~Ãӣ!kW׀9,?c?A$Gi;30ACM GWX^iG>8Xm1eoUA9o^9` A7T4 Z 2@j%6M^([X yR1b.g; ?\Î[B -MV7!'xg+g{LpG_Ts>_Ķï ?zsY~O"}\˞G{L=%˨Bh[ [c;}G#t M[F%w3T{;^|ܟwu|[Ē/ZoOo^"+֭L?(bZi^n[W<3mZ]i.~诛N3 Mtv$ 槷Vyc$,,|zˍDrOVΣ8~\V[m9 [{7g|qߑ .G;Pr^}M=~CesBMj@3\vN:".ZWyDO9_ p| ^8eɂd f阈@]0 BpB3;w;(¹!&#!r1#!r1#!r1#!r1#!r1#!r1#!r1#!r1#!r1#!r1#!r1#!r1#!r1#!r1#!r1#!r1#!r1#!r1stɧuz-l XH% Qb6$^6ΎP(^>99 X,sSkȞVu~—.g@ڪcZ/p!8UT'cNFRr/ti˖Z2)1y Ȏ&}AbBh/`C8)٢]*B)qɺ}t Y6+* g&9#=}MjQA/ŬKmC]l6[n6lpoÆ ;v2L8em Fajk-+&ga䗰zr~jԔ99Wۭm& ^{q.G~z~1.Ɂ1Fr}0ZSa 8غh ӹZPŴ ;o N=%}-fP:"D˘3gq!YY+#<|E_^1rV%\ȉ~ضv95qSG}•ݏy{/HóDT}. 2b|j7|j`1dbg#Yh#q9뇾bGx-V-Y}Ŧ;_z9@Cz^W}L~iNNΪV--Yv%yw 9o@ž]hmjT3`+u'rrʌW;3nGfN/YP(ΥQ*===,_<ā? LWa%9D{\v-s1rᾬ[?{^7En9.^o0prO~څ_+wm9З+V{zP_~fIvβ|mc׮#lml;=Juݮ[q+Ϳjiœտ}v7q@;i C J&mN<2F> ˮF"%I~?OplU_~co~syy`0-?~?q^O>}#kr<'^N:~/1 0QR͓a[/פn{1hŁOk1;v1Ƃ{\*ΚǏrPH ppӮ1Ń (jaf}84Qs(^.?”$7<6S(9O *޸zΜ s1@ȱ%t#7x|vˤJo/H zGcAMOϞp`dH@3]RwK6&Bh[ݽ6/)~ڵ)yyvJ0K>);߲.LH߬j;|s:ͮ>ݼRwoy0Qց<.3=$g&.HGBRzz$Tyⱆ0 Z"C/"mk}~]theo$4w3]0acib?C\K_jf2Ƒ[ҊIVyc|~w;T_|5Ut=W˝wBR(ge+ΡR)Yߦ-7 b(eTw1 Yb׫6KTs>?>VF&mOv8NʌIq'^g,?~_N`죜g{m冷9f ߷.ZuL^˹6 `] Z $D`r'}(qUٯ㈠27Ou?L7_:QbxcFဢ)]ehXnn۾ۼX8~i9-γ7?;z3==QqWPNrB*'-ޏyX^;soo Ӷҗ=~rxmi @0YrwwWyGSƎ<-P`A Z.ngK6N;9nWUwtz'~1p3MQ!R6(*VNvP7c4EQT6sW\!BFl|ᡐ^frWt^<2}dț^S#¹=s7oAr^~"^O[&Y%ɾ&ȹO$zNg6,ʚg BIϿ[kW6X`շ}-ݣׄGɨc8w(=-չtr{ȟ^NQ e+B j6l0 #"}|ɂd t;%Vh2f`vRШ%zoIB ul `-+=^*Pwvǚ:ށ<F]䑮-jy$Ho+kRY=8>9Z%6\^Z1hx2_MtJ,:Vcd4{XߔXagEIUۀXypBZ$]Wj"@lf3?|9+K*[̄#J rlwj|m{JZ TpQ(^k\ԸY ǏR\m(j$1 ZشqяxGF s7dj+.̝KHbZ7uy#Vu} ʌ )82>efL$ D֢QΖ+86}@poV'I84Lz(|ޒ!ڋe l]U˲dтivc`' /KVLWQZ$S%ݐˡ G}:/?(HF3P}x7cIk!jɢ8K8# .7?\ZɨR2׵PAsa75մ_ 0 EÇ p%DpXM uP8tΜP4e#3WII-[l ly0 4Cmk;΋CT^-hpl%!B>5;zA>-fMԆ𰳻JĖaB,&n.jd(`Z[M^IʎX㌧NS9^'vu NHq,q ڦ^SX%]Tቑ .HPtF Cgu}3EI2rXiK='82C9hy0 4c{Z06+72A/卬x|XVj4 ]-rP"O % VJbdlT) &Uj`+eՕ)ftTʷd ;U]wxX }eJˏX )IhFpO7iAv:}8ƙesc"7m'`/[<'==%sن';}-G?M2f'f,o`kd,^S[]7nufrBLշp@N IDAT f򫯞;W_5G!ty27w<28n097`tgv}{]G"\uz<4040mzӺq'yXj+\\F(w K'&&LVl5tC$ PVܦiGzT#859P@p3c UlI}S1S}GX:ilf,)IbFq )Rlmxaݭ֛J߾aV_9!ХӜE~-ILv}_+l=۟~?Iyg&ܻÃJ96\X-\Yٳ=?z{m֍ܾXN >̻>NBKH\<|ǴKGGR9Ox]W)O.5 ¦;%C'߻;o'WK^Nٜ4Tƫ֮[,r,B!գ#v7feKr5>~ֶ|Hd>{f*agS_R+}xvC|7 8zT!BSţ#LO#u]z!殂gY2y[[5+7\ɦk^7߿aq֜[\ջ햍X);߻sʑ(eϿkzz{-"Ko+]\F(B_BqY\{U%-Wx_BO"6zWdBhzp<Bs$lތY!\Bql!.Gf: "!\b B0 B0 sÍ DerIUr컼F$M[;".//sjH\Y: {8@0UIh*'sok[4KaFē7؇ZKORWEiNt Yi{@lrixaĨ:Ug$WDbbعo 1vՖW6u ,;*)5Xf L_U]]SSW\.bbx֬(R%[q01+ކnbeHlBG1u7@~}Zf:oO=K,6v Z)?&9WD]}1(VZ-0~v ʢANxg)x sD~{E%',mE*{fO㛒L]5%MF%R'$sQ.]#}U`.[ ?7b5X\YgwFMG7)DΡ<"•kڇ¢O}^Ib/ j8mG&/@ SN]Fu2}q!ŏugLq67ʝ0S y ^< 7V(Pʏ6à%dDjRfQ`*ϯ2]%%G4H#DrZ>wItOרTIJ(X6;B!2y~ "%t7fpc[z+k ON?f_NvfTqMmy'ERQ4_|QUƬpL"xxz% Zl6gK%,H*!g+smñc5+AP9sBǎL%#!4;k)JvM;Xp(Y2fuj97OHL8dYn{u!5!^R\rvl=-fMԆ0݂",x>-Q8V2h" zq(ۡ;Й[XO}+Nt3ފmQKsmv`X#/bp6L؀mvkbv iXFPn+mI_q!f J"h6bc*!=%nbzʀG1 hlD(I`j6tmݱK>1!&F͠2yZES@!UR[ңQe3(7h ?E&짝r\t'c(ǖg:ˆr}xּ4b~,87v8֠<;jy︾$lT`>5#33i@ b{(1h@}v@f Tp{L45}8!Ōۊ}E]#I+|uvwTݮ0FuuCf桁a c6[9C12MBR Lz>i_kU6U!Җ[ZM9A!4蛋sR=9%u/)X"(bR.ȎOc-/;BX"EHZZboۛM,f"qefіX#!ctȩ8B32bsln`)l[ [?;އUvl޻V/LXJtvZSL ^BePx:\0wq``4--f$(.muCzBxnc5GOtޞz<*+=Xhl./R<Lr&V?}㱃E\v)ޑQ?ܽ<#qZJƧ@&>; |!>'HPfL)pn1U0 Ќ$ ixp6KGGJ Nz?xԈ}!3@LmEOV m]N en<>l3[Os (w"KR;}"FJRFeDjRfQ`*ϯ2]%%G4H#&b7pxc75մ_+_THsa~ -4oY΢ܝ%Yq^ رn (q9?3*8B3?Э,tKZJHTFkF;[A|E,2ď4$!\F9EݬeK) Dc%dKVޮmkii3el =$@^ߦ6k3NS9^ -{K,6#+bAJuImY*-f%"Ģi+?y$ ;R:8(iXFPn+mIL:0 D|um.Y`ҌVڇkk,@QI˸Ёff3Jż SwL_yz/hdImڿ J3F?{t M6:Pa(2xX }eF+đӢ˽%yi~|xW0+eo{)B:r 2GSVql3l{Aя;(0̘}xRTd;P_W8 Np+tW؜>Dp@Wa"ELZxYy*;ħE)ZK f >΋xitOEF;͗g$':r6j@3\vN:"BhY[iVd ',B'N$';^Is,B!._,kB2@++ /8:B!8B!8B!8B!8B!8B!8B!8B!۠!B?aNu2MObr4=MGBѩ"n/犩1M!tY,heDfŹt`A!aA!aA!aA!f"FhK]B!4h4򊊋$!̢hjjkbc6*2R.;7^8:B , r<*2c$GBO̭'r7s9"$d BDƶN"*<))HB98@lz J0`/2Sߘ` ڋ4i1 WtvܩG"OINfXc+B!9H&-Hw&Vc @A <}g KC[eq>~Ĥ>%Hfjվɾ\koc &{eX\>Yp!A!*Dw0,S(e%f‘F%J?3/2T{`o 'ac{9ͪ%C|_{z(BSf)LRn.[ ?7Dܕ_:]KE74DP\eRa@cs;.{qikGBhf!n8 ÑEcx,YuŊ _}~FP}=]VHg@T@s:o+Wԗ4hkJ&,2OaK]{C¹g({*pȑm:ƹ̆q!f|Wt[{~;% V:;iwWG6mFR(ǭZJd{)ipJj7~@Ce۬OLFDRqPkj"P tAd&^ 0} 6d4[ rvpod̟(2IOV~)UiqupNK/1 r܄ZqDž~eGBhf Qř6mx`q`ހyKΉB) y(9|``8LNV~vuCnAA^pJjJ?.tAg,!Sř~v}5"穚8YB3 % ?^ө1Bd=^]cc hM*Zw%(J?=(W*&ZˑS5ݗ;>;{^̹*/qNR9rN- єP,4 nn?UT4E4ͩ"}|F8:B3+1;hl'4'*|y,9Iev鬄)R>PR'mE(@TZ^\5]:Y$QrKFzQCS㰜_؋{y^!ҚREL6,+"<ܻͅ#Ԁfй**JOKu.E!.Mͭ~>Υ&{Qg: udAJrsBh{Wdi5!H$,GBH.:~ps#!Lt\;B!8B!8B!8B .K/k::N\ʊB o/Z78rΥSB!3hr.EA!aA!aA!aA!aA!aA!aA!}Gf' BJOKu.GfH!B 'kB!bGB!bGB!bGB!b'IDATGB!bGB!bGB!bGB!bGB!b3$0M?~2,7?>fL)w!%anoßyy ;/ )m벝9GqA7Vve/|"ҲYέ&f:uKyQd7^"}[n #]uB68t]kfe,&s[,=4Z>Y( ޗ_U ;o~+2-{As)0]q~䣣v>nÆ_>Ӳ?q|Y7|.VpJS! !-K7wn9Ayjo}֗w+wYJ{C,S;l[G//?i74M{)@{'Ē=Jتrs[cuvJ,e6Z=KPwoAͲYm~ԶW*lh뮌R@z Sx)ɝgl.fyzogLD-죂ޭdX7ͽ~@qd!~]';xG>?]mdW.1nsnXX |l 9V,|=^f$uGB } m9DŽH 6>4˃0|ρ!Rb[ ek4 \'Y0}%?|忋@Yo lW/)4q訥 _߻΄\KɮaW\8B{/ß" ^q7x(Crk㳌'{iWUlak;YK<&oɨ 0!ﴥ~o,MPj{_cWڦ>6Ff+~lGB;gtm姩h7ksⴳ!;fu@h||0VPIӔgՃ+'^ @~_ Y>bt!@_结gW[r¤x]0ǩ1qس- ]IIE{{ < F:`46Or33T ͞-Yĉ}pRepڍa mWsŝ^Q2nX!s2>o_7W c!`q6R19r~m7l }%`a&X+?zٝ7bg??n^l) 7a3EG?)VιdB|2ME&MsV&ރ; WYxWt3|\6kΒPBq(8701 UZ;||y|]2|-i#9dEZ.ο[J̳:M;'vxrY'o$&D=+k#sg~ 3wj7^ň6ØzGbB+*=ΣĐUkz=ꢐd^Fyi*bkW^]} rWl-ͥ&mk~yZ@.k!ؠS:GrsK(yGh!Y_o Զ6Shڼ7{ ! nv9+j̜#:^_}M_ߒf#1gS=VVX`utZNIr>UE:('`u,9uv~tz(.zܬsNޘV㯲`B33Fg Sɟ&Ȇ>iЬ~_=􋩋S7K ɿtlLΎ- E<]0t%Steڎ_#6pA v@aVyjWcM-Ӵ3?^zh4bz}LxrՁySpӯxv֎%Gk1};G0D^[dD2=Gbn(Z, rkʮ5WL:9wD!5\رqӦ%I$WL4kU T9<G@=LhpyZ?z˰Q>GW=D ?IK)>U%+.]ǭ[gr515iku֭zZl5BNuXKY3/8oT*]hH,U㊯opNض` ׊5+I۵hm(nڊgh<ǟM)4>!^*nXk׮=kV'+L瓥'&˺[tFR{Y0 zӽٳ7!#*M"IC.ZrXCwW n'-ƇLʮY!!"{p$t9/[PqʆoUdׯ_bYvʤɉII yʯ%GN֬B2e-4TLɵ3| ?$^hϑ#,;^BKį3sacC<!23aEX/wwϱ6{ZTvh~#GzzMYU W.3c?ٝZ'G@HR48dHYRvZ 5 ;7*U>1|qu 0~,4dpp 8;;H33^̮O~*k7o;r45{K?d*Up2pgrqO/ ;k{ )-kgtD{B+~;'vwepS>#RNkvzYԉg!TfM>čE߯;t74;w>QKT $D_`edH$RÕQCcw-Ȑ[S ʤrH v{D°*nӟ0g5x Kk|Y0ޥ JTow,tIsfba9|+x.T\?yAt4vlo\{?ii6k"J/bpkMFdRJ!c'5Fې69OLHJs(@=j?Y[9A[6oԱcEtApIxX˲*O3yU*d U1۩%&qNGR [.f~22ЕNK H7빖"/+L8i>52Ԭ9JؤMQ~aUUocޘR)y+M]?ifB!T.-WT}muQJ clZseX**x';k*Ⱦ2&Zg,rU\-QZo&?1,]vhs3T>ع iǺJynSPcC Kg~ǖ=to6>^{sq.8;92tidĊ=1{|}|QCRbB N:;׈ZWACJJ YB CjCX- nŰz(34>PbX%i`FcX5xp;k֬3fXE!龢=.WɊoE|0ۺޭw \f\xUlGİw[NΑ+>[p)+j^khN+"\Q#WM\ݺV7MY;nr98=GU<'I7|~Y,*$e+0ufcuԥd-Ѽl[U{4ݴrs?Ηkwptv޺5N%vE뤰On\o{O<,l9AsL򷷷gX6###&&c0Ё4l¥[^1:i[;q=4d^DJNj;Aa;NX.䷼P5.dhXHTn/oH.h(G %J)c624,z˒_JYQDvu4L~A!gϺ-ŋwޮ];A)MLJL:~<33ҥKgo//oOUVG0a|}|}}|6вV؍&SMomK @=# 0PO+ܛPq*G^PPnAX{KV1< qPNNSss @ 왁>ZuT++0ΝR@ eŶ~Cw֍&S:#⒒~jӦhkFnc5e!G@`# 0 q8C?dR8>IENDB`kraft-1.1/manual/images/de/catalog_standard_work.png000066400000000000000000001537271450127457600226700ustar00rootroot00000000000000PNG  IHDR}B2 pHYs+ IDATx^u\g%[JNVLTTD$E@qp?|E~}?2;;3_!BC' B5- GB!$` BH0A!a8B!p!BB! B #!0 GB!$` BH0A!a8B!p!BB! B #!0 GB!$` BH0A!a8B!Oy9,_p8YYYŕ_w)*.TWS#+lMMKPO )*(/@?@fVV_|ƿ8NBHEH,JJJ\u|5!<5B8B!+0A!a8B!p!BB! B ؟T&0G.J>i ?n{zxŲŷh.>}}PſʸlO\%:sfNըF{T#P3'pǞ׸YF/^Oa?v5FKǩ D= /BV&3dU3O$;8]wbwߖֈa*2xǵG'27T0<¦e#|{!B5+=wxS1Z `g_Ip)=EJɶVd *+ȞF2D@ѽ;4aj}֝>w칳gϝ1ި0FR7 CMS,!ѷȂ.JOV)@kh%S!33yZ֭Pt ;*2p5¾ܷmslg![}rs 8-,FNSL>~B2n:/>GτdqE8V/tnl;g,\`Gve-{C @V>凩EKGt!肤[I.c*w7gcEg6MȪ|'NTnՙjQ7d 1%ݾ Lxlʢ삶I ݷ7E.Hln6b@%=,iX26t1{r/ A /$r.ޫz$Xz|ȆYr7-p Wʔ7([>  8~:Iz)v>ڭ IuR!ڵqj6 ^=#PvJ_"Nz?ni6d#!*ƪ-fǩTkKϩ{BbX|#k9ܸzz~ ,e`>p댂JZSY*AUX]><Zq=Pej!~7A# DrS )^NǾ=e nroL]dwnrPr^rp"mڃӯ%lԑ3no[~ꦱ.|؇.|Vv,yu{ E҃v3}のRw}8e~$Tڭk/ jo(epBPp ^Woe {|//[K V W+6~zճxENW{:+&7EXi4U>_F`.tQQ :x=ᷫȧs&-8s~V^55ِv8_-!GNxb-c]tZܯdr3n ttwf#3f>c"7Ԧ;E,w!e^ig|6AMSAc[}L4Q$ĘU+t}d\:-.\ -#0ϢIӾvb!B˃l@IjOeY6/ARߪ[VTt2eՎ _EȶVA|-8yQohj""µޮLcdt45UyajL|خB1y9nW h UdƨH~5IJ1M5P &æs ؏o[6@eic0T֪5CTu. 9l*7;1x %v1]Nw9S\I4+{c'd .+U5WIn%%\։P).uW>lI-Ugn|y/{`h߶oLm61+$m8zզ6 5*h|&OltQ{GT权g2LN FhχOX?Yj1!a45vovy%'OnvUh7sVo5RI-g0#Xsx-/_}O]xUF h4}{:e+%k#Cfݫ+Hk_B}e"П/OI>VJ7KCӏK,:u#))6pMM-ԿZjZ߫U˖I!Դ6Y;UyVġz#"!jtG|>i`uv9B5e8"ar!jBI0A!a8B!p!Br8EEU/`k_f*'KE5.q qݶHWG7k {"Boپ}{?WBKJKS#!0 GB!$` BH0A!a8B!p!BB! B #!0 GB!$` BH0A!a8B!p!BB!_Gѫ}OG!PO|Nkb9A 19&g7"BPYW>ͣ%^Sʟ!B2tk}6<qT܇rUtO?h@эW /ɧJݿٸ/"-.q/9̽OyɸUw)vjjS>>2RJeZ9u/>J-ѶvJ>5vV3>se;[3J>5GyY&Tvͻ38b,Y`Gv;1CɛO3J5ƭX1XOvB!$ёjTyf⍰J$~ !KP zjkw/LW0v-~{|ػ7(eQOߎsqAصNj-V2s;jyWT 7_ =)uȖv߸pIw<@.SqvXawhv`)oGl0xZZ"BH&= ͜VKvF$2zueep:CAUL3lY27*'AXlܠ"Վ H&UDI`(E B Eےݪ|nF1JB fϜKCI@v)οg!jN3I{LZzg˂~N$eV$Gj&r$A$!%-ET$P\ iYi"Y_@ŜӇE$UjZyR^Q*bc0@Q @_XwVx̾bU<6a'PIUTnb!I)=C!PӇ#lkVF=uu ƼGD v{$ ETAס @0Ȣd:~[Jj5Ufy3]o}]VVʟY'3!('a9ᚗ]GV uBZ~+np嶭++tT%"NpBrO i"Ώpm #޴6UVs8VSb]Vo53Q.li}Q)eUM@!7M?:y{/V7e'wՙ46vRZN>鄅Vor|NMm#^e;\7e8cjGjdgm!?:?؅w 4{rm6T輼Cutk;z!П/OI F=SvjʾV=>BF>OwRBwB5SMHc5OD!Ps#!0 GB!$` BH0A!a8B!p!BB! B #!0 GB!$`Y8Bޘm:|ŗN}82lI/˟U}%׍tv[yQɧ<7[u蒤s[[Z ۗ_X8[]\&O=aʙO ;5C^f>2e_+1qsZWɟ4i8qXoS}c.lŎfaL z LL:C{@&D4_i.Fz<^_7] yW#TfAӁuj߀⾽2cԙ;;Pqwu~u־]4$*?Lbk?B/2*+Ȟ#5T/5+ b֏Z?Q{'w[ط')پKK&!a#r驙*0CDzLRR):d|}0T۩\;99(Lo"Gй(;(̟!ϪRѫ 5sð^Av3\g bLie.z2 ';%tt{K{1&अakf>;2Ŗ.H:qq9;z݀@ޘcMM\Gmsz}{ۙ[z X^q6SwV· *ֺ Y+ yX @e?s٧4o)v[snJ>5t^P)|jt?g s5t.E҅e}-m-<󼔷vFԮ)vf֎S}N,)8O}L<qөTL5U9xCd<8ZZںMȠx:ƋWyٛ۸MW|'"Hd0 Yk۽sPRuJn)=ɥߪ;@><гĭTƬYՈ.9ksn-댏^៎74t):,QR:K<0f\,,l9 wX?aМ dJ <;}xZlW_4$ $nz;2j$7 {jGR 43j]窙Zu{`imc:|Wl:_19VOՋ Hw O-tr\|!Ɯkan}lͲOumoi{/x'8pd{K ;1/_ge޶+C<#!pqnkiK$[5~~h׳nkB#nا^p0|iŪ(g".hwrͿH|nr7zǯ 0[;nafΓV~q}=a4ű;vzym떝1E;-_OSq7.!L}>ty3Â,[Dߦ*L_a7[#6woP6 Tի"f ujz5ަ=>hhAꜺڙΏ:gꋑwCv͵"#R] 91F,^F^z吨c"^:55R4LOr|V(npy@OPw[iOT$bdFW2ūewGDӻsl}u[ƉޏJՁ1l5|''w8'7bo@zLhVWaB/yKuEޯ \tr$. uZ= ˤJc ʼrU᷏Nd/`㖫wC!؏z!0$:sil]v? IDAT~((23ټB+BFAU4B!k1d4 lw5aTQnWAEm,m,mx'p3ϑ]dHBANdok*'6e~cT@J3ܖW u=Vc7﨔or#NUg:59Բ)JiuzPF1ڈdEFIPB^u6XIla.MCB *fZ,U@uKO͢{wZgR]?O;S7n=`HU 1Q&v.{p+Ru.L!1E-y^''>DYaa޶$%*iBDڂ^ֿQZ"" S9[>2X8^w|T֫0LM-xlܵ81 EeFGw9"cF44@Aֽ3S?tt0d: d";PˬboĈ2NuBDvk靺OWQ WgV˷j.]@j;w|t;*9$mgg[u΍N?VCLb:e+B L^DYY4='<Ai;zUU"lk.KB)PB bS5#RJFɥ@<ّI{o+fƬtϭ$K]BBYq<TnvncOp*: uM 0EUVt$(윲9T_BxU6>\Vᶁ;L8)SeIT!%-U$Iť\V>J?l RJKK*{)*(\fH|k8yů ^:_%x@{( @*ik=SYA?3^zڪXYDC&܎&oa9Tԗn-,G'~xTn0p%bU{"i.@JW%3ewjF MP|׃H((}7 Y*l:6:{L3FwA K7? ?Z*[$$TT$Y(0Zhqqr:YAPZ"<<׊WK{o":M"ֵg'w3`J)*KqI`C^^^}E5ªҲR4+'5Bޜ!+/'}km*ztRJ^V灳Z׼ۢk+rryՊWb]U!+'MQJ]RĻ$ZΥy2dNV 5=>ks՗\%qskO*@;oN,^kgn #_S_H}{M0jaTD釮.REڇ#c3һ*RoPgmHYw anQa1-ɟ!))#`eVDC8<;%-je%[P绠Bd蝊,1r)$qYh@gfW}QtMsO0?%J# ,#7'"%żyo"f>%ܦ X>wWJ┰r yB]$BxŦ&?ǪyU6}{XLv%eυƎIE vz_DPo_ MK84;#K?IaMdK;J)o2 ~ xTe,@Ej؅;uuXO^E.*U>^zԋJa D++ 6RuWBJV])MSy"Zzmd@> x;> 5MR+z=f H={HH^{kl I@=%׃\ṓ)^]q"f`iuVr 쌘7Pݧ+;ŋ2 @Dma@Ș9{el*M!oާWC)43cy+tT%"Npj1k[n89^*R^Qw|Vkd(BI4Hv覹{XLjWu6u!N,*+$&r*2{١F9&s GFdVd:jnL*.kv)DojYJfwN^=dOF)Ŕoc=e5$52KLoPg)yҭTW#g|f~r2-,M?9`͊ٔ0[[eVe vKl^+BX|P[k:U|93ޯ:T \nRW/!e9jTN7DMX7t՚]Z)3`ޘ{+ʵ3wQ.F+c}BW/\ a:Kp_\jW]?Aϟ!Ӓ뷎L˶a// edZ~o   jED]E%],*Z,5:mۧ:yRb6iA9ägײtwwXyю imc.Bo{oJx@b(mVt@yuD#Þ:=gV*EG88N?r-?0OIg޳*(SɠtX ߉bNxYJ;#7m :|&!^@&[3Qj1&ԻYĥTBҷ׼_I"J'PBN BB 0A!a8B!p!BB! B #!rr.:B!T'&8i..ZU8˗JDTM22 ~GTLnǴQQ*/_kߞ?oo{5Wl̗/_jij/@UFfǏ[n-%taA90A!p%z깨XEEhWcTUJʚxGGBDWS(#!lMuƇB?omB?]Sa8BFo@7yb8B}'jt >WS7)#!lMsF2γ#ogЅ7ZLA/@/1OuݵW.ȃ/ܴc\m\W@MkG~S'/1:B_.C53aP}_ :SfV 7_F ѩ+ܬأ]U!$k6fbg-U=!k6^EB Jmۻ/e#;U $__Puֵq fC{Zius9Y NҘwZC1 ~t_CB}:w_'gw%qXYsu~6HCڨOuqpMSpzҥZ\Ymk/!Ԓ?Q .L{y~q ivh't ss>2޿ȔR!N 23#+;P_sʞ6"2sMz*"rdUD  ܊[LPRcGj3 ȆDR\KSҊ:ɐ$lȪ)ɜ؞YO~B=mZQN =sm~7x_@|AP)ibG[3vVp_ PكzYغN#l.vc7~b]xs^go}Wg6P)gY ,E7YM8N՛ѻps0cGEidJkvs2 @}5c˰^p.rfłRc-8CٮO2r;@T^fUi&S\AyOD|XV\_5mtqXGkk{i;2yE6֩4t}2ncM;|ڵW0;L.5@!AWw~a-LwѠ1p_u[v& 8ܜΙ;y'LxoߪԝJ_&Juۡg,_'RvFB? ؍|Fp5Q9/D y;L吕^މOAA7Ӏcnu'~*:zu#D朿qod5jR.}p!8,MdkT}y-F /,~v\ӱԶoPp|kAwBn,{B*t0,JCؤmeNN @sfL4Ӓ9Լ ?FnkLery뚣g,ў]eIBU?ّo6~S@3zvӴӇk4ci3J-]û*)qR T5}[wssɻSlR{i e[+WU"$ASUO)~Mb|KFR]((V]rrd5+@LNN'}UA2R:=X9,l^i >+NS& >~SSC+UU"(.+% (OEBAA` 0_'O:Uq&;r-Iˎ60 d!K4 j:-ϕsjX5N0BBYEG!#+S9BNA x5'#or9 ]RWU#345GEjfzǏj٥[w6JW<C%rsX1]#.p)@ƊU翁<)ʺqOk++[_1 1ZOTm5bqk_ޤd~V־_]$AE4@՜#?!#' y\ TIKx7͊# w`m]p{IK`GrA$||rnWus=6@n)ۻjV-02Ґâ@f!8LZ06'ŋk_QQʾe[5xhRoHȻa1QRLu5gdQI]Y"׍`y|(V6 dd}*:2Ufyg}]F ,F7Q@aS6U.K'_lPSRy UտPURSosT6;;9J>ͦ%xϢ '+XO^qhvǗk=!J,DV%P}HY uhōW5oUG*[?uH Xc/QIdj6S[l7rP=A,ADc*h8_ˡTgOx\HPo<7^ϭ53!f-:0@>)KIٳ\|ߗQJȷnq oy֞뇝,%;ٲgƷ "kص#PR5VϟRe u(keܳ-?q``H*dubq[ #%)e!E-2HVEVFX#rK oa\v3tѫk.2e5;X:J hA1slSլ=pҬ V ):'}xx$d*uv]:+SUGc=#zSiNű =۠Bt?V9-,.֪Uò-;vpTHkX5HT;Ճ,nk*@yw_ǹҥѪ~LrYZLuo[;p,57t`z.9f_/yeotH. IiYą1 WE^ZF9/(fEߋqtkE~MmQhdؓ?ηK`}oL֌{})Wڷ7k=lWtYTTjc몯$1?նm555u@_?'5zDQVPtٝ6(Ԝe-' 'կoC==vѓbMus]ȩD!`M?/hFpaTB5oQ GB0E1A!gk5> GBњ꓾nS GB隺DB&JZIHNN6?LIQlv@! ?+1q̌L̔OOB!~ şR7o^yͿWRRR-Z_; A!L틋_ ""$ III5q߉f B! B #!0 GB!$`6)Zo3.z]8OجWɟ^<:?/ynM?sdÊ4.O޾Stjh:joȇR2N#kjtѫk޳:44i3h4b,˰G7#V< IDAT_}SƷZIu;ܠ? n0v|*XN#N&S}ȑOk wyR+# ~"pEjÊB͊?+mc]4C隆84=dkɟoGY,>I_Y̼qvv\c\*!Xef-Drb^|Im5W$[ 8aPi*VdT;Kor`VZXV;FʨJ}\3eLk{ҎYl>0#sʑ] v=e6dd'A(my(L1VTxtADӸ'C2}xk۹@RאyK*2B}\6=S+bdut5޺ozwǧ7l:}ЂSz)XpvD]t_s׭9|i)E|.%UL ŷ*T?و_%:ظOK7AO45ԕKMff櫷otu\d!mܻا5GK˗ͽx/6͠%5Vg K>|+^ע^g^pY5RdC*NL]u+Qq!Ӷ}e%SO?~Rб[HZѽE̕<2&8w 8u ޙ@' ˩US#!5\l%vk ,X6/2&'}rަ"ghal,Q@i|d\oT0̤2c>uzyy޾N;.5.Y tZ{zw):;pŬsĨ#1W).\u5olN0X}nw{]Qr_5K;xZ_хc:?ŽC +..Xq6S Gde*j#4nȣփ&ۨ18Q1{]IooEM`7xzf::Zdr;-ڱ9k.u;Òzë́O^|*+}~-” cc%|ZJ:cfaV&flEX]QVyAvQgQ\HOIɰx+YJRjɞ /uD"Tp%<y^ҝ㫦 Qc֛~H}=I25wk.*])>VRN<8Lm\Cc!-%'K('[Uv513ι#!CDII5Sc Ld+p;?Կ}ml3RsmhڷoU2b2$-X^FF`^L(ɬq6?,)^FD$%Rϲҵ4N<>GDnfT7g563sϓxclg8pg\~Sք121ִ I8U12o]"RBDo |T*VKm*"#zb>t I{g>F%ԧno dYOnĦؿw.vRL gy/%A^]DoXsnK,t{bl₏gIq5\"Urp1&\ Hxz VىhYΙŽ;8G-DND^@Y;"SejYlto?'7O[0ٴ$9&uZH꩕qz Wߒ%yy{Iz[dVZh㗼wۘ\"YwY8k\\J!eZgA5m+7_yVx6lUyCO*;t+1U6j-Lد6 sfN!""Z~ayl0 ׁK.^1ČBFj~3V{c{a-[.{нysʜjDDUY L^ǪUEk23ɖ|]dT)eް$qzM~ܫDDVVu:zpŤgd*K/rW.-0w ~b+P^ZJ TaaᮮʥaΜ9S~*U(/P%*:V} O rEӖ%,ۧ}-m˖R4r» =xlٲbhKP|q?p;ʥ 6.nÆmڊL$ӝ гLnAMnP/0XPu"zV'Gg7ǯ:(_y٠YD'?z1,[~D#y{EUw#kժjظS*@ciiDw->wΞGrYѰRYa7:$G~+QJnaT墯ۇ=jU-ؑcGi߮y󂃃 `(Uu;t[rf{}iYn`-Z3ߔ|z79[8Nz.'d3L!Rȹ]֘ݍw}N?ѴpzS~NP:s'Onq?[q/TƎٞfLkԵQ^[ DUI@}5Sϟ5Am+D-qBmI6CjVU+'~ #"_s=hx _\r\C3GLYQ}tWT,: KȬˌng}з~0Xgdd8::N?~>s] Ҕ\TS3qufD|~JgyQ`\a- _U+Dɽr%7b ĦI=uOm~9Y* ~zaj?:xޖ 1, WN|R9'AiZ~;F^N:նuk7?yhͪU=F Hr9?ٵ޳" ˿0k;UrVr9!G"|D#BZoܴaMZz1*Y!]<_N;Mul55BZT M4yP''%:p_) ~hQI7e%KSksUq:P eUU'dtVm[|h&~?%BZ4l?#&j.w""?yڕfn3/8<*O:~ũ'g|ByUL_>絾Y{|LL7L:3:km2xҦx6W׽M# ,c$<㉈s*< HR0҅;V_ɷH1y'~YU?WM2AlBɆO [Coo7g{.CF}LGݡu߯J(9:rݒ3I γBٵ]qȜ~m _-S>]+n c4h6|naX6}^Ǩ[8t%<~Gy-N/ Sz7)k;qH>uݩUKcw!"෥Wo*W*meԌ,6L@D7.\qpħ]2Qخ?SD$d|a(owHxy~-yu?O{Qk)J>c˻'tuzS1K:x}[.7oαCکD_0= [:,F5:`_φoܺlrFι`W9Ϸ}vU/::vLgLuV<^V ?8A6/  U?DDDFl(lyaD@rUv޶FXɟ_٨y{ulw׆L՞vvܹ/_O5[U']v<%(7*rug nE $Sҹ8y?7?z0#?HH]ygC8z?ގ']=<=/fЦ?Oy˜5^ulzśJ(uP=Q/߸u|W#ь/>`ىף>_2^ٵ>͚tӪ{Mi. Ԉѭ"-1E meT_8t}ﺺ,״O"ey g7U*ikqC4[zCc. Cwx LnOvũ5GFqFvmT}>'qPtVa尘nV.uEfʟF_Li&R#kYM!n#6P>c]#mmMEeIVfĈ!!-,eaV g"mv14OLGGþk#ɩﴀj欹X鿮z!>5uXRѶɋ2ϛ`U\~]Ԛٿk+} cs{\NHidc^^$> ~P1p?omm8("%?jRŏK=YrlpC꫞Ț.Y㞽6ƒkdfR|8*KEQiuET}Bm޺;W2kr,Qc]؅Ҩ >6%10+-a*UMOIȌz 3\%4e䔂=*ˤ\X 꺟 Z#C[~?[K*RXng kU8_+/izzʂND'%RaVHf~)o=ՇFƕKr->+}mlNnD^i7*nTQa,/##_(RUWJ]ITt$d9O3;%YbL$D$d'&M}}'4W0ߔv5aL5mczR""NWN8G-DND^@ENJJ|s>HbR6"qntɾ=-{uK&"qr҅ӺmI匛}oMZrsxM#7iPjUS_- "j \pAm'f2U^e5 'Zʳ+ߴXTz5>~UtKw;-EZ!S|'/S:GHfc+e7Tp6KVe-63yV-Q""bLO?v&[Y:wђQ䓖ynַzwU5}s[YU4n֭۱q }שS[SbCSOD/_| *USW!tW>MaG@d# 2 qD}3&ɮ^t׫o`. ܜ pB|AxQCUxwD8~uZ∐4;ˉdwj3\!4|kU%W|lu/r_Y_ٵŝ͎jWr[+ jТ^F5#}w){4ױ)cU5װQ?V"*I7e IH=8®QSWeD0WC+v`xY#2F:vZqh|_6-/y-6=*J}?h؎- IDAT~Fx櫛?ү0o p[$|lU\D#DDj-yo߸55*y9VT^+!}|dVΫbp6?컢o\ b̥!Sr3btj* >xd>!8𮥍iz^]6ܪLWzR>:FީABL3H8q$s.]chSF /#R "FZ=1+,#d#LZ?Ft8: -@xzH_w'G{K4>dPo7VgS^.NӠlSaWkgnՔ I?40,M{cuݩUKcw!"෥Wo>;q~v}"'"!+p FyKgF^^_d $d^>S}s<✇ﹼ{RO'[Aٯ7d~VUBVpq7MboKT|qI8yԦٛ-'m39jވ '~+ṣoKo }C/X!aYګ;W٥{L"Nlr{Pݫutzڐړ`N;wb)&T`vK/+cC.sUmTY;JLoGqgg"^)lDO <ϟ?cёXND$.]ೡSՋwoGBOH3hSxd̓'<8˜5^ulQ?E(uP=Q/߸u|W#ь/>`ىף>_05A˝qD~󷾮nήn}W|9}qشqCQbNvN{[=ZbeNqfp CѪݫCrة{tXvoi2wU#0U5x<'ʋjͧ:0Fsٵq4JxR("? dNjnC*#}WO~­a1\]<^̔?Lb-FG3̳CF lr30D1i=||ǺFښVH4jok&HZip&fCzntt^TwZ@cs\,_W [:,WhLxET yBokݾ%[&cиz׮S%"6qk51.ka]}YT6Sy2,JyfiEKy.<ѧ>;A>L_;5BDDIۗ˒/݉_8G-DND^@E/#,K?}EmmztOBFK"Ңw{gt%}}yiN}3cl #vxm^mVg""!߳աsDD$mc\ PևR=uK0W2}rBY%0ڞ㖴v zjϪ³]?b[H?ǞU oIgCҒS &2znSĻqIeǚxy">?%Ys_ehw|C#[ﺿF)(ND H A}5[lP4d#Du W>BFJ6^WC6J{f̼-]vR%eV;`^KEj7a*+|c*khI ٳ5ȩa>cB|*B;"C! #5ksG#_g I8zVG57?/Ft)A~Yqk;U\][=+@k S( +?w$ߓ[6>qjcZzls\V K|™:2У$=5mXPvQ/S{6$iA:=6v}KӼ+BLf{(ndˀ^w;kk Z6T+ѸQ[n)/_NmMMMI8w!Cw]޾Qe[Ɇ7n뮼z?8rsN̕TeJ:ayvZDDİ[ɀQ[7|,/}2!#|9Cj)E+yU.~\k^ G={3<UgI8qԿ(҅;c,heLm 2M6yzzA"j?ڵpSo{'W"""*6UlH>wt۞u9"\ouBV]yVW'vy[ q_QI#;l96ɯ/42}rYadaq7iU M5cO 9pev;2ootKa]vA:oԸۤcT7u)mru^ڐ1&m98|WND$ XO=uork;$, X{9c 0R@E3 eD-ZhkZ뇕C\8>vՊMSU=DrR!.]ೡS?f!"!evⁱ%Nz)MW F:'"?:ASSv=hЙ;h{Tyb͇%n4|{Hر}2g[c-l~ymQd7w Nn씹i;6Ov<%(7*rug nE $Sҹ8y?7?z0#?[1=FȻ#`sWh'$O)<2|fHTTka̚_/:x6|iOL(uP=Q/ߘΗzY!;"8~B8s ȬG8"dye39Lnɹ[ _7p[D|҉z:UWOS^oVnXv<*vJBŨGzNV.M5SR}Y`tZ߱f}G迏?z|Dm#'&) ӃAqr"ٝ;to,=xXjeޣen/:uw]]kۧS st;DJ۹X'>yaqzKn_jeQzXdiŔf;m!5"8FaմҨ6b`!TVH4jok&HZip&fCzntt>r|29UP؜5s^UV8ħK=6>y/'JFЀRSRy2'>Pxz7HM?r%{-/ʮ'fyZR^K.OTZn臝7rY6i3Ծp4crjR>2Os5>\YCVzihqf3 |=_OZ-ԽY?"@^Գ)CDDIQd9x9VyɹG,SYYDDv8r{x͝lEݹ_cW.~s7r%~Py>bW.9[6#yi;u6ܹ2$ɽ>Cԧno dYOnĦV ώmTwkS#-l@|j3T\6~r㓯#+J{۪\\n]CմgqAV;v~߉'Eץahp76K A%g[fH(H{p23&.xĭWE/"\%c%aﺐΪAK<}WPV֒}l]E٩IoغIqs1N."ts!""Vj~{Sq/)6tj̵M}t=xҩ:kqP#û΍}D\ڦg5?'F1ݡyK\3~d:um"^eƘuylsv=`Фk/ ÛݞIfGۤuJ[vV]?k4wo^;g᪟KVgv~F&k2 ƴ,~aeq{Guprx\xa"Zkd`?ӫ(&=#S]|ri)(`O]R4DE*#q{GG@l# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qD8"C!G@d# 2 qDVqDcBKJ_1ʥeQS.(g >JU8fr)|Y*:k*z@  qD8"C!G@d# 2 qD8"qDGG;99Et):ʥIT.{G<ߋQ^_4]un|8!>4|  qD8"C!Ԕ ޝL&U^_4zu}Ǡ}8gQTy|ђS6WOy;8CD9"_!33ӏ-1!| qD8"C!;R'tiw (QZs0yjךzyiݎ;׋N IDATf1;CSfڍ=8(lsӚ^ `~7Q-rToӾJPnG*H?~7)`ڦE -4R=lXB̟Ly;,ZP.,_\A[wj1 òDl\= VZQm+]G*@Ygv;fvk/΍=rSq٬qçoWUO8偫yqimJIkm M8o!#=3nᵯ|+Yn0W[˸c=7~sLj%[D+sk:uo]XhWo9|φf =|;jy|;uOm!+hLǃ6}L1|a:3GgsV  nԦq/3~LJ nvrW"n,=C3:ލmGn$Wsv> tG9#Nr.g4d> uR]_Za/{u\0v축^M|䨳Pd7 /ϯ.k}s^;u׿8~*"to?63fX#kg9>q?V^Q}GWM8j6PmWe\ދƷ5dw}pDx|&!ݶ͡kz[nm?f-ozO[[vr`J≈U{-:p3lL40"_^;1#D%!F?q4,/vqLPTAʣ ZvC5ry#E*!#-,L"" uoS~P::,[q"$fV>tԯh5jIjk#5KKJQ4[O: Bökz,iZ9Kjf$<}i:ilgh;1L}9 sʺZG Ԁejunzj( Kbkxi]Ua;~JxL@Dh ic!>o]LlqI>|K#5k2r\a z7g5lao|i.1yI|kA1506Rd0,_4cYy^"A-SJٙY<geU+ɩY3:G*^'䅼w놛Uqo&V@qMĚ 1qU)ɿLK0+Z͍2ӕW}𶽣yO"ԤLcyi&R^()ZD8PX->zh[H ""VPfk]mlw;niZkGx:TbeזNyM{s !755O uHMN֯a88zWy9'ڕ!dq~OKNȒ+v0EWꙘ''& dNDDIIƦ&o]RjoHE^~#s)ދ\KS^nեJ o?f Xճ֗  +$O 9B?zqR$(zT bu-CN[vFyؼZNuC7yT A+.!UDD$?+$>_m>jھr>jե}q9<ҮWoOxyVAemX0O=@{c:i=66byw?rT}P>.]|XQֲjU"zً کw͕7("đ$$«Bʚ"?fiV%r}?6nĉ%_ ԯOIV%(=4$/| 739ץ# F̹. 0V': S =3]ʉ]?;c)E^a܃+W*/{^??}+4݉?e%"H6b Q dS{ɈhΊ|^)d4涬div]V\/Y2GJZwppi[bRWID٨akTm/L&;v,7>f?U y^9Mc~7oKFyAr;)) in-%m|-Y:jz @]JWڮ؜^EȎA P#񯩶^ E5 C*ះk7{HK (ڪO[imtYmN[uޠ%v!;`P[!*9''%sνT&#G:]{zmzY}!ll9Bٷ@̙΋ GIINuH'^-Ny㭛'j3a~Թ{3o[XsX7;udϯ]܋#%L*S98_?WxY< Z=`89N!o+̉m;. uO|ҴԹ)Z0{mm͝3'ǾR0y)V?,\Z i?œ7,LMM]zs?G}0zK,zlC/ܐض^Pl{WDjk ޽u߸Ywբc?q)WaA!f\n]:L> gFQU+/HvmGciٱϥ7nseGoyym\ 5e^ZDů^۵|%K|i@[w,_h8; ȕ+g j,Vϒi+zk+KM]v?ݹKߤƑ:-MuXMe_Bjii1`g_?ᦢj0Pb}qޝ?K8]b-LϭЏ;oEҔ;yӟmώ k#>&֛`]n~{G׺4m?K/oo{WF9N!tkooᅫ\\mc|r OtVH;xϺڳE}~atzn|? cɗO)~7ç(4}|Ѳ?ly:ukn |b^/dا޴oDO/jm)16[5# #%0VzvyۓDÍv/ X~..+زemtR_k-:)đC#1λ}X'6PyI^ƦS{Ky wΔ:drhSiIbV=2Y(Y/ ?fYz䓪?|Ҽy_\u>l -_%礖bQ:e+3*[a6FIxV51S}eGG0]eXkC|E[Oʌv##NX7}og~x}cL3\T1mJ p;xҋ Z'pc(qҊwrXP^{jSg9_u7T6 jp@ m2 ,gQ]֤ 7eo>߸N=bn Uemz%s7BlwH{g\&L;x{IϿ\tS/|}cǏw>Y(o]N˕o}~3@MS@ gQ y&j5??"y:cG^q_z~ۛG>SݤU_p)ʏmVä4EQW*l8isW>NmkWmvׅ}O&koE {ӺSW<1>Eg򜜩[M\0yނ׬Jx9#fQBh|,k~'늑~[˖Oܠ_{+n{04pwzY*ixbKo$Yw=T Wpݏ›*QȻ~>[NNf ]-zrIm7p=KNl(sBIԼ̝;o6xZqGVO}9 q֥c^w#ExBF5u9BɃ'ddC!B6q!B6q!B6q!B6q!B6q!B6q!B6q!B66yA3> tӦ4VBhHEE )RZV^:ͺ!:&[EEhKBjB>cӁ-.>~`]Oќ @[A!t!a: wjvI^̲(KH .jt2@@mi(/i5Z(XUSb5Y[^^gd(5(:W(\{Goa!|L^BVqԵ:rkPp%*JT8PgwA?MUE.S.H,M=5e:,.I]'Ƒ)-?k`"Ah !}* #+i ͘BvvmiS8{AMrE|֢R}E]vHV$%bzte#(h57_)[$yC]v Ǟh^{$'Vou档ev#_.%".kO_Z 2g!ν\\VQ24US>Fcu֖7t'aOK_BmFLPb3&(c ֬]vXvs>)굮.v)*W ;΁Qߗ-[Wv[G}kϦUJm`Gvbc}}C[&۟&n,˭(`:.JK{#5"4^a]xb9ۏ7,ֿQVu8DIGY2go5AqNy'Dm)jP(I@bLoz.+~A(N,#ST =,& KGmCplIluGX@_ĘtzV04xB&% *J$!a^l05#y ) zԚj`{Y~K+bYj.>iL/?N&e {'N\ Ĥl(ٟesH((:xW?#K5lo6jIv6- L~&tI"Z NN_!9u26b!1 qhǖ&N - GhGѣe֒y!3FF|+7`DS 8xUhWYl fq/8Bg_?yyV{!NqsԜ^|*|Rvs#t"Lt5gf}._^ʴ I%}VAc}ҤщWJs߲䙱iW?.{QDS+w,K u@jjto鱣?Z]D]Mub/'PW50',lD*7py\soO@t>yv"a0ɦG ]J;zyr*u`n~yQ:E IDAT`l+ΫWOpbV)U:3Ĩ>YӤ8'sGu%{`}ZRfqp2%'ߏ]WP߭0NҘF40!nzNkh[|+~*b#.ig{:2߾gXoO>$ٷ|_J7gtޟdj(vqy@g l !thz (;/oʺ>aDٻ F;x (KdRXiaX<[hn% m)81#G]uK4%p樭?ؠ3ps*)s 9p6\,(6A2| Ԙ{t{K97&b%~ҙTuYj<;>!khdy~.>;mNYU۩12ػ̌SLWZ8bwTrbECHbUXrtWB%1#&խ.;G9 q֥9vf6Eh8܁X44{ۿ|jٲK]i!ŎQuidEΗ$& ;_w͕Jy/=п%~z&]>C=ZJ>͚t ߑ>]Y3ٰ"`n i>WUctB]hYt.BJ|PM>ÛWrU~ۿ !B [ώdX8ްI,{u&~ܱ a#ނ/}j+_<8AWgJ;EӍʾϮhuSBMώ0W 1f{qe1lUJz`:}x靻zV,@0t݁w][gW~{Mf]W}qUԽ:=js}x/BIfy/7kW9}S>2ێՏ(eZM=\N;bw7M^)/-(7Q"Ϙ|bEڢ_ԫGo~(q@c~dz{BIf }υz# H nS5IGV7f=>CB_B$.=^D/6tWqB!4 lXs83Woi]Ds5k0 (/::j5C!& ƑB!Í!1#!1#!p,Pf?@4U6kDn iQ[Mhxh2MXT(+LTE"RXwd[r(\ЎS#D% $t󏳟?.hr enp6/h[:e`:Wk^1n"4SG8v.AJGoa!|Lɋ#BB+++L,Ob]Nisl}nl)pLt Uxqxn.e,FXpD-#,T3{I=Uy4nN!/E;?ɕm=|H2"XJ3NQ h[CM7ɋ#4MZ" (jh3glS,R3y)礔iܡY'eF'GQ]PTӦ1[, ( Nh#|:;@QŒ$' -=uE=&g.@ӟiR9#U@]KInYsh!F~[So{Tjh3#&eU-I O\F2yq!ЅӺ?;sd^%0+đ!ar2y᳣\xeG'/Q:e)"UMa-+$uK`ڵV2'@D(T8kQt9U-I Y b9q@^B1]N+f$\FUv@q`;`jR8E3 \A.B\싚|Nֿ됶W8 uzv\?srq5}#N{^Bw_c]lx7\X,eXl#6 jDXd!Dӛˊ_<`A)LJP4C1al@?=vŴCr9EĠ7@0# z=R'**3v ݂yMgZeJlx|@wM!P&U}EE}{(VG:x|Ы) b,텻 l! py͢, aX(g (e1 'b0lPf[s,٨%{401kv7[8BSvGU}sQסC }Ȝ²y9u>" xЦ5j<'>lkPkDN"S,@q<$09uک@6FĴd&ώPLgάce ]Cǻ.@¶j BXzZdpef@"\HĮ&(;TabN-iMIA!t!#ƼISnQ`R Ͼ [-k0:eYu]LP\Te㱴=jen,a c08vR1o?٪;MB<$^Җ>3 fG7F!uy9m㼐 emU1vUU $1F˘ OBcwN'wЗcw-ŤS4 #!ܢ>ϙq <"Z6ύ sdaqe:D8{4ޞg$,/>_L1u+Uj-4ų>ݕ s4Ǭܝ[(Ȥ=%Z3x8iv kٳa dVu(goKU +’۳ 9GϴuѩZ5DBCK r3KkdO#ZFo<8Mn--P1b! h\K<#ccr'[c]vrrs/@!ХptG,5 wxVlLu9B42_I" . BZ6EA!aA!aA!aA!aA!aA!aA!aA!aA!aA!aA!aA!4q,ܝ{Ku h6ƺ| (*QФ?BSȶVQȼa3wd+yA) "jnTc՟2KuGvBĂY~367d!%$Aµ.CgmyymKwxנh_h%]zhOpF; :DZQTRڣRאq#[L#!4hOF2V5KuY">7h|O5X:kjų=9ccb‹c4b%:(CgYfFVCZt;7,nƥTA{2PVt W61̲˒m)hYJ3NQ h[CZL#!4;wO]]}[̕@z - y% }FÖzEΈtcf7LmycguAauB |#C|*S̋ՖBfٕ fIQw΃Q\C^A}w`# DSu C4V)Fs*?SgbIC|ų sDSOgҙ>W.n~| ] (kpy.N8˜L _aϧ@`'&B}Z dRVHO) {D8BSK|`#Nk#'7N# <\"]"₺t%zs`G%/[ O0=MA)9XlSҧөZkF3<錺GEEOf-ıy tyHbh׶Zyʜ֢R}E]vHV$%h-v9 & .>]gmyxLw9aeB\ fܒ1gZDpD]Qf$=%9 R M:O_=ǎ*N !rnP CK}gy7}<Eg>Q=suJOKNiTxo|\,5#kno<|Q fO.3w PFˬwp}I?UJ8{7屉QXtqznJd pPĘ\VHsX;?0 DܼŕV{0!6UTԶq~Ġ30=V P&#FN=nLgU}(Ϭb䆦ZuR Nx)B2ĤӛmS=DΦKly'.bv62O Umݱ'Di]=(kv}d`Ɍo6jIv6- Lw9|~9!GVXXd̀TiuģHož h'd3Qư)bC{.1i;:Ly4-2(ǖ&N_%}Y=|hJvo9E}1l 5t(;TabNfҧcB](XL]NG1Yb4iT£[b{ۓxJ@A ݧ KmcIDZ>~D2}Ksp2uthѵh[ڌ;Y2@d<#uStQzrJ"b.iś҈H"&UN>v6|J9yb5!4p0 %r^ZSm&@:5+]91`{YYةLaWw9`9)"X3SGeJ1Á 0\%xy5yDR) 9^BZ(LT|QjO0рy| e#ΉLnWlus&qEKVĂq(}ejkhӰ6 Y|c.PŞ@4' J(UgX#2N$b({p/sѣ-*!1&<9Me: 0FMZO(L9vts(=Rl'g唷]ȔIf%%%*"ӽOەK͕JQ=M BV0}P\jғ}wXXPD]M!Ean/]u4f -߲([WD?'mzϪe!-}}Ü AIDAT,@Q,-(>yfejtּu r9>-Bi"-Yy4=v0Im*%Ο`o=KϪ0 “fz(0wړYs[? )gߡn%8>enu 0Yq+w#;?+΀ooK̜xkG  U[0ECEG?Gw[B|k)fG!`H]8B;_K|'%\qUX40+v\'SՏv l0?j˟dd>^Mo4<#߆7 GwW4*}{y(}Km}lE܅Bi=?N/N5Eqi+ yÄLko6VJk8@Q> i~JoLvE_5ڝL^~`[{_GΣ/m#׿߫|._Phg~ӺUVVUvy'1k“- :1~j+]ؑ !Фbz:-u (hJ;ke[+%HJNͯi= o򀐰iO}L'o{H^Zŧ;p&i)kJiko W 9e5H=hרpR#iQsizzGd|/`tƯ6=헷emn}Ozz6l2M ߿R~Oou0!=~/&VҶ;Wo=ipf'_zvz%䑟w}ˬf[?(_BkkVgema ',የU˼ YucylzKff%|x#BHwg7CsɂR%7?5}`! {Ilh/Բ-4vCo/?RhZ8 to/:}?ku;&5p^w<5k߶Kp5~u/Jf9htS;vl]udDǓ7ql׍/ϟMw=?|%G1vKFYĺY|Gq2s1t;J `i㯯 7ȡz4^z]*cJ?PB!`ʷ|X avLxn 惮t{՞Ksȟ{,e,(F%Duwp) ]E;6?imF&etmh[]Ğ9|7W{(v<`)[DsMUKW^uY>\Gޜ;YB!V\m9߿}qW8*v~Q-(˒oyy*5Y,s4_CM9F ܁o´s'yݭ1<%ΟLF8EqѻukHs2VCncmPZ%"ah ,BFק%tۺSdA㵤OTI=-+RG) 0~xSw?o~+3XB G\@1E|Pl'Ǖ\ Ĭ?鿟wC^b?|"_>g%+ּ`[_kCPt{S6cpDc:~Rf L;w[8YWNv{i_|ڶ2cSr|”~ݑk>$))ڛx6 D7hO6u`y(z:iX3ξ99ca~sٽ?T|:kZ؞NBSvvG+O ]&1,l ('>_SCT!~r]o},L}gn&n&`+[/XwNJGZ>A&=ힶ(۟c9 hH@ކC;;:[=gZ oCwΑ4Pڹ˒DڢZ?򜜩[sGwYHNutd퍏n2ebɤB]Ș?> ġm>ffD*Y}GwRsMtG?:ǿK|M!q3ϼm\AYw:iښU#1LܱVդӷU>?ÛLɏ#@+R0|$ bV؍[?r [t B+xzu럤ߣ>Kvl-['f?ڴn@N򜜡[%ʟek^p*ͭ^p\N_б%n!wsVk1ʵs>~ݻ6 A3o`Pݪsg]B(;nG'uؘs4I[TB!4Et+C'5/F!Hk,.hB!l B!l B!l B!l B!l B!l B!l B!l B!l B!l B!l<Ha]BK]G{H(.=wTǺ1 SYY٧ZW B&in8B!O8B!aA!aA!aA!aA!aA!aA!aA!aA!aA!aA!aA!aA!aA!aA!aA!aA!aA! BјFc]qĺ?C0 :+EŞrºZ]Shggg]76a5!J__ߔ} Vkcm8gGBB!օq<Y(A!aA!tV 3[ Y9cq!B6{GB--1gGB)8ǩBVXaA!b BB8vAٴiӦ͛kjj/_(SiA!t0LE֥x`w~?6lom[z$<<_gN[wk"3[#!0ᩧfYu]?7MGvݽ'u?{Y@Wh|zMIkY[Bٸihxw_:++k{07mܚm`{;!5ڳUY`A!tVjT[FÓO=xu6{ML˶/6W 3}<+կ\Embs k֯~޺+-Uͷv{\\ܚ^{n*Wp_7knEyhc7Ϩ޼c`ؚ\b…WƪI^Y;+RStٛ.^h/R<0B4{uS[xՓX^e ,(&E玕-^꙯w0rׇ-+_t_:&cq!- '|J(ym, 9x8IBxg>g~w|Gq{jjNN3f8=LrD#M^Z6sJ`Ӛ/ / [j~CR" TU \ kiڐ4]w^W{]ˏhs6lxݺvtG Bׯ6w~><<ϓ}V9yku+v|Rc!;d'#f?0;~>ka+2]&K'^5 f~.~TFr] >-y1-FM>!㋏jDYOL`:ϲ)8fetnFDȜ0"oEUa/kvE#?|]/{Ѓ'߇N䖂TcҤޗz~]uL}sSR&9UvqޏJTT5,gcܘh\{X{dx #kmisڴ2""bnq΋1F&xGB2늭[[l-Ua6{3gþSÈ5y=e&bFr\m]Q"efc]8t!Vo9?zcW:"[.:RYg9Fcqwۣ1}]yŦ;ue+:/}LS|;(ɋ8t鿳>}vsWdK766ڵ+=- :{f>5G sH1aOLKr“[_M cD'/KwZ nnL׬/~z͆-o/ K{D#FĈ1i,ﵹ(\;eœz~flC}}`lNqj0ƪkj\JD))sFSit>$^:pqg6&s`8vF6O; 1lRmH8!8Ҍ½ ,$ gG@*jGXIF+E Z!@a$Q*7;F斖(*gUc8OeIv{ *JJ"+TCͦ&^# UgggWWW`)2j xG pB qB qB qB qB qB qB qB qBV"jaIENDB`kraft-1.1/manual/images/de/company_adress1.png000066400000000000000000002771401450127457600214200ustar00rootroot00000000000000PNG  IHDRT pHYs+ IDATx^wUיvޚ4H$$t*4)EA@,UP&Ez/ J ZR I;3읝;{[n 7<pw9Svv33͓!B!@ /B!B!CBB!BP.B!B|A$ !B!_hz>3fW;!B![K/ro~i B!Be>}z^%*%=Bx]]B!B #G~tl.4EEEya #G60o6c1a=-= V2aA\BCGe477hBi@Ȳ,4M3JhT9/ݡ[·B!BlY0 HRiڶm;@ڶmH`{70۾9m;8N4M0 3JpXٶmB! 7 !B!R8J_7+t:J)mvvZ Hoa3=0P86P*H:p* mۆZ]i;!B!Bܶro8w۶혦ضB!HRT(R-õ͂=n ,+)aD:q 8aZ+q ۡP?-B!bxJ)8%w6VJIjZH$t'I9jm*!mp+DN{oR_W۾ , ÖeZk#dRieY*Hl2|p~yΦ{^ܭH%I"#dp8l`:_='N++VpB!bXh-ğj6C7D$P>z/ dۗm[ٶQ* ~ޫCfz"Pe)0e)qf*2M;?^kĉ9製9mH$hjn Cĩ&cB!b8O+U_h|B+ -IZDd^,dD#abEEb 2 ðm Vmh4jBFϘ1BW(6N8F$1 P7޴:;;Y|! -iK4c m͝TǷb=Lyyo!B!R]UI}Ccne [8鴿jPꨚaa]<FvRJ)q{u92\7HkYv54AAúi4S&Oe6Xn={UUU=,8N7P֞r5e !~ihj"vٞh4&\!6!3WNhF{g ™op(7oP8ws+iY4460*ww,o[:Ӊ\R&*yQ,FUe M=zѻ bh砳C0 АU9c̙ynW+?\6 n ,KiNUqq ۶t:m( 4ݫ)m#TBk@_6lvͶl=nya$]^VWrR[WOyyT6O+/B!8ضCSSPҒcMsK+HdҢr"m4hD"Tci[[юC]}=!$ٙ iom%/ =B1(d2USsD}vSҲhnnPn?剮.ػpޕҺ[ߕLs J&{OZܴo*h? ֆ-1cr{^xMM EEE: -R*aiUTTd$I# C wp7PCfiYr%-;*[ic؎CkK ϥxi)ӦMzgǟ.d,[vo466wyPB1XZkilj0xicbkk%% (4b"Z;74ҙHP\uTUUbk&-ܹr,B͏ pr(/'T˲hjnH$aeycZkEcSUWVTؔA bdImu0̫@gBwWڶEyt"٩_sr7O0A% UWWG2Te=j3WaGU:V@n1iy=d~PA=ώb Ft8գYS/]n&\fTy I|"ޚ݈6lun޾|x¡e455/-HzȅB 9GkڳKE"BEE1+s Bhi HS8NqpF;2reNBi Cr#0eeeBeEp?qd6ػ (.7C`2_y `Cyޖ=mmmjҤIhnnVxS 0<pooN@<Wd*TGG*..VP0M4 L&F45 0Ӷm0R?4kIm0?<8>mhb:)ƈDByA޿dh ^R"vBe+-)NJJ'B뱸,ˢ;NۘfE5CBle !7SQ^NSH8CrC?zǩT:39 nUO2 ʊ̩YvB!8C9]ޠr;?{۸6aPQQN}}=+rϓεn!sz6zȁP*D\8mF8VZkN:dx#{lXǭB PȰmZ:3d=1TqsƏVF:vt%Xb)h#䀡hmjg唔Yny޿B!BE & w~y֣[. _T< QUUEcc# ( sRQM84V s=N+(..0ܴ?׹!ZkM8bjITU)BI4X4ǿeBYՕOaK3A಄B!BlMٞ =3wL=W]r!6.YѺ{zP0w۸u@oxouj@@keY|~L8wT!6ik֭'qzhJ&4qHEg 0uXVe+>W 5E }-{MOa BGk IDATwx+w鈝3o~ߋ^{a@w?<۾^qCi@=< _Cו{Σ3'oXJ (Kk,OyXRȞ]Nʲhj#r}Wq_g?X!FAkBɅɒУOj:vN=xvg{ϱG~JyWx/cfDU%wt-_j@Ue8ï/:];Lގ8ƌފ&zhgcy'9e::;o/߷g{@k)۳rz]/rq۟aG Cp|y߽).lJ~s55iY;{`1\tY1;o&~}՘ Łiz=znК&M܆K=)+ӳq? y{[i'3}(׬; )x~t<ԳB!vq:y{x$Biͯ)owL չ?Q0 \3_u:WxڹfOU7NuLKe`^w\ =[ C,Xf̘^a {ܴL4ԯGWR4ȶpwoZBX1[O4^h-f!;쎿Dža?4iBHFcs\;gg/u//[N2iE5l;aޘ6ot9_x1#Ʌ3?οϛoÞEϽVR樥{q_/=@Ey97\~ s>Z[Ck0C!8"y.ޑLa2*5rvhjN7I?=2~rpډ?.m<&oY tУ}nPs緾ukH$Zp19@hTDvv3[v"Z+&sޤi ӃcOI B/wy9_~55k>oo).5e9+*zX\Y$Ό )o9T4sebΡ,ںmuTUVpON`F:VQ9=:7?4?Ʀ&.q%촓ceE?p&m;2khBaj]wùy߯mG 2d )z>mhhlb19俽=io?hr'{K4-Ѐơ|ͫˆ(ORgSUϝ_~!;8_}F| WK=BYf-p\ry,.[sE埮oζ]2e:dkg}Ss3/[Ư~w*˻<ukݳ*UmmN?'|Iky^==\^@i4 $;8_㹗ݞ3~L}CjTo|޹6dB1r!<|7p遰R)^h>Wp3V*կ4ђ{Q77]5uAr_-׻Muum68w hդ5\~O8 )|[ 7d޸B!>_ y?_]BGG'p-//O?[֚=vݙʊrȶqn{JHt1i674|;k}_&l=5kӕLfW6dΟ~9ϖÛ{G|e+>mƏc+.ʊ himEk+ɚu멭'/OWsyCγ\_p,~tUHZh;.FCvST `w^BMϿ/2s+<@{ǂKE9m9K÷o_t^ߜNq=>xc1tev}mo e3C/ J^#h\| X?9ԓ@0gNr!e?ǟxM?9Kw/| 74тEv=(gzga_n}KxClaϸꆛJfx޳M>8nr"K/W3s&\tIz{xN>o~s~?[y?oq]Bd2Φlμ,XS3!;ݮ]v#3rC7![={˃uPp<ז1cZ`SƄ TmmLTqp$8Sdf:,1.>cs}ƺZ53R"Rl*R(3 S` [;&7-B!Oex[niƍﯘAIIW2) 0,Jiii0nR* +{gyI)8Nֺ+%;;;SaJJJ˲#G:˖-x\9RO>]C[!)w^SP5b$vDxm'Y6{90VӼfh'BAB!BM̎ӧr1GУOWko w0ookU9n{oֹ=rPP!iRR4+66v## wӶb)[5!B!ĦGG@h" >Tj3bn/{]A0ϕ]ha#rIpYO%ʧKQ5IyMB!BlV^˅\;fi;P]]@CC#-\̛}!{7{^}n7ytp<; ;l gSʡF !B!شh`<>;_5`ް^(X6Bya/B!B:Knf^vm!zPxFB!B!A/o}w!B!bp{a;u~iby B!B!okoq u76 B!B!?WPsO"!B!bѺ9nHw/ 3PS.B!b{*sunU|(H(B!B1ho8=)TW|CB!B!6ippoY7nHOB!BaGzHʅB!B +@ AmenyBCEBB!BaXC3Ԃ T]]g.B!bPBPP B!B!Ħ[W_RMz˅B!Bl2uox_{P.B!BlJaӮ{%/RSS8gs/r|fΜ,^0W+jkk5ŋ0.*!B!D?C_y{PmǑ@>gsH 3;0B!oq o,rNB!Baʽ|5jсm۪XRɧpءB!b!w_6g]vfv !B!ߛtP]ܫ?mK !B!](kl $ !B!v[PO^$ !B!vz Mr!B!`zɃ7! Zk8g !B!LjTnCׅB9VbʊMؒͬoL`tH¾6ÀB17Lk B S:ĺ.|} \ig9Ng#[U0~[o_@m_5){H[cwtdpB! 6i[{*ʅ3Kfb+L8.9s:f.iz杂:rr7(Wl=iu3ga$*sRvL+l>{OreRXk r[S@GZonzSSϫW yVaFagsJC /?h, ~0d۟^"Oy\8U1*tףL0fo4%F(Ø1(*RΨc=(bĭ{T #!Dv=of^ |B!R7oX 9]?wZ fT0i)(\JeT#b./œw6Q(sWiq}_@nd+wpuqBӟOp'[(B[͉?19$k<-Wk4w__ͱc2 nz<_\j]]̥UntNCsq= IX#qQ{uEҷx:x T=~(X?q-dA[,z% y=};g>FT]yϾ˵f~ ь*>˜:T6\ŬϣCn+ַ!Bl7q? Bltټ/wEg 7>nl}ϼq;hlV2s t"w.S(c?θ5oux.׽/}7\lg=pV-aIfS~3KmgSO+O[)V._MBѧM=,B,ܬhNG %{p&*⺙wZ;_ڜejfڵuMݙl6+X#/sopXsEfg&L'ii5YtflL\Sv}UE, aɇݥ+4o{W~m\nV_9}rUDSrV;-4D eP As}-֮eM#RW"QxȿB!={σt:!R|9FT &'O"VN+d{;-H/ӏ7Iڦ/*bn1b8j;뗱}k#nnف+53F|*ӷ Zfm'O">#C!m|$E)ȼPHxW Y^NyAQ!P+b1唻SGwڞJ9/+\VFg(wZhDk:t5mEI?inΞ>iRY7:A[ӽ*,Ѳ2b|(_K̾IVp?!B|ξ0P.%)fu̦0"ċ W .Esq~}Fۯ06dmT`r IDAT/OIg/ʈQl;x,-,}}Vv>B!HrB-*,B]nnف;;{72dT젋yʃm,FY9edf׳#G~>ŪRwTnnz?#p}9ҭo3+\a7g?=?P.B!E|~4OO~k%z_}4̪ɏֿ+zfc/պpXbemnB(4]sÀgm,ƘضMi΍"̸mF{BlV.[y/v3Ԇ#.z?]ܯ!v>, ]YTcB!^Jxud73wڙ:o'> I+aCwy,{S!g{v-_ZPtԾ-wOM|EudtG^ӏC];?/t{NZZNXMH;2<ض+/d[, NkB!"{S~hBP ~O8WiŇほybe`$·=!*K4I87G_៭*a̘r ?{E?p{]zO$PH/K/ HґDzwBAJ '\vpT Cvfwvvgo^M$={B_ܸ^H[Y՛"r{9:cS Obm);& C @,77L_p3JKޛy-1>\LA4,ˎp煂s|7/3!}CzT>ϰ< rtIЪ?8Q?{%g$#vOɴm%=xdZOǴ3<ߠq+b_.ΔWx";?:d@fK5'w/ O#Q\(Q gI%r|t dcDԟ~WHQ.*V0r ?hHj_3xHyʞ)cBC-d7dM5pTTWj3&9դ׀\a *q<dÔr,)^= V@Urp,.CEEo+?wۚqvD OQlIC<  z[+ɡ2 XreD7s^xN:~7sS/rp7LM- =W'5=Bu7V:fվ gut"=hNN¸6xw. S)potOsOו^X8szIY +?*s6OO3?{`'yqi<{wi`E,%;̰e;8rk:YiR.%™b96B0{qN'82Yƥ@u:]G981KǽPyw24G;G-=#T{& Uql^4_9{)#:W;hTH$XuӾT$-xI|="OM'3T'^$UΔ˸bS}ɸ]%OZ MuxԢ_x?CAAxN.$DG'`Q7C]f0\&9X.?b6w Zmic$QfӺmqdN5p=9y7&_Ҧ-lm>J|2XӺs-<~O Z!2U.H[_0k!2田ҝ}LYa ڂV $l}R>shC؈Xw f]ic$Y]#͋$Eݲ rkZ\ h_\a!ah^?Ogl,W6ϢAUM~;Wi;,atV:4Fkg?eD;U&Яm΍,q"O)j4Y٫[>6(jGqF5tliWfۜ_0k(5Ha{tZlrS\CZV|A0[>,-V-N )a%-ЊI+0(][|%v s :AA {"Аpl\\R K Y+ _  ,CyX9"UhX;AAUTT%X:-57%FƓ 1*e ѤwDVȶZvY11wKLÜ)k_Mcׂy9vpE&!ۆ3YJ8ϣ](* 5e Wf[~ Z\]CB@UWx\8*@:݄qsHE^$Mh|o?&OgQ^0)pmLrykv ,`#g7{e5.O_zdG" 3jl$Q OOIAtZ8)Ȇ m2TH&N‚^E+-sSYno7}G}\3}Fܼ*(puUAADf(uq:CYo] +Z4eknF` BvI)w%$'7]*g\Ńv6+:EB޸3fg5-n</sʽ :{[+Oyz AQKBybHH${ =SYJ$v/Nò$u]*snIzh{JGHGmX"[a<*z]I#Qܽ|З vx+>Xx>14(mV/E]SAAAz \܄S@ړTh2|^O o*5fjH\i>|=Jh1i7d eWv!~"m,##ШTdC{ㆴ'1(:WDؙnN[ߔbЈ&OsIy˛QN1kW\ Q(ݒ}bwn=0k-6vKҺů8ZP꓆qӼ Rm$1ufcK@i]'o{krU 1+ ?2pƶ((a4tϝM1V>41J0R2|X:>(OgungEzxXDAArIeR``"EEEI>>>RHHj5111(666 ZJe[UUUUu޴y&2ryjըn,`<>na-rj|˟U3nEٶ,k)H.ϠT[F̭a+|Rk'N5^̏sk<'~O Y?̖5}I '/_*.צnwp/Pw0@v&NZr.K֝zMwEoVmB@m<Ã(+ryxnn&hiC.d9,J9S@d=TRQ<oԈetcmi[bx L)f֒G *nc[3 a;ϰϕX/gT5[ި\@KFKstF8b:;UDRvތ 8_Qx8;ߒJXt#3dA>yKar^5e}EorkS:PoJӲ}y"䎾ñǹ~ըP ˑl3nj%guung]R'WV4rdϩ ck,??#cC* [ȵC9u/5{-A3pI4R9̔xSVg݌B֠hKv:νp'֓Iv23i_0Z5%Kstd3fxLc~hLXr;Q}JۇF] Yv/mԺ*zxr2lF\=PIk8Nyj%UԭO3 {^N{=hw5&7F{p-6VXůmsm]O2aI"kOdʩz2o ұ$vCJm\@TNum&AflgԿ%O`-OJ3~!DgC="%z fY3<~QuH \ю^~\=+<N>Tlݓ"Dn@x%oP>1eޥ33wO#&7qERcqSVVܥiU'MOSzGƃ |xI8Ȧ3p=ق5񹴜!(i;k Ŭ<ŷI?FIbgܞGaXvk*/gU7+윖9 םI tv?O|2ʃSwC wçۨD] SVs*(#*tՆ+Ll062E ˞m{` \L߾Zk q/a.,L /f鹃 |̤8*JsYp #I ȫl_iWIl{ 6J86rX27DkƐaFGsh, Yz`('6#@ŜKht/-S|UXDƕDFcaa$A`cE-څKZZS㉟=C2<_O^ ï j҅X5^%^kN'`I>R軚F+l,W'a|5|; h- .ʠLn_IT(3TUEQEɱgFcCٓg0Mk'ș?8w:4'yP$;m_ױcc۴UVB8|Bٽg 3FbH󀨞w4?ލx&-LVWѿb΅mg3iNRޏ2U0}r: ٹJ^dKP,fa~X]&m˾uSh~Q}^ܴ40Y}Xѿ HyV ͨ }6m{akpRkO_ֱwV5dTg:RlٴU eQ3?cfӀ fYVm%٭&>bϞ;_讓8mHIm6xSvG3ƭgl]2/kO?`N&=Q IDAT^EoSɯz̬Y3X߰>wq4"i%\ah6}VF|mlۻsC%}T"bYm{W":Iz߄H[ɂJ_ֳoNV (уXt-ukQun͸O "fNϩu ;neYطkzp^.n),d ; @]&~M+uhGzRzP6g.FkavϪ-ػ~eaSNOxlݳ=}xfv52Vm{f vvp Ҽy9BV~4o_\37Zdl|Ym*/ldtVR%slLR`)b-l˪>ɦ:]{ף5VZbdoXް2{vs8N; @BkE~'۰K^b\"y-_V2hܩPPR5dX笎40yv~ ACMVݜ׊IUn ܺIGFң:5K_BG']iԙlLGW5m;I$V2Øԩ86mX$i$jeɥ-K~ˠJ<~OA&ye䀳#DG' $"T,덍 c) ~*ۓ/-wo)Z=^7Y& r4.㌌JKV 7o>Tn{sB 89?K6p]okBҽ꯳yTLM ٳ ;Uۤ!⥕)IQ W"=h"tzZA sFM5ɣمҥ bFXkw8p!CĢxcZGliܐҦ e {z2Dx>*-aINb{sEƖe,Zs(+Շo 9' iW\IYƔK7?o޼$rss C 9(r"07Rbi柑ed -${@*e_&="U rBw&/mqqI|`YQ^yɉs,QPl|%l!`}HEh} |]2jHw]&+%8Om(<5hg|<^-/9jNt:妡"s 6-e^Cؤ\.5Ȋ1>Ϯm0;^ϒU[cI>!ULaוş0vɛ՝k|3w[/e|Y(%Zu.|W)V.\͡1h4HUfu1#{Ѡ/Kw"ic:e1){npK)G#aPp6G UQ͛0B#vvF܀[ixx8ERxL_trRC)񥕀$hqH&#KI_f՞d)It) y.숌KXb/_"k$E1Qu|FlXƲ?cME>ыSUZoL$;,2f';|)qƫٰR,++0S.YS5% \qz I,I:H IN6:쩠򈣫r"yq:)7mmmRTe ;^bA̿G[2jgK̇H8Ef‰ǶETz%Sn<0G*DGF'g?fVCh\K֚:?6Ϊl*Ш1{u5eIqjd|k"}#3lZ`3WCbs4]2:gu̘݄R79`?8©+$mJg8%y%)65 OJՒ'͑g/pvK!aPØSr>"!#ɠFD|U>KG[%2niYkS>/iW5j?.G3yb%9< sgE6qĀ!cqc2\2PFdY“ydd;YI+&*ݨ;$'Ƿ+.卐_Kv^ܯap1-z@Enw [ZP>mIh(T+#tŹv;Cqo·c!&+pcz^<5R1$@Rs /^x|e舣c䏛[J/͇g~Cr*KE;E*Œݱ휶-O|2"mbrҀ݇&#,JҨ-,\CTw2,2e;< `%]QdeM&y.k_`T ]{veqjh8r7cT0ꍜO;&*7 )z{NJqR+V f֮D)Oe/< (t66,8&eK *1[u=teoXJLchT;%ovq sp!, #Tr] j=v{5|;sY3iINiR!{gCh jM xq毺oS (qa9{OW|] +*6a6܎AYvܕ=vnn8mψs}d?W^<ϤG)^rw6οoҞ,q=(TTTog#Yt&.J:D + + $dvl4nB >1.$MHKKc}oi3ghwoyY;cI-),ɬoz1z|͙O}:GD2E')D?áv%m/`h-Ofނ"Nӝ9=G¯Vaed\ݝ ݅G3}rVo9*nz΄lNS`OshQZs5gA <e_?pi(QH=Ãŋ|"EpwwO'=9(7CzCr*weC?|u]SKV"i ~Iv rDztN(Dִ:NeJFE+X8Ba)䚦*3ju6M^è!D8ySDzֲGJ % 9OcQt.?~m5@f1ySM l:S엫<ďCF|,s{z C=uYۀ/ZVedF i=!xpmB1EʪHz=tTȬәt#L˦JWmܕ;gPVmd%Rj }E͔,9U I O8ߊ@,OPҖ_/ikB4S|iO钳8fҐ8v3hhR8:!_~Iq(6^o3cC2H3> %hT)qKUVH26@!hW3?nI&}vN>ɻae_j=Z^tt=AFrpjY;l΋M2> isd VnS&hdkf.ڐH>oQt0`fm]ȣ.݌ų%:gdfo -'+섦'7mbɎxdGoJD/xNv ZnO}>&?k̲z,\Qv].^&AAAZ}ͻ$0'Ovxxxzz=٦K>AVn   MD$KIx餿%IB#`CľjYiuxxzAy23RV-Le5y^nE'  Orrr6Ӧԓp|zPsXzyիWSM+^8AAA'wӛTFISAAAAy3nwtVwjқ/dɲe \$   C"(Awf+fy24PO/AAA]Çh4ͳҨQyRd   fDPò'aoo$IM٩   fDPTUEQMM6Yې\?AAAExx8/_ 4餿%){?f|I/~DPÒpӡsJN_AA!='ђsy y'KhX ^ȅCU"  www߿o, "(QkmY-Y~v'   G5OhѢȲͳ4d0R^n   {Wo_%?B0\`N8}7|4̱ߗ 8lBZ @(`GDuxUlC/jeP||<}֎ƦKԣl܉~*ȦV4js*<;4QpY |2Q*$9S3V{2]~J7պȏÖ(iVwc o4 ;g{|juah(l r*lOk:@5*ƍe ^zSj-m\x^Aq;Skyv_# u,QN146\|JťP=zˇNO7c,v^#L/aKA-km  K9,;Aor:}qttdoAO,K` ĜaXNN̯3gkGsjf/zEJ 3CY}A->1sB8c}oТĭz/mw=ܤX|E&bϨ?SA!26H=  4׳?GUUEAQhnO:vvv)QQQDEEoe|u ^Eu,xz?&?%sa-dGZ"Ge K&>Nߍs&^҄^ۜ@f(d+3%/6SYSH:oj'Y$L@ X"P,E)]^: :?eKc +GHeU6E55 IDAT$T-%QEB8[Ys)-Ipxx!Ξ0:ʁ ADָQՓ\W9x2Odls mrX,P5lYC^s9l~ZҼS6mx&\1=v {,ݨؾe3eqllYsz^4 ;Ӫ lGM}#UN6CjCȠS3lv&q4H^_9H=  >SL_4􆠛lzʕyi-K4z*7v~ ne8,qЖaC.#v&62h4,0WuUdS[c8/"8[.$T (ՉOZlCr$!kl3yX%TUI (8 q9FESpɓ$5/8ٸ;\Cq ,[)Ph Jq)(ECqjhB)nE ($/HR噇칳wΙ{g1'ޤx՝4}0v7}GߥTj`CGyOm15Zѱm Z']QQ'G(\K-"oeG²2jSիkݺн{MʴopBDOB+ظ+ZvRE:qDٓj&- Yp1 :%oT\SЙS4RDpH>Ѷ!1_4'7s~C!y#'?Ly rG;PpH$x1G5VIh߲'GQ>iS |0s;l {6˼!B I_3d< wcOni+8i&]𛽒o%y =V@:y7ొc ْ)Wi(Ti[7q'~]{,#w J-i}`ʌҝ|G<p+Yz%[P\8s+ʀ}*uɄB%3fx5A4U5hLO#>;&Ы|vn߂&6~ ꃘljϬ{1-\(ד=1]йk3Eg ћS!Vjʈe0CMB!+S4F;wN V"## (.::Z5666ka ='S4ɓ'([,ccciп޽{lݺu>J4,`54 %۳o?39viHt}LBdGRlnBwu[[[TUEӡ( :UUM~(JXRHݹ{ܹr'3TQ[Fc`YYYF!..nvfook^^^ѣS~jS=kXiȑ#i?MW\1)yRJLCϔ|!B!F,=I. D͛^qqqmB!B5KOkzyy_`0}B!B!^$ѳޖv !B!DnX!B!$)B!B!^ #66HU_0ӐB!BL$Iɓ_+KKKӐxDFFH8ӐAh(O0 !xPpTUf$oNGllu>ǏQ4,`QxWhB׮iH!;*$8K.QX1"r5J=<Ɔٳ(5%\B!Bpsw#:&4,Az_#777 ,Htttr=H<ښ9rB!Bd$寑2C!B!dLB!BHR.B!B&2|]!B![%..333TUEUUEA%?N=)t Z'MN}$B!B!*666ڦIēNJMxD=i>H既(GDZ֒B!B!k"=B!uz/[@ !xqTUv3$B!u/^"gn{x ! u^/\Wq"rC!Ŀ.*:Zr!-={6L"$)B!B!^IʅB!BDr!B!5\!B!xM$)B!B!^IʅB!BDr!B!5\!^ o?LKF^뼊;F2!B\iYyʔ+j zSڢˏ4/nzs~ۯdbR>4 -M|l}Z[֕5)YkѸWv`:k2a!QԫDT>7bnaۥL\BV23 !aFkX1wBEU߀#FZ̬6Ŏ5j2"9b:[jPiSQOϤm XvљytjA^9٭xrgqʩ3=Sndƒnjj䍇ia5J*:yH/Ħ/B!:o>%F hN e(Q2-1iOF@ =Ɔ=⾝Wc-8BޗI*{QoMա%M*hќ_-7K _?w@#bS#¯*u[+rk~jSݷ!pO|ٹ)~>5v?MZۍ[Pn-|괦<Ԍ:g~4mԄӎ?ô s(fnj޴[ ߺ:v#W=}37v?)mhШ%#wFW3sn %lCПaZ,;]R')_LbtU3{SbӈnjT~ N՟aZL[~Gsv~-wԿk >ĂAWufgho~SYE3{:aenSTSVJ՛1!V2?UVۧo黌s]tYȹgmufWݓ?Z8G}:TVo.yމ3W4OdHzTZ}}08q8Ť&]Xfewf٭g|B!x<!^:ˇ`('m`+쌊1 B0YZw>MbQBoџL#b$/ ݻCp| KJ 5vd]&IJ6.oz}X>seWƜ9TV7 ؾX=ko@#27.߰q&~_8p0*_wg4 N <پZ7<n^vC3gsٶ+<[6%n9 Y1e;9{/aǎYͷm Ӧ"i]skԇ9maΟy)8\߶(ۗn=C&,vb<р`W].L#2CCB^)iaf1a95[̞ZEg8iϼX WWU5_{&.A5UWc9=2d$G0\dɄ@r?X@OYB֑_`ϝ kJ 9(T  3eԣ٤#ӷ>ժQN;8ػ Ч5a:.?J(2\JSٵ{:])d:gbo4Y5ټD[׫w +ŀSzctúI{N+6 >z/uRn]jȼsQٺѲ-*fBl9Kԣ5VMW ̳Uz1TGU/GX+O`[ C zVosjؼ5;QQE*@ ٻˉ_٧/ }3G ɍŻu,ỊGCT>;VX(u10 '1mwɱJ*%f΃*UBdTl/{,Rr>tҾ fZur;PT sԦe N'6B{0<a~xWwU_p)#T￲ V+-toC?Iā)t*W/s,M?uݽ?rW=O,U;hqj7*B!6a^zu3e4^hY)76 Jƣ{=þo%fl/>_Vf< y1f"3s2L=foKY٧ }ggݠ2k lgN6Kc77ΣWsET"rXGf|ϙ [+UEňA(.,fIqn(G 2iꕟ1`hې>}i %LcIHT{<=]u$Uqct2e%HfP1&ВrggUUEw!UFF0<σcLnSXU88BQX;t ƳoLKV<~vA)~?/bLB~jTs?-Wčj9)#_'p~>pFK##!!^X@c8EG'뚮u@!o&+Yv! &tGEhإ7۔)bY$W Y5I5˘Ξ4BхN: mZWؿ %N7 9p=k7"gS TKYr,F\Ow7QK~놢?6z2ilquMt<՜{hɗ܊'(( T)Stc76aBa;T)&|4@JjB炋;YiF<} MKS˲iNkLۭe(gNLq_xFac[R  }h5s::g7m}au{j T֭Y1,PrFvpNjSGy8iMyQ9`eۖ4yсtX;zJ \Xyg/F1>!3o 8C>w*!=g۰z&>1Qr:Oy( |ȼ<5Nx.Fk'VҺm;ڶĄ1{$cWC|pVH_x%Vx7~~=[β?_<ӎ*mv9+*88;s@3MJҨ-;,8448{#pbMSqiDk*F/).0G\bZa9klݑrRסqc,ۏ5&c&D/K8h$.>!IKՊ\s.c>_nV6ɃǮ~PqR3mew*'MB:*,Ҝ{^‚T2ĦzWz£RKz"\ >މ|vFऱ&>/Ne܊2`fJ]F2KRQC}32h96bGL1fB M4_YK- M;Պ6:`m_ugW祛.?LKYto8pM>"2?g}uBiXغPetE]r$7ZA6GKWA͉u\{ _3nuuX94PйWALm\ycNN=bڅmStBU_jҤ)㿏a>cjΰ)|u@!o>%qJcȑʹs`%22R)PZXX袣UhncccoXjii6n`Z߳?q>5LoKq8݆;GY:bM'`X9uZck(,ڕOk;hv8]#zȦ{̕~r0^GzNNo2+Y` JvCNy Y'4x/B9rŃ +?9}+` nܝAeG5O當hsi1qmKI!B! _}e.H_ӂD/C24uݛW=u,ž NIw&yѴ!]., 6zbcԱLS&cdLJg[rXӧKtRR.,M ^f,?LpR^QFM4nZ)f3&3KqMgxGE^{>o EiE1:seҁL>?VOS/jB!^D.b)W07E1-z-dF5{Ӱo?E݉GU>tXSFWƛݡlo918ny3x)'.q,8wϒP҈|`Ce~[Оxfo;σ8k42w.pb4Jʷ+bg ^;Ч6rblEs~4&/˥zsiA͉9qՄ5>l>shT+jW[E8p;JaI8($ n1rk/Q#3J>MyL gp ʅ.zϞpdpŝ۰o•u3;"uoL}|rycưhMb<އ8T4n8s 36fO==5"FLȷo LFWQa 1D?՚2Q,(ہFEWMfx|7yU- X`nl\aFkP s>ί7`ɟe^|x\ϿZ}uFU7a,mEϪ/MޖB񶑞xuX47f]d 'ɏOĄQo  `v?sv9y83/ϔc}>wwa;0no+I ̆#\kq0/cT*|lj6E;:9wH>=xk?^ԍ9ZmdԼY>T.g+ٽmr^` W}W|=v[dݽU?o!-ox$%^(e˖#o$ĻH|H∳St8kql=Nckm,;v?fx'$,պLK+wت:{V`:̆o`ld!5, ĜI+8}M2e)[}WRk,zg%& lTV)J0Uך*/uk#m9bݽ?rW=O,U;D%y !o>/y4JW*GJixb\g',\#m7-`',GdG%H1tO*nZ$c$,\A*Dy[-%)wvK:h|sYt6/`O߳El%ǹSq/Ȉ_z ^=`s<gۨ@T\jѼoGo_ϞnHbu9mR!Q.HIv'ܒ>_}A?mcF&$jμj2~6Zj 5.מ8e!qx@gp|ZL/fd͌hykD?g9vރ_I{[ {jI~C)D_? ϺXʇl}J=s'ƓpSpvu\{/j<<B!n2|=]gЋMBtEii-B cS܉?1lNuNgd %UCǞq%Fcg~0֕B%rb@?; >RUV4{MӜ7lܴg9~5}j)0 ŷH[LC4n4lϾ/W4!OREӰxSDoc@)zrR*8|;B!E{O#G3}_7vNNCQ4e㪪_K8',7n;WI(p<7zGGGC\\x5^sww׼4ѣGդ<=8BwF䕓\.L\v_35;!B!)$)b .fX9΅||Ǽ'[^!BHv &' ;žM B!H&Iy|ӖmWҤa}ӐB!B$Y,+:7XBu[K!B!ˑ6 >Y=iYhѧY޿~~0zgֲc Q5zyλL#b}/u^#`Vi-2ꀜW.B!IyӴ$ċ:8AR7koٜ Ɯ+q&y Z0&|~cwfHLj׶3z3_d&BN3C7]Mʨf߾ߗ}{]l>JSnӿk <^A#w8ә0~Qb«d)JV/Xx8YpF}´&jY/|QSjTLJ5:M倅B &GLBa}ٳ~;+ Drpt\2} nޱOE<,0TLg~8,R=+7]XWt?6F®X)[(YX]̜ ~ƗU,u*Ҵ +ukML^s/͌27יSojF<`Yo7UH֢KDo8nl=Q7Xw8~W,tQ#y( !B<$YLEo(D5B8ZX`뚗R>o?f9 d(Vҵ7M|n=-B疍S&M3iwPBih( EplvoFa%5"6;fEZmFױ(0CYÿ7o&=[ԡ?-zM#``jە؋~z5#:7ϯ2PHbr+qzբVㅄiQ_;n-Pruj6O'e7w]wׯC t.K-c?Nad6ԭUa Zfgt]BiVu5_Ӵ1/BfF/4ŷjmWۂߋ1-cP&I6Yp4,a עAW7U:\U.1FB-ePzT\u1`B ϫ_ϣ:RzeWoB 2}׈dg`?OP0+ͤF`[NNCjxרOQ븜n.C=ޔn23+ҾUEfL\SLj~[@uM&1pƺ^izv~QZr8q=0B}}vqdAרL0gVCaX.6=aFƟIB8٨\=,ĂB!DzIRLy/C|'Y0jLI~'LJ^VT [7et4pg=R8;=S̎3|zLk!`%'~Kf. 32u{6M4oq̬U0YǨ{gvoeel_!3Jǹl~~-S.PiɶcQ3/h<;Qcc;@]τO|YuH#S+"1~r08Si|(dz)7~kنXЕb o멌w7ՠ_0}}d>cjϾF:Y][ $'ePQL>Ć^c9TJugX_貄=ɾUpoejl/=)Fp1{a@ ɺ _qVF,FG*U)ʵ# Ӏy̝¶sNuaeRyx}֨tY#1Ioe#{cS2T D>ȼ؟rX!IRŴ$ ,p6GX~(^6LNR#V,Sb.(XJE\iŹ Ջ^fȅbwD)GŪ-Z'd^.?o"< W8NNoǾٱ@ŮHK:H܀jȟ9ZЭNn,.ޭw?ήcQhV~?r2(si <ֽX5\0-'. Yrc{5jVp-} c'W"8a-K-}8@oejً6QkJ4Is3##Fj ubX`y ! c&=Z63M};fٌڇi<)Q4SpU \2ά4ݾ gO ᄆGqH3&6#N2v6ئ6KmLή(i$M@Jޱq0+6|q]fUhChMDת&]SN.8gPUMRÿo-N f;k#Xfy^gƫcb&wD㚑`0upTG3@] ʳK,%֘- ͶegP22 #<$(KJ5CՌ耡/qt,vĩ V aڤ}\No3J+%\eqa s{$G]c-&_X!BKǎ`U9C߄9ǮaO L#19c8XFPрve]ɼ=%i:t6 $;FQkZtL!>8lGBaCЉN Pptv²r;VjKVsy^` op;^ZGa踙nMP/ Pȱzhax>)ޏ$bmm={*ή.-B4(~D\5PtL]"mGRH)I\t30+;mmfσr5 ;cY#wմRRncyW-釷ʋXo<~i=#@xh:Iz,1-B%ݭ ΟkF]!x=p%-(;íxRq\æ?,)UUAڹA6hD޹e1/J;@Զ=bDbY7eǼNJT_ 7[X8vAWkY|8 .V켞KT[!ZB/zI78}:x t$5>-+FaD#.ڿ:pZ 3Ԍ*nQjlJ .j6,$\R/3 'S*fo"^/[ 9cVlFisׇS=vsX^<Ɖ(Љk NP*Ҫ-g-HHbg]Hϔ+j/en;CP\=VTȍmK8`^ `UjA]x|j򲁇5>DlZ@ d\)-DRO%#߯}y*fB!Ŀ%-B'B:˺Iu5ETޯ_Eѩ׽;F F+j^̘ %SGN'| Y;Swd=#̰/XXC }Sܽ A1FSƗ.|_ 58T2mn2j\{ZR]WCl{sFNii=>Dpje(dѬ>|x{h{J J0MeʐLMܣLK}Gc*p ƴN&SmJճ-ce6:b4t6]M|P9iW7_o4խG1~B/fS'25$[({x-CJӗO}ض-Q"5 pɂ%}'2?Wc4 hzteTV&/H 76,rsj~x]ŭ_Mg%no>J 7Τ+#ɟѪ%9S.?  83q BKI{gĈӧP%::Z)UZXXbccUMmll̓-+UUmu]uiM'[4Y۸e8ͦ[Lh< {j*yr jTnȽOdDG7h93gۈZisN֡XRfKz7D?~ewo<:Qm-6-L<$1t~v{`neo+Bp4~#Gnfo쁭-UUQU5o(eNWU ++WR3c9( ۷ooDjvh4VVVqqqɚ888ڥKt{{{UF˜!xYQ |OfəDnq?'DﷅRJYnN,ޜ?Yx.iag8r:8#@7.dչT1]U!@'" C-`e#<1):u*Űj\RMEAǝgY9d]ҭ<>MBܓ\! S$4]@ ^ʼnMӟ_iB! .BdO.BGr!B!"HP.B!B ʅB!B|"AB'A B!(%V"$(BY.B!ׅB!B|"AB!BO$(B!B!B!B!D>\!B!'GC'!B!$(;R\E+TĻBeoCƳamRg&NFB!BLgK~ٚB"`˂|$/ ?ŢٷpZ '#wM]Eyͨd !A)));wX,!BP6x{yҶ8IP0+K xstL=lЈ8J4ǯ >YbD..;+0bǔН׏g u6dZt-B̺4Ww1"zo` 3T9Q:wOKw- ʴ}\QS`RУAVq$( խ]ou;_ #PkmI͏3ݣW 0^Ȩ1 9O(Qf{ѣPF'j]Zo5wOKX}-MXd|EO.ijܹ-V77,!BP!9{r^Y"$-՝&=v)c{dp`-S:.srNm~cDx5~g͌ml奝R&Lc}6 zk8u[Mz~v|֙ߣu9]ۦI@.s &6Vr!)NLLi#~k''bcu‘׸(V Xxԥ Z+Q {wf k/<Є-k6,ף#:b[_Bn{_bX* lO3c8[۩'>@l@mJ_}w<|akձ +ZNZHbSw45֖!B!xH\Ӊ # NFDX8;5<ܱF%%3CY}R&sNqN^( 8߻*Fy/JII2P>66XdVP5.<+p'CPUqXtJ_"%(f~oY!B!WEc6oT\][hP\Љ&ֹ*.iѪ(2#>_+ߠTU@\H"#Qr;ᙂSag,tdnrPr,.5+=D[yz|9`߱eq$v ϴ+)ʽ B!BpN7Q/,Q(:ob uH »e%{dθph_G ϓsX^<Ɖ(Љk Ndߊ,aD-0WA ;I(LX+xg63]~8Y(ttF!B! g#igVHjieciZe[3FO jR'pM&25${L;u|R2c۶.=ԒG~3TV3U_ulL[`fB-yZ)%nMy+}7wi7բ|]2,|ٜ $cPB!B<۔}F>}Z URJ)!66V4<99RUVu{]םoظ޴?quL(pn߾[3Eoڼ4 ͛&eسwUT1MΓ'NPi#G_!x ٻ/Wכ}׺ճ TUEUՌ ܗ9]U5RUӗ\JQOό(l߾ i][YY%%k`LJJ2j.]uWWW[9rd6 !B!"$(BGt6~@^I}?ukAKVgMsY_|FSQ=0kcMwQK BS݀babh*yE0͘l!Bx)xb<ѩ?8+9_-1[5 :-gܤe h@ ^|9??uAXje5{ۗ?3iU8޾.$fLsd% چg[&O+ÚqKJ-)9:/o;qm c'.Х0 xI-vL_/hŋ ȡ-x"=? vV?{Ʋ`_Iũپ 8rKt3si"|a+J[gSg#ZPBոR&O[z`lFwjo[R}No'4B~ows!.q3>U1ϿBsA$^mo3vf✷) T毴GVC"*B! A5;W9'N8Tm Zz>h-C=>7aV ތ _#lkYB(xZ{J?n>󿥳 Dϴ|9x%փg LOGTZ[P=Tgw3?Y =0㻏&Sc^P4z{+:(?7fN3mg㢘f[._+,<Y3' fnꊷe(} Ho0TC^= WX6+.Yי ڭ |6xMfCR_'`n71! I˩/^R$O߰"j4YfQ+ɬyYb,9{sNq5`qJfp2nH/P ?xdB!KgE!S+S߼o-}Y7go;NjOCO,p:{\%JpqZvhJnw_hCX*kqv!םH5*}ІShWUbP Vߎ(S-ֈER̵tnOeR;)cw:m;zy)ؼ5ݺRAE*E6U W.ՙFm(ޞ~-`f{I<3u[Ӯ P/łq3m&UTn>CB!xk>ey?Qل7˄%P.o.MЈiE5T6oڟũ9#fkڿ[{v$޷7S?m'\wc4oA-hg![.lv[l.@֕ɡ#ҞmCciаX̫TMob)|Z 7vz48E'"s3ճ-c7'ai_^GLC[mjHnsܛf5o~{s?̇O0}jjL{nqMVIބB!rII{gĈӧP%::Z)UZXXbccUMmll̓-+UUmu]uiM'[4Y۸&gشyi-73Mʰg>Vb'OFudDr_fVb0PUUU36 (r_^tUU`H◾|Uzzf,EamHM8 *1...YӴcRRUtnoo:ȑ#37wr%)Pp{w0m5D_?o`H+9RJ5 v3~H4xH@.B!s/O!x&4Iiӆr!4M1ǩt]}-Jkx4]!BH.' ĂzL3B!w)B!B ʅB!B|"AB!BO$(B!B!B!8;;[CLBQcg7 IDATkk,Hf_By-˙3g9{iB! (;;;ʚ&<\!*y& !B\!B!' !B!Dr!B!"HP.B!ByNB'.%%sk%Bo//TUv' +L s6MBGry+iB! Μ=G9o/,rC!+Bp'&&4Y䑴-..9wo܂Vݺg !B!E111b<?7M.ps5p,!B!xˆEUUTEAQԿMV-ȧB"&{oIP z yF4 x !B!Mڢ*!56\N3CjP9HRބB!BAZʟ.^䇥K9x7nӳ5}}ҹ3/.mB!B@Xrr2cO`hv_ի׸z+Wc|P[G!B!D)L>paEctx=/*~EVZɊq2.]ys%0B!BDƔ?ƎÇqssc9b^cnn#G`pssÌ0Ѵ!)'&Ѽ$y~)MPiB! ʟB.^d(”IQ*jTPe˗sEU( 6ͨ[:Mhk4"Ÿ3b6aQ۾3N%f1;?堍%ɴ,'=4yM.~^6[|,nǪسn}xovɟ8>57DӼX'iB!Dȗ`"t)ѡT1~@if;4M㇥KM(M|9lfy>nvWh~k7%ca%)?z2,3}PC [xeڼu|=yBff->L~_ iF)WMOL^~,cG{; Qa'1́F/sz׵w,B!S:xlo;b媌m(h`nKӤ~i,%X>wsMδ3ƱF3}܌%ٶ ->AQ61y\~ǫjlg_^C{wUu|U۴+[l~ Ux˜6>? h?a:Ob]CS ) \0q /P93BLan&`CSxvݖ y`űQ1wK}/}]_?7g|m{fY7EQԯ;у* s}pL!5&=lGPݪehpt#I!EFFqEAI{i+AU!9(\rUU EyrylO^c'uˍuӷ1X%3E8hK]yGj0:r*nfFI1r0]ZJ:R6ӵ&[cNpHnP=)gq̬RX$y(uXr hWYpv%Kc6>1S-J9,տ]2V$G\J X$ιC&zj1n s}23~5C{2v~Bk6oqV H.rS?$BOքvk ^{мf׉rA%McuLvHxkr,닗+8xEb~dt/^n-B߳-Q'IZd̅?{c~U s4n,yqsqIҷYŇB~Z1"(lEkPmB50^[Uԣ `p(O`ꆧN+D{ivWv]BUq6S%(OMgW30!oٷOR<)zks2$sR)b stXx0ƥd1Ӄ03/Zw9`I:/{:Q:ty'_28a^O]'*9@t=__fm뒼qKWrxa=kfBF[Y>q'.+NUtk7?}xb7^hA*ǨGr`se;T;~yƴٳ$;)eL{Ӧ/yF(vq2Y'b:iGŰT ٞfq$vOa3P(P׸.B|kCZʟBEz.\4;K.NY$GC/Cw;:QCpc2>jꄄX^殮bH璱;Dٹns/ pqA*`36ئݶ4 #WL.Q16ǘfckɉh5I1ŀy_2B Eh""VuͺLa{M 4 M?щDqz7g'{3T]4n;k#Xf}^8|lEXbp'TPqr-G Ş |nçc) NgаJ&Rϗ8t~Ýo&,0ZcJڶZr"Z\-RbOTp*rqp)"4BH<;@Ei:)IƦ-.jv!B<$( kX#Ffgi@BxfNx7aαk}0̘6J+ #.O(b{//3+kk#N[T' ]$"SyZl qzjw N~,^{ v*aɪ{BCr>eYP 9B !L)]*c|]dAOY}`MIz jL?S^ĺD=|#Pp-Oj v }Mx/ԞJIhFhI}0+', ;cY#wtÔ<^B,{K|]:wFUUV\#GLpVZty'! -(;íxRq\æ?,)UUAڹy.ż(h-SOZS:q;ƲO}+=P^Zzj&%ctk啪K=c,_Qhnm@\[g8I78}:x t$5>-+FaD#.22;9{VB؇_\t=[Tj7vX A\'\R/>Ќo[Ү xxҡ{V$,HTKJJέWۖp. J2ՂXe^jBG5HͿ9C͚ Z|`'j*?K"QF@K3=DB)rt]G0Nyt'Iңβn{thZ5iԯ~k*/S{wL-5ʝs:ХpИݽk@^:)է[ІW=P^}w $ŴAf^=f  eF41T߆<~  ̟Zu{+okjSQ z)*8 cjw iMmڼy@͜*9{ ^oЧ~s;5"!T=2f|s~~}0KߓANUKyL bO')תIKR-ZtaTCGtC/W?i@Y >}.ʧv0۔4 K5SMg* Plhྑ§a?6;uW@hŸo:cXUJtKB!xZ)i1B9}DGG+JRBCCU Clliyrr`;߰qiy9~u&?^Ny&9L>paEؾC,.\d\]ש˷s`n-X㸟Vo-7mb@L2ٻU&'Q=I@F$~ĊO}3Y14\V\bg~C; *êB۞i44^!xٻ/Wכ}׺ճ6W)陱P۷"5Mk4x++ĸdMRIIIFWWWҥK{{{#Gޡgߴ" 4sssϛK@EaUi׎VhӮ+VBQ:2<B<_{'gL"ĵ?Npn2:Ee_bJ>,|.(B!G&z{OԱ?,]C2CYtY Z _U+m)C; !q:l)Q#qeيQMӅB!HP xt\.xT}g?c.dQT!Bܑ\!B!S%*: }pjZEI~o9}x8cӗ4Sjխ/;v&8AuMB!@̏5 _N QXX8_e\|1jaaB!B/t-19S %sz>H+ xXA<> M!BQhZ03gzjНvJO]''OZʅB֏Lr!B!OE됧&|$AB!B:t ʅB!B<}Ar!DDmZw)=߾KkܗWr_C?Y<-էAlL1Y!/z)_Jt·|D im#B1 M.?f]O'AϙoVRjayHN_/ t_=Ѿѣ1}7fJ0*R8:M2IW~W=#4yM.~^6Ni'Gj'#WN e&>JQݛS>ڋd.V6r)tA>IhӠ&Ԡv[hmcx|kԠ_:~cƕ= $tJ\uL~şi=?|j֦HF'leK{k?KF 2|а,n~֏kTQ#Xy6. BHt`}+073MB<]u~ɿ1d MZf(#G~1޺A{y*P MWȓ$Z8if`ƫ=&y1, 3bb2ߴC+[-0#dfB:EKjpLi꿡`_7==z~rxTil w3 hNٕ Eq0MKyi+P9 +?&Sf߿.J2wb\h9jߔ/!wf X7PSvЈ=;6 SԴ5wrpfoCI{ͻckeEmHX?Z7O-t+7;Ī:M#{ӷM7Mشx "uHίFԫkeαīlס_}^{k>f-vLP~ }ygXh>lFL]Ifd[mNm>m$fiռ%:ڛδƝߗiVIFl[zkq18% ́;z'\g귩Eu2./v5 *vtwx6o,,]bft|1VtbyEf )ɚN^Т|a,sEpmm/Ӊvuщ憴϶ٱǤO 3+7R_ЭCYЉǢhY^*dŚ^!)Dȅ=rnwA嶃汓{"p^!;o7tAr!D$vcOUbn~Ðyh/D2m7:!PPf ]ڸW5d#sؾ{7?ǭZZ@c9ln&ͮ3g>㣨0g6 i@HBGz-tiRl t)RX * I/AQi"B $;} Ml-̜3لu2Cro| GzRq;5?( ߶JR| lA2usطIesNp0QC//dO_0hv xZފL||T3YB!?d 8Q~!\a;WӠ{7|KҡC 7mOĢHؼ;гErۢQ IDATi&Bt"*t/\bߧHز:ѫyariހV䏥k9eM,z(~AŹ3qnH*{p_LaԫWx\C[Wܶ,yq>ULSq]FJ8S28#54?-~~~B|F:ƾ{Rz:*4z41Gҫv^/|1{Cp3CaYrƦoSdzHq 9wɊV0w`| ƅ|:Oum~:tR3?Ngi0ĄkWCmϊ3i(ƹj{.BOasO5B E.&mX GHq$%p<5ޚy͋)(8m k|Bo? N@E  qگLa\SS?Kynm"$4-=Е)3BiYAޭ)u`Jftx;ox$L]Ǹ|3ο7"1!-@֓;2&/te8z#Lr5^3?8hP_Y,c72 $ṫߧU9m=_g>[?!tz̓opB2edv,j:݀zz߿C0^T~eڗɍl܅GŸct !ƯpW-Tgr޼VLF@<ۿʠg.whh vzC-MC,d;A$BJʭEsnoGvLc !$$f AԊ$FPH0uNHh&ր:jL4! %M̪k̦(4d@k'_z}LF#~/_ ϊDl|&Xɻ{5.` _D棸mVo涮wCKz7FrߍJӷfz4bs"*ı)Q~msG$w% l`"p xɑ?=)MZl՟&:vͦf rA-HBla9 /||߀k<:9ٰ̧zN`N~ūMKgǼgqe-Ky!⟳հ\<o* quuB׃nOfOl: Ef8vm0NF}[+`Φdi؎ڳ)H's|FPb9LR؏|"snc7F)ABdfdweZ4c_b׈n5*J]eErrksi CʉM/:E+g8~!˙v(Q 7MrgJhU\̠^}>9%TR3?ħEz+V_=YKDž,&=V|Q#eoigٹf]LŌAʙM|4c!-CNZ!OlE_<9fUlI>#bgZbE[8`&atQ0A|hؓE.B~[(=J*B+;Mb3Qj+w1j?;JlfT>ߋVh}0C:!^$ 4=Y+oŻb_Ԩ`B/ҙC3j4K!T#Z.)ٲk|2U~W%J;Z/tj6S&0DTyӻS2˝?yeh"b7)y:ozr w wb{ߔ<<:L< oy_K`M+EvExrp B:1di 4l>Kb+O$` !v%zeyN4 CrW@*4 uɇ.jfb0]C@!8BlN8/>C/3uF m' ,݈&E<_*i#HԘ6rZ^Z?n-ǐ)ʴ3.Eu{yfeX_V!weܢfR+JrSOeN >\;x]rE+Yu0322|_]RR,]z7w>4j,lj%,,̽nMi{[Q{?w>Ԯ ]~m߽Sz[4gfM{Wjx-+uo>Sݣkvsn/ !6nr[Ǜ;wǺκwm&]Gut]'M7eBu0,GXu4M>Dzl2mq .l_=R_zu 0f9HaFf޼yP*w*44TUXQ9́qu2u3gU"ze] @rrV`2E|y5< !Bd*.Ǭ̉])6MkՐ/`i/$D`sojB+DvxefoPk uoB!ٮ|}m/t~/H(1m{'oaF|Jr!T.Ž]!BY֬w4P/gS`xԊhËc`_γ.{r`&}:$^]"ڽ `毌oە >OH֩C0}%G3vQD[<~%?B!BkܶbcK(QFE[ٽuf+v 3bXٙ+z>os/3w~*O;Y|>I | gml5kmyB!B`^lR1T#<'Ь3T 6)7|v*~yͺQ.>э&)Ӭ>ŢOqEݧV>/)ߢţOs 擫YtAX0/.ԒǛ(6&WB!Bbn[p YW;g<'0'w9ҡN7w(W-==|!N ֽ qNH >?UB7(%>m'5fȸ L[J !B!<]FbGX%.f@9 "@: ݸ_OH`3zO{~@tt  w !>M`@{sMf]EIf}KB1g~A *kf~=7C>e9j<0}Tӈ~9\q?P<ѣ]B!RByla7Z ?1d}I0雇Qm}ݻ}̨icֱ):?u _m*I1Ci&ʅNJݛB!<0` n\ Qg1L1?z[Ehtx=]L%{0mV` CI!B!rGDWևe4Ps}]!B!D▱<8_GBB!B~9sN*P.B!"gNvO4,a\C4e'W% !B!Y!6ߛVn8:=r!B!9긃у% !B!al1[`ٙ='DBan>{iIRB!,hU/O.*Òƫ{5ʅBح>sa qB!}HbΦѦ{WP4{>}{=A !pr!\!Y*K|ٽ9T[o=5K(B!B#)eZ\{0Ww~쬦K(B!B9j\]ܨ={I(B!Bcٮ+h#pΊH(B!B3imʰtyaFBB!BZn*\!B!Dm P^w_ʅB!B0 ӭM?\R~}'P.83 *ս|ݯM7Yt"-#Zya(.D8sXB!'qSa0n#\qDVk8=Wޕ=F,+D.zvR0KO,Ƨ[OY T/mnhx~5$쩍ռ%ğB!2k['μ UXih~*lΔMnq܁)rǛ ǫ;7>C`*L:wE˫X«"ܽ#y/B1#=SE,ru]^Y0WJi.7Q'Lq&L&CG׀knHO:~MpQ,=(7MXe-gO34E]bM@Kӵ+B[7jJc^l?°OBfhֺ;FHؒhK7mF6]00*gԫۀ&Ik9[ӽ]7K1ڧ3w"_}ft|unP6#] ~ڵ:}ڵM/92\u"z[FWէNyr$_ɔMiՕ$Yy=,d,KB!Aۢy:O,4 !èܺMT";5Þe̟݄3>~ GcدzTu}lu_+`9h珺ӚIoeOFzv֗{9ka=bbyiS,KF NE]&|ϴ~$G/y m'N`ڂ,|9~^G PGa Bgn!a"^Ԏ 6g52 II!LU*҉s|ǘ5h(* 峕)`r>9/d׆}t%+qedzō>K!-O-}u{.9דB!ĭԽm+ ܯ)Wʸj)R.293DFF<2QA3TA}u0Q^Y2㹢-u_B ;YZwF>Sk1θpb*jl BL\]"NZDu Pe2} @.\/1)IB~@*Wn·͋t(JKWwG7SF ː|Sj}ʇxCz(~)׌VJR,O@(XB ^yC&w.dk"3z|-$OY ²Ԁ|cDN|Y음dRro K$+G^Fcxmkdkq ^*,%㞞`^׃fh& *z3M CNY)"͕,k8Y+|!N;tfn~hr&B!Nιv<`85=N"I|1cDZdRvm2͓ǥ]0s 1.A,)1 GqiQڬt<Lj_chұ"{}ޚM@=o0yRpͲ`$_%EYuИ*2>G{gGygH LP^xa4ѯbFLo-cx322xKW~6[+טe5bMi{[Q{?w>ԮH\?'>-̇{S:dY1JR 3[ZG(pTdzW,By5Yعk]?uֽk{0i:&k躎нrra54̈́&ӭ{Mhd9huM8q$E `^heٜ^KII0 #3o޼tshhqq;wn*VF|Z@Lx2ۤnO<=x{{ם"j}eӘI8y9IMP:H @]\e B!Q3](ncDo9´@PPln+D 3!bR(^ oZ[`Q#BqP`,]n&4-_΂?o~{ m]|{0.#*2\r 3Q,xѽ]!B9vVPn[݌dL4PPA.BPP^/sY$pwa=LĐii;NC/\K*B!/ܫܕ2ytqvPovco3LDԯOmi g8$&&e6,]ʶl6k}ҬiS-Wf˴Q۫!B!gRJ)2{X\By>0޹SG^}nD6iۦ5L> b6Ya˶i;z4V,wiB!B]- doה{V0P={q5*TҥKmw!<< RN/@XXF0hv{&9{ֽI!B!<#U;Wʕ߮ƕ#I(PǎW_1jp|}}ݶ*Y:ʕҥK9 >%Kl۸Q#u!%#(|}B!/σ;kO[BOSW\K/q9) |Æmu:~'ܹ5h GE][nBOZe4֟IvB!}. {ȉ{kzr[ ne8gu;5R)70~DQ-#6dυ ۯ?=^x:ÇҥK^a_2|zBK6<䗭B! G;s ޖ t[4;Qה "{ٳ@BxoXt3 |mR7f y\.B!9"ܶP`{N*iOc?jFȑmqw,Y@@@>! IDAT X>|伩B!Be  %܃>r]w "n[]?_=~;wr?7B!B~m躲 e(aR3gPA~}g;;R?q}͜9e!B!8ioR-Vyri.LǞ={ؾc 4Hl޲y3!B!(^Ϛ-p!C:uhիg޽b*r/uO>B!BxX;(eVVw,e{LBػo}n:N=cY }2 B!Ywo6{OS!.D[KPt);gf} Mv[ _$66 Pk_xOBCff&Gjr{B!sTP߲S\3WN39B;[VRJӑ${rHHSϝ˝;7ٳgY",Q@p#GRh w !>áGT{WPXYikR :ћ%w[*=˗AAN=_HjQ%&&ڗȅB9|{s6VƯKmj2YV7~#Cm_r?ԬY5k7TRR}9w㶅H%zTՙݓ"aY"jԢpsA5s bϩlY f4>؊O~ZϚ^6Nz&Z5jR+ix4{"۫#S~S_Ўu&9o?ӚkR<=GZO\A݉jTe&mG~ 5>73-3\*Uh޾B!GmR1dqh)Sm)W,׬qRoX'ʗ+G6mܶƒi~(꥿p͹ݸG(T*vt.gW]«Ѣvarw`sn͢=ۦc įB6-bWв)X~6>-#xeL8QMѠeN?|v?Ijb ,=RYW2Ic׳H}r,[#'9L|/=z.DO>CMy^(O U̫]S,śDP6=KN0)h:%~KN ]Bcid(P52[sj$dyvȡ\c}k}r*+Wj͖3FcGrJn[ THΒM]j-]Qm)ewFR nz|ѓo3lT1_^"xPF-ɰtB0cBFdRWo1gzV삚^q+n~3√ k0/\N`"^a k3v/3#Z6[g߇Hr:;&LVnȲ158,>vOp64%m-^,ScǸ';\ٵ͛݋Y}1(ݕ :мϭ/˯TumhlCb;F$Mzݍӷ+R$smtlAziVp B!DNta[t+(@Y5{ABjۦ5/ @jj>+3*p x4苽zҦ#n[ 3( ն.[Kf|m]ݾsU$lYbռ04 oK]+ҵUS<֨>Oftk]p3NeJtQP/.؜ [ֻ_ߞƮek1=KTԆ6%;BgJ ܔ?dmFP'yBtt5V\B~ ???HM!53 ضׇSdݚy )!f?ӟzieDۺ5yޣ ]hGIw5_|hUXi;բGsA!9`͑ɭ \%; qwWw!j-=X_g@~g|̣:u6-oߖ[ySgf| `.ƀu-ItB_Xu-K^-Qwq Boo' " ּ &Ⱦ7Jta7fk{XKGF<9-5Iŧr~~?"#iI.3C ^vI:ՌP bBNP|NUe/Loz* f`(^B`B٥ɾX:ZU>wR84}Wc(4W,ݱ{72`fbĬjJݟ|xi`]מ~v~>!Cj,۞VH@azAe0p >|zNt(M6%o 'Zg3pceF}ڗz 7z4JYZ_gLP\II-L}Qm0/΍B!ȱc Mx 9@&q|&~׬`]ܵ D)]4aKl\ǎc}mZ(VK9/Eg@SFHvS>[ۄEcɜ?(~u OaOUZf-zZji CʾM D ڔz/fl (pN/CpQm3&ЩR0K3WBm]"t:P/o >_ɪݨJ5UUw'!4RRD.?/B5T(>*[apXllPydǷ"X]* ;&}rXij~9 !)^5G)P9*wUZ.<(^S>0~$v X&۵{}VjתR{9wstj͓)wr5PL JEpj>Wzc"/ީɥyg/#9 `OSB2B¸q f.حןgp1|pZ\\vdɒZ\\cJNN |u]PJVJ/^t}hҨ{ .\` [{uuLJZ5kмY35mJ7!66> !+˖poy7oF}S{mݲ_B! mܼ嶎7w}׏u=T}u ]5 ]f۶&L^^y0頛tt݄V&/N2|]!B!Dtmٙt3mlc5,+or!B!9[5r]sT6M.\!B!D9UӶ> ^P.B!"qKqֺ̮eX+g)˵aޑP.B!"GMv=[XbmvwV.\!B!DΣ)kV9wnL漍*=-$ !B!YClܲbCY͌k==;f_ !ȑ\MNvB!}. *UUXSҦ@(dp3`dl3+mmϻ$ !;r(E@X{B!s1:|J+wsPhJlR@*,]-qkfn ҬgB&'K B!D իZt{S۲d]W>e^^P.B!""?gєe eس_%\!B!D΢Ume]˖Uǝc33;- B!B!֠Bۢ9dz!K(B!BXuf^wpJ-gu@By8՞:V!??E7˂"~4a.R毌o݌a?g܆46hEǩs;_J!B!m.mpLꦬqkNreRn{H( ^F\\*5*U_pneѻCR| bօ )QρFpn ٘&-;A߇~X2k2~r7)B!b=pr[wq6{v%)͟R%3XxלۍXtBe?sTkRp ˛\5[\wFH4.hI?e B!B62݅mlX+ wJ)ٲ5y.b--eQ|syG.yM DԥNԳ]mi&dЯMV3r۞~zH4|.#~TEҢXҧs$uԡ~WGʋ3ө%LcfzN4~'xc֯$)t6Ӑ6Sb _ӿ1[Mw猛O0ڌb<ՐZ#hxG`xI:Q|f83 9T ^iȋ .fn^!VVֿk(ˊS 7 a:]a,A}m,h XiOE-ORfgZɖmY_5mWq+/Зz!t~їUg̒iDiVm2gTd%;v֗|7e_#[ m?6WbI | gml5kmU_%^ &D[Ȍla9<组$P,zUpzN *08Uwj֨ss^og֤f9y\T:/G.Ӹ=W7 Yݮ|-B!YӋ[v/+{+{cwr)VGEk6ԝ,XGە 0Qz*xu(q)8w-:+3cMX,?K o)\ 9g&uzZ@ |>YD7@L>93Ofѡb}¼PKoظ6UN5P.|٤:VQ2qy)oDÄ)#c:oaU?Eķx?x?ǁn֬ 0cOɸvh62a4HP~SOh>GM:f $5݄dAwW,Y?miLk|i:ٛm[l6geRTU{ѽje#Lw/qv%%z"vzvcdǩjI?bTv4!qrd|=Ǯ脔o+BސyucڪC\L -ǣŪϪfZYxi@nJ6ywn@!"RʖҬ5ќe:h=:R)WI݀MgZO ˑßmMth0Otmޙj{F}o#H8-gH-kаS$f6D?y&$I "bEQDyzbx)J<={lxwޝPHmvgy~f3Rך癝]v7y`<8ZmMk4l#|?/ >Ae_,~J~Θ} !1\||:I#Q9X { vEQG0|\;h-׾&q`rw_ޛh>G\_R}|q;ZP^ y\ˮ?q6.~s^27황Sc@y^[V{_?ṫ/5 D5X*u< IDATr.hFʆnOkH!ja~ܿ~X-NatEv}~] Q h ?aiXrKvX]a &_ aA/yX:? `wF=O[I8؝S~xM 8 =$|h@oÇAc(i}[p'>;'|2'-OgA,]A@U_(#pFOV)~ _ީ2LO~Q0遮˰eP&_?t^7.gaPHɓ]ADDDDmU&VOXP$R |'b>14Z/9*?L9adccq|o=)lp.>; ?Lu . nǭ;Ǩ8spO}"u;;-.q_gq0Lt0<$qS..y!Lyvz_11誗Y]uͼ<ތJ!Oa[qܡca8LM]o<' - zWB'<؟.Ļu(<*&,T\Ы۶;]yUt@v^}X0_> cpS}qpw&-?b?зG-f ٍ6.6"""6;;b=Vw4,'Zǚulkl*Ek^ !a5.Il]f^)bW;޿mO8d 99~C&+̽U_?`d nT6%s'8&q+ONjv.^Hz@ME$jb|]wo]_j)4/;F5t]ѻqcԁCϙx QKsǯcٵHZ-qZB#h!w *f̘!V\) DIIի(((~(++J)_jjϲ,?)e:npo1#6:ɉEom?i)aǟ`{w|m&jVK?A7&SF!5)RĮK -DM) Tv@05 a`KVtR %K&خ8N9pJJJRJٙN4uՏ?Cֹf͚\uڂʤ[DWm4Jyc('"""""6)Y"E)ԴR-17؍ō*t|xs'NY1QI!܍vQH5U|PNDDDDDDm)<{n_wo}ncұ9-ʉmWxv֞xvǶF男D*g('"""""6ɭmו}OpvC9%a-f""""l޼ii䀮cW+xe ?lV}1m"juz-D{cժXvr0h hoGa0 R҈WkLʉMDmiBJ)%C04C  _lz{=Y sr""""""jS#q!pkOxr""""""j[cUo!d|BX=ޗ[^90xiTBACg>vtHDmmXf-Jʼ]DDDKKKE9-KJ ) H!!X\ )\Ư'rܟ0 ebԤS II2J%Q2rj'Q ֬YuEo6oނU``oWRB2C 4?>_q4>ʞn0 ۦ5#R Hlg"լ}Ȅ2]2 fcGDy7#"J(-+c '""u ׮6CNkfHJ x Ojs2! fhSt iTiS(4"vlzHD<6I$"""""j[Lӄi ӈUcA8ȓ8 ODDDDDmO2|-Lem@sq8fT;Qk{ܽݾ0 íG5ʭr^niGc7@F"""""3a=7F6&6 |WyƓo"j+*霓qCyhD"""=΄NaYO:%y/`]~5o'рMwUG͍WQ=mm|[Rj 5k[!unXyyyB:;;Ν2b}pN9U٣CCJ߳p׭Sг޿f ^v4@`i^*7""""jV~g'&xǒo-OfyWc/B~y&\_r#&4+XTȴ30pISqݳ˶] g#Uo@mxr+^|~N>.KL;}ӧNǞ1]Uӻ/]ēNK>c?#߅ c<Nxx} <8q4}a0r${"|?E"""6.^ZC)Umie֬Y "n}Kzi;y&jKKC{`c)]~l,zs1^z-A77 \_Bi^Xw,n{aj-2D%iڋ_w>X`q~_y MW|bwՔsw?Gj>Ksqc;1e_y^[VY/_GE$DDDDۀI $}$;v@$$aYbï5OqG 9`=2y :"7p@7;6nD"|dBWMWU4@ ~p}vTӿ'ˆ=Z+ۅ>, ʔ)0yP~kDDDD{\]SLo>eFb MAp!>A3V)5vjDDVILR!4}]SWѸ/ަxҼwѱ]1M0yy:oGL䖕%/Ĥ:ḳBZϭN ٍb8T8+~lCyboWL;"FfJohSY, :]H Bzͧ<@Vv ^x7FmH ۈs0kTl_fiw!fSsK?NbF{oI__}""""j8|/s2 ;`x@>UrK!&2Pn-6Fc{Ȟ'`_ccXP(un] #N¡?>yo@U5XBVkG9~vXАܯg8F>7_&b%Ɓ84U~v}_Ԣ#"""j -jRFhk80C~sXBy=CS}}_ѱ}}/֭ཹӃ_bJ\s}<޻Do>yg╿3 qaKs Ns,e00o&-D)0EF}6ޙ= '.N㗈v;:\7"0z6LƱsqwGƝgRf=gPDDDDmPaa!J Buu! )! ݋VRJ~t<%*f̘!V\) DIIի(((~(++J)_jjϲ,?)e:npoסfC|k J" bBTFMVX[da+xkȩ76Ɵ4۔O0ͻoa65ؿ\cFm&"""ېrYM6#-- RJ ݆Qm7mn; ސށƷzk2mBbTֺ"%%%R^^nI) ' |u iVۘ yQS d>H DDDDDD۠X29HT́øRJX\v6R?KT)/h;*4 DqDDDDDDj0qQGcSM%""""""jvnya"""""""e {C.DDDDDDqzeJD'ᓀ@ؼrKaKaGDc{BoDDDDDDCybSAjc0RrbQR;qNs""Wzz6oނΝ;yh/yfŃ56']W)\-yt@!_K~-uzNDqǪUzZo1`@o3"V.'@Lm=>$$utʷ!b<J ~|R[}%~ ̩zg"+I)1p`vVʐ dUKmPh lkX2S$0¹)z3q;DDDDDDB& N PO_feu$~ο Qdg<;@_bMrkDkeRM+s] ^Q\$*c& """""JB-R& h H'Kر༱lt6XEĎ}L{Uz""""""=[!|􈭱BiIԩ4{,7 ܎>jZV إPJD ^:yI!9DlVjS`\rhwb(or dboB]a[ce wD9e:tŜ 6-E*~N=H /55Bo3Q),(@jZj-[Xح8K٢R})e~[lNu.""""f~}zB8N p+Z)wq0 ZY%a{lCkv C:S /v`S%Ā~DDDDDDi4"9V$lil džK-'"""""BRRVY@ `Cy :UϩSg.ƕRWTTxEhFqRMqD<^~r"""""ڻ)[-RH$LLD<77ΰPBBS_ܭ6-#!DDDDDw3 qG9LTbo; 2*8%J9R0  q.k0tII!''GgggYfX)o![=jQI-9lc۶,K~U^^MEEEZ `|5vNc׬yr""""""jS۾}{0 `K)#Ўh)RJi=;׸{۶m!vOy&TZkGu("aH$dee뜜_z f('"""""6E)R !"J)Kkm !P 6 C;S-#^NjBeQ-Lt[2M3*,ˊ6"W'c('"""""60 q*Q[ضn۶0p+q{=yxRJޱm[ !,q,aeYNEEɩ+׫IBy?hwRJYRʈRBBDm۶ʶcm[D8OޗiZJ+**RJ|QJr&NNNSG oP@nPNDDDDDDԌx0ljEJ)4M'^9VZqᮖPJ!%%E@$юUgt4Um;@@k9Yʉs-V|hyTkm+ض혦-RRJ4 Wxem///T4UT|z@z9C9)Zke_͖RZmۈnPZk0 8rwrvo'MîEl%vm333uIII9@h DDDDDDԦPYB؁@v(۶a @l.yR eY.ԙ@gee:Nsr""""""jSR j8r+;a4tfffṨHڑtzzuNN!F"0t8~_^ """"""ᮢ.TRJec۶E贴4]TTVk 999U5B5P DDDDD{ٶkעE УGdddxm+PZZfL Ogɤ mZkm!ZkU0rɭIDAT~_P(X*C .w^C e DDDDDw߭ES.j[`O?{B+V`]El˖-ѧw:߳dӚ!<ʲ,FZN@ NOOɕ}z+l )ϚBb('""""jEJJKѩS& VBiiiԩ֬][{8cRK)aʶmUffryvvC0oxjP(CuIINvVC^>6ƿn זeiWUEEE: `0@ap7|{ƽwIB95&OBhu';֕R: @UC߭ PHam'""""A3_#y:c˵R=NOOwa8zcozC95ݟheF4c @Ann'""""K EAt|^9/-BBoLL!5[RNDDDD춯AvRN(~瑯}!: ,iw<6:/;wRac/**`P{Ex/͂j6p?NR9l3 o]9㹸7~Gq .n ݭ/ g3Ux`. '+N3Μ| Ds< t[>_+*0pΤHk#zVJ98‰RIH{ߊ++r ;ݮcꗧ08|B_~ Dn1$s9_?l* xoþSu%O߁cG‡yP\1|_qTU5iwY """jt?-"⪫!U"|xCA#qꅗ!bߥvv8| xz~1{1zvS%Zc 7q=a}G< z7x#|UOxlxeֱ5.{zޏ=Ϯp۷ގug?MxYj=޿u:ɹ7>! ,;|#~dźg5Cp#cSbؖyxoQr=,: W<󟜇ş`y_կcqѣXx/acKw/ƝOU5@AQՏy//<ֶ=5h4?^'JbJ0|ڣxڑx pǗ5fc]-\9+F=SwC o ɗH4{Oe˖UB /^_ztXBU~7饹'qO-݈KGsGsGfjR|}!0# |#^j{p#N'`a~mbz>H?X [`aЩgwˆbK!y{M<(z:zKS&oa6ߌ@? p}uvz耞CD0/(4RQeW\@aV&lZ_q`=>@JVwY/?68c,ܟB:).h@ުoEsðap˜9nt|WURgEWiYWa!c񒍞|acOѣ1swcW`eKp1؋&Uo<~T4v Ɯ|n|~J.oŧbixi} Ə g)1jXL|>>[/`MƘ1c1c_- ?|_$z}s4^U;`CI[!nu۵?ϻaqԦכX{E~eW[W? +38Q| w?#^l'8YK0鸷Ә><ş܍kۆ,Dɦ"ȮǛn}߈l _>n8/,|e\y?e8WECq=/v~*\| ԅW|( C.vH "efRGb“jrކv׼35rY9ر_Qgc@ms\jkwyXz~b=ΧQ~DDDD{Xwx7D#VQQx%233qۭy}JwCeDR'AdC.R du}< O~Qce? 8dʙ8 DߑG`g~/ h'hT^j͖FࠜQnpd?FAPe6 qlǓX]S~*%s 敗\V|kXNߕ}/_hĆW{|}Wy9endο?[ <\K.ڵ[o4j"c++oo6to<t \L'Xt5'_߿V\UmСyMnt,*6|eJճ\uxs0ew^WS6"Yڡ}z1p؟ۅ(|{8 cǍqpݒRrXN1nѱS_vN$n )@)E[]$?._ Dʠϳ}@~T<}*qX)ę۱OzT^^k_߾??0tX7zb~d>n($R:/ew<ďϺS_1[npL\ܣCPmWXpb}sqNIn zy's1y80)pGFOk~>Fu!"""SF$9uH!/}ދ99`HQ: ">\q9 vŪ?CAI8(]ēDݐթ nS]G>K64R'gGT ?d!yM~ sl<'0iĤ{V]O~ モc0) .֭žGPX.Ǯ3hҎy/Ʊ^rdf(/FEj"> &w#Ac(FiOӼqÂQ7=&{'m9D~N)G [}]0䜻0ʦ$+n8UabLr۩^׾n~ޏc76̞Iץ+qW&5ƻj؞h롲6SN ):l=sn Ðhc}S^7ހ.ń!]{{ U&W@c?C.s.GeL_;qD,yxqхV snt58 rp;7r=0Xd#&|X~9Q//ݽ{_qNyȧ{7/7zw ǽ=WS#'ľU!a8 ߱rT/PFKt>3{?d $-+W@w=2|Хkf`7w_YRw87uepN{X*q{ƌbʕ@ݻ|#%%BJ)+ajCJ -Rc|CmHk~{5`F:GGoxD"URRRpUiKO0DDD1ro35G={b}v%,]Ç6WƢŋ7Ə !7O?=K6iIRʭBqʥh4RZZkqU(#GTfr  sަk׮uҥm"""kUa&0i$oQhP.D+? nүoMFDDD8ICi' jĪ:DrÀ]DDDDŗڒ& eA 矈hW0:|{=ivr"""""j:{Lh8tuًߏ]RJ1l]vf*e {9msGkaf~#w9QSkM+ܺ4uq)VJi^=!""""j ]϶j7 ݦt(o RJBPGomڵRz `-ԩ`˖-Bj lٌ-mK~>2dO7*~Uq)w79|E]DJ+W64)%<o3k6wIzzݺ"wZ}YF(^=K&@#eYU7nʛir`o3^+##}Eii[-\έDC޳d $w) `P#k߯( G%Qr""""". 5*vS:h|Z)u~~~;B ''"""""mO* 7hP(MԆah)Rj!m[;G(DDDDDDz9mNTʥ0 m:輼k,8 u0EEED'a(0Rv+2 C%O.//%%%`P@nn5kV 򺘦#,K+0DDDDDDDM0 G)8,R~_Y-*GӵOp8}>_rNޞh7jSpXHUtZZOW8lg۶ݶNDDDDDDmmۖn4MBJOOo>0|0>) P#vy`,zw }M6vj>¸2?Ϝ 饽-/bҲ|7??/I԰۸mq%=Z=$v~=AI|ytn o<,z}xCrnkGfpF%+G=!KG&*bLƽ5U8<9KO$]7җ&ݔqOzN^a<7n0$/7``^ `g7~lKmS ŷoO'*p>/0%ڵmIb ;FbGM㭘iRlYQ) ^@rj1cV;,) OOuP"a=( Vl %R* 186da1M l@O! nCS==Pm$J"w 9ٹ[%9pd|8U=kP +>w ׏3$XHY>&Yr& Gm4/n @ߙ{Ʒy/TzMf b{אxqa藲{F}x5 n&2#k჻2`&V,xNAoPu\.b+Fc8kg?u jVc CU"a<1DX!*x Vc CUyVUUq:(N'"k4h4dYd_rj֒N8A‰Gh7n趇 \ (߷dBBC bvZhN'&# t:]SaUU223iּ9-Z@unۉ̙3ѠaC3ɖ-[iӦ5kVa=wFt:6mٳg%~jƯ*Gsy%8e=t@#;49F;)4 mڴ揽о%ڰ*BII Xg6cZq8\5$IBM7݄F+DƚĞߒе>ȶ"%N$o z Cvu ladkҒb? ZhA1͕ZRLO0?2價`#mM)~.5eB)L-+}H/p"iҶ=1!^HJW@sm̮j6 H 5#{I,Fјm֎vf-i;q{?cΐP^4o&%%ӧiE˷eT}oZۀ0:uSB}uoӅ_l:d8]o4ƑͿxS*j'~Egޚ̮Mst[JH*]/ fVZ0h3+ak;ћʂz)UfPFetdffTοb|}}Zٌv*AD+xBMP"a<1DX!*x Vch,AijAZķEU7)t_.|dKļp(b xVc CU"a@1=Nj153PJ.3J*JoZ%t?0MAF=c[3E>1Nv/d^??FlEg Nv' ; п?h&2精L@i7O5D9%|E &(10JG^"7{kjV=kŠr/K/$%%?з7+]%-mܹ6'VFZʀatgz- e  H4n%P.cYw-HFS;5ZLn#7>_TXgσ?Y0_&H)ěoٰ3rx͢ߝDqeo}m\Ͱu,qL'9aujV#A>)31FG%Y"bx Ͱl d_=>v9bvs^yi9@B+:)6>;p=᥁s!M^3NDFgY*GJHӭdT'l+:lMwmWZتz1z?5i4624D/2ز^ߡPyk\N7ȨV cBBA&@ \_OcU%|d@/_ߗ%ek%}Z bHK 5Pob6eȾ,x"+ygQ>L o@1nWUJVC*^Z$AJN>FGUiQm*J xf&kS^ZLY`/EB[ 0V3 $I"&LO E:AO$Y&GUKz ; mz5q3!Ә ,]60:\fT$fXvU/:Y}L*]td{~?#NCI%l5Q|޼;_TO0P/Tk vJ<ʗ'$33|OT >mIKV\B;y(!+ żD|z|KL0@"a<1DX!*x ly}fvRx.ݺ6w_'ה~s CU"a<1DXqƖp{G*W'j'm3ْ[qBMTcwsa D+FavvfSWN2o]췷ϳmK,GgQXnjLh`wS2f]ۃqVPlT5]La[п}gΆQ,|/[k' 97Lt/|}J^blBP?灑:޽37٘mMx>|xCn(Wy?EY\xE(;ub׫ lYP~Ν:j4g'nBvV$ɇyO|>֋o~~LS!!>Z->ڗppb?)~W;s7!]7g6}8jf}{nƖxk~˨b  qKO۽̜%_%açDOpO%AeIYF=}  ;՞aҠm@޸fjKLKzi$_bXѶ`>4Ѓd O3 ϜbbqhȲGFL&>~'T슁3uKj99<Ɔ^烛1ZP6ŚDOX=\UFc5QۙI)PJʬ hprdI0 f]k4P*=GFf1)'1heYJt,TZXnA-% 6Vmg>34(3va>/7tO^7ҽ8ESьL#b`J+VJߙ{Ʒy/TzMf b{אxqaĭغoPW :Ga<1DX!*x Vc CU"a<1DX!*x Vc:v/`̓x ޚ"ګuX}o!'N䫯䫯ɓBᲫuXWZŌHP` 3^ΪU7Ҋ,:wct5Χ;3k>R:a$(0@223+lQSZL];׵yMy:MTGzv' hCN)`Z` O*9_#9֟Ȟ3p~8Y1}|st(ɟ32/~%1I@ u[IX.HBΫ܀Iڑ'6hI ILFBdpUh M'$,fkr69 k_BK _xl#WK)8PL9YXz=.fON!h*.ou]&|&+).J<>a/^&($ug.AFd#Gc*řEFV^meϚӎb0WhF#(#c6Î4).QhYPJOrrl&MEв7:•"[3X ~iX%,p.-??MM WB9\/TU]mww 0Fe|w m|Ab)LJ6l W:,S`Es(-3'\UU)>#Vf) >ej 1g:gCEő:` r c3dV1fHd5ĕ3&4[%UY#},|{{Mf21V7<_=owr L 4!е]3c `: o A -um17{ h}# ^6o|]qEyڻ7'1dEw~0z;k޳BXK DǨq*TEo[l\D*x Vc CU"a<1DX!*x Vc ֟ p:ڵcǎмys:w"WP{]vaX;;X,ڵ}3Ajݳ;v;5_~|wtmˋqjjvHJ㖭iUyD )gcvtE'ץZ{֢F +lQS2mnf~K?:/$&_g'$b]{VOs9\߽-\ZL֙$aT0@If\>4mM$[ػvTYO tiÙ_wTXi5Fo'h v 8:"$gӯG)$O#ϦbIέi`S 9{p/OgS CH`KAҧql%tjOIvl?NN6 {G##$7A:5:GүD+}*GaË&m2W=;JhJ"a 4QЂkI Fh>- z4]ֺ^T d$8=M[;kPO"KNIA_owA#2xf_8hsrs fAE`N-5wjŊ[AG'_ss]kA$E>[P8`! " N%SI)/IqMyeeG6~'K\Cg V l&"\(vUBSldYkH:=:k.ҭdgPFdU)!!'Oh`tx>W5سNvʚ?lM5IzqH4:_iO@-+zItlu~`4KKbh0Nؿa5vYCpNtRR&h;wSz &usm kКidyEp.tp uv>WC+t:(W|Ŏ|Z"{>gi 'gxٌjhze1Cxb ӡ$΃ph++'&/Z3Mq`lЁaM6DGmqB_0wl=F/Z3y H͇5R P2v nOc#4?Ɩun8_VHP׈^Mg]-05SUJٺx){;)R#/LYa?-z5(J*+v6ϏJW;8݌- 0Q % Ť {9KK|Kfsܧ3f;)e>fl3_Mi j J Oe\VlOˣ=\OrͿ*r~YC9$zyן?g~ ΀u{clW:Rյ*AwҽĎ{[1ӤbٲS xޖ1$&Y؂+!U\"202YۈIĖ'Qۂ@!>(?zerArUmTܺ=y|hsZL /rݴЀMt& ʩ8Vi=w'X 71ʖq g [!#С]RIN~ZszW,ĒeA %|)4SNŇ^.奋YuΩ[Fii烥4(4h7B?vzl8 : m'UK( HWֈ>a"z(!!0'Y3!x$@VXf ҬUܩU$TZjM7E\p}ԉ?2PFDy}]M:`q/%ri6-Oj03f2pCRJ69<1$ᐍwM nMҒT{'<2njO=]~?[ K,.U4\Oxm^vG.c5 ˏ+V j%wEEwr:q$4-ZF:ш!BB=N}]#} g;VFH'ȮP9.{|[bJ˽Hg, ~[&>X9q^czx3cwͮNgӊ^tȖ,1rƎ*O<ͽ~^=VF"1f " w*"뫣:m,5.r=K؃^b.Fa{uF`mCf}dL\T`O?}Ʌbw@YXrH^يKrRS>C0d?8{sϨgrdz`8CQ<Je+_9(XWfp{;+7"׶:;s}_Xs9g$c*JeޅyB}f2p̟xkujDji܄V#rK|M C'QZVr]mPUl U}}J?bF,;*>›;35_bܽTt7?/^* |ɘYKXa%YYBDb{2,~-+gY,: Ͳ+#*KW,gV3Xj5mZw?HNdj^ɪuYL_~eE j4*%eN_pI\9_ jhsyl9K/fxz$bdO7ˎmϊE D ޅ 8ZyAߛI umխK#mM g9WEzDup(8,w 2i5>0`a)[Dtn#u;mbs}-&R˭& [<5bp8'7$VPv%~Zc%-&Nx硁JϠlwŜz-zM{xe8Ox7vgp@䖬G^#3t@0kHOH6q6fEx2ӳOSu֬˕\~vy6_ӈ4.Ld3Zg z;jӫcP)5f>N:(mCQgѫjD⢴E/~/(!(!a"z(!a"z(!aȯ~.y%܅.yvv/(Db zAE%ggʷ&J1LLx͂PߨShʒLR:I^ 7[BJHn wEIl˂wH䱜XY\^'Ǯ5'g#M8+`"7xJ!e\=6.mt-?ʥ,cӶQ'&-=M] Ŧ7>]a;xejiBtOa"B9\^.*j:>;c OO_Mu]NU^ vlg,(I{f0u޾p;#tU22åHլJN$xf'y[LNJ~w)Am")m\/Hn3!} *?_ACt> Ko*,;N| cxa\}5LqpLS^ˣ.6(}o-7`J AHqUr-4J"k.$j1 ?S|.֭\?ze7cOiC:Dsw~5eYbvWpkw~$#ѝl+`Q [<MTrNSImNynGO均rGmnNï0=5.mjN+7O4f 'Ϝ̰E ]!`by"c|DNN@ & ^;) €o+Rҟz^G"h@g_pQ5lM8"TS"1DʢPFD@D=rxdIFA/.P*ѫDAjfU(!(!O+4@ E0hРO}a$˭+)4,DQ<2i ,IENDB`kraft-1.1/manual/images/de/documentype.png000066400000000000000000003101061450127457600206520ustar00rootroot00000000000000PNG  IHDR 6l= pHYs+ IDATx^wxU{6BJEw)6D`Eg(ET,`Ab}PA{yA H#:{'g$!$֙gfwgp.@DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAg *o"""""R,ˎǐj` X<{cDDDDDDD`<DDDDDDT>tUQVe ϭ">&""""""6*c*Vsj P8s(!"""""3Ky5 ~L-""""""܂,L+x_""""""" x `7Τ;P5P *X1j?Au&zڏhHhty?@_(-c+(}e[""""""*eWen.*˶_j?DDDDDD] ooʲ߲l-)˶*_k_nY[y܏,*˶UQղ<e'"""""[^yOs*>J]@"4_mdJ##"""""]p{ڟݜ]K+#""""":Sp۟.Ա.Gc@m/,b@1oc5߱7GDDDDDTZD'uoc@$R^ES|2u߱.GyS툈*޶b*5߱LwMV^Ūk;sj9nNc.NDDDDDDecW\qu cx#"""""<vs. }]LK5_ͱ K+s:uKA]4JSjobX]uu[/yN|֗}jPrNΟSe# """""G Z}%[[ e[tsj:K/9> F>K㭰Pmʢ4qn{_x9b.uKA?5:@iN溘: jS9oѐDL,u+SODDDDDTQ[aԱN9 """""@D|P\M-ڄ0\1X'&/4 '_r@^D@ .rL'X9܏BznJ>v}n] QRTY؛XA4".b4奿m_DY\GcLP'7#t&ҀP.-&\Dnn60 Wӱv_PODDDDDDaخ .8ڶjTlݾ+V-I%mCCZ (z'r\KSe惢tqq=s$żXD,C=LrsZf̓bR`8cZ07DØ9v""""""A=h۪:AzEغ}'>s:"–onW8pY7xP!?a_u1 rd~61[eYΛ$?/BHmՄ"Mh~vj۪?5QT m[Q`LEuM1/D!)U"2P2yoGn@x"y,嘚/9ݼ8n2jlsZDsi!F?ou{`YݶJ_0统""""" {w Р~]GX2+[Tn DEFbScq\7jhb゘Wyv8hʳ!+&c.79qɂõ.r 9rj]r 1B ; EnvZ7+&"m/j@X&epx8r츚ⳇ iS>(L|6$mW\B\qI/8-ujP.>0&$`xL5 AJj~%:hؠs9 o77\ӷhIo~|נ^]xUxvhu ;v"?/z}ؾ-:o}֩}[mݲhoN@RSIWm߀s]c>հMR]WsdXЕvONc`D\BjwʲUfq$=-hQu5CjfM-ICM]au,˄iv/n[AVQ)Xτj!Xz-~epD2SR}lvޫf]eazpubp=n.Ԉ'P|׫UkeYe_͚bj*QvGYNe!'7aa?yv;Mr*L4q4y'ŻΩ/ X!6 pе<&H_f1ѶuKmo~W(h,Cb]rwEMzLw>)j6i;njô,2w|y~}-]3M| ,GvQ3>oL -jN[ErJ*>|66l ,,q .SR«c{!!X~>U{~Aa,~ hެ ^;yοX 6mފNc'ӱl zk ժUC1éHNIsC@ Ƚw;nnPt+V3?Q˦Z𹦑a6:og >NA1 ~mU|йc{& Y֭잋IEA O4# ͉$>s,]O €#=#󧖅.8~LbQHܴ+׬ v;!x˓sn m[ArJ*Ԇi`}VXd9b(bk`3}ǟQoZlϾP~s?|\5+p~x7q*7-;o?? ((,(((3-7^>7Mƾԭ114iDDgF 㩁dv6^}s2lݾ?q~P [pqדZ5&Le/=7T|P_p1P| j-kDL3u^]k}v::t\{Z/j4nbN;J4,4-$;wM)NPڹ)ygDhhf-[V:&ve*)qV9=|n(œo| ":] lܚ,߱asRxECjZԮc'~\ƺ=cǓdjηK$svsJv(Dr /p"9mGM{Bl#:﮷Xcoy^MY'~_nz}g-[4͛!''iݏe[~/ E7Eog{:&":Ԉ藞_}.EYLKܴLyL.ntjJn?v[Vՠp2m"nzbBTq*5Ou|bUΓa&rRM>@t=cw G[ b: =/(쯿gtkc֜o1a쫸eeB<\qňe5Ky[j~VԪ `ba+4ۦ !!!E#G@}'f|?`Qp8*|õ[b{5Tx  z=qۼzpM0 &?f箌Pݻt ԩR۰i[3@qchӪƸI^?SRѰA}5\/=7`yQLԠf)ϋςr]k(s21=v.7_ &.u뢹`He-^c`"jnSp>DיuKuv:uhg<|۶=#%- &QßFҎ]ع{kpA:ݦe |~xe 0I OvΥf-LԴ4ؽϿ2Frg9_b?mY%ţ`!=#k,zr}_tgHBm_[_,HN{CL|5\r<_\P y!HNƋE^~>^~).y^Q|w?DDg(;p0g6cFi|1nǷo$nڌ7MB^~Ois 'EAmv%PcDm6WD薂:Ek"A:1us ķ`BJ^VdjZ(Q*:wh<'M)emx1`R""*_ea㖭x'0Q8y2pu@Vv6e[N\9⧁ǩS9hެ N$'6;o/¢%M7ġGq%sy{ϡ+RX_{EjZ:4j=n+;#3qqQ, /^n ű'qw 8 bf(5kjyE9:np*~&qf|-z ͖mՐ+Ve[m69ioXbρ5\c~Z rLvoڶj!=';uud8HN-IX~{}9v^9qѢ zMp pst#$Q1)%3'ÙW'ZGކ̽;SbDDDDDDЬ9b֜|6mM/!Fi7nk{ĀU?xRn@ELoE+ yx\q9i]4;uv]y6 tATq`rL1UjC¡شn[)HU+sIDDDDDDdYٰlبNT5tI 1|]!j/n@㍜|&LX/kPSDDDDDDTSC^u p-XԸݺq?JDd4/ 1&9iDDDDDDDK}ٱ1}>(ʻS='@sUǀ*7]A!yuMSUYozQs'W.1""""""`N Rv9.`< 5Xw՘n)?JDDDDDDLt[ZUWbȏ%`!e 18n$NKBDDDDDDDQMWHMCGk)ؤJB0qDy)quݕ j.P^BDDDDDDTZTQujL}\%_.ـ$tOR]c]Aզvsb,jR]6_j=iDUźZTuuΫ92]B8 `ح'j'RLXчGXB31}|,zY`8Q%ν?tH(>0 }Ğ9sO7Q ͺ~[E0c>>S|_dov[nBƒf6wx5l&~\SsaZh4 y? n'_=?`P<|6'r f` 4ڜ?xj&?y ,X"-t;rDNn@w;ѸfqnWA )k7{~I[20SG-$FuׯE: s%Mǰto>8F)5W3˾4Y9{[aIc 즈w{rp8ÁyrkM<z~"""|K}ͳSJw3?؟\ib԰GӦO4zLL >ct-GjǖT̬؟bu0 M, .iH޽?}.>[ss֌+k(f?=S\͇Ƹ xGlP_,1q˓O⎋ZVH*2ZRa xo4QkfaH48oX?s=5G[8. v.i#c|6܀ 0/3oG!moàn"0[~c'}y`!y~hB^@؅1w,.Wwn?fg#qŠ0sаz.$I'l8jφQ .{d3ć"{j̞XL^_??w9x-+4L^4ϿvY?_܋zA|D3 Q/}z4~GwE߮5˗ADDD??gt,P['ry6lPpVLg=9j'cmEB kI0p8<*ܹU?~bg%1AH8jװxᲄXQ8[֯ ԌFTlcynm#]QǦ|k1jS{s$ԈBT|E ؘcW7Ϋ<`1N^4?iWBTIBBqo fĻ1KP n9`- b bgq9\8Fx\[)RXn]erYVc A-aI 4DUÁD#8ր1Ѫssބfr5ѵZ.;Pkq~z}V(Xf:2, VͳcbʕaлG8>잖b8jVoف8/FXg\wu? б-`!=-Icbf.23p*VBÀkasNAQN!qSϟ䯰$cTiY O@<ۧYVVUSŢP{E ZC+MO0׮;V`G!3 {^chqX};SJ04CEj/BIÒߐ`;ZoB2ƞlqL~8)LEr h@Vgi`GT!ݿvi7ػkVZLFLrQNNAv 4/Ry" K&D6gE@TY mte2qdx[W)D >|x G@uU"G "? 8>3B"]? aB|tD9 -E\T5:L$o] oБ(8Z'W3UU%?2t nh 5 `!qd[hp .,1p{I73K''㮳UV&!`5bQ2 ]”bD"66 WAawЭ~21˅8:MFYB 4/7ėKՌ/z7-bҥ+ׄqa&M撏_'J|`fΗF!t~C\pD̝%rK Z!"^뒽10Mǃ(f7M>V 1ѥKgu*:+G'b}"sRqdoYGY\9/ē#aQ@+M_ aYg  ݦcTxpQ6ulC ~m$z5yi!`uriqkxWWh*8^|o{G0dظO,\ LO#-54pc3 ,1{O8nU}[7"mՍ\] &2NcmwA D.2SaO?X">O3"R ;]ίZ:;I@H!l^3vDxj:<5qyo8np;!h} x8=D#)n>=m """|c QP!aYB+/A׆ Խ)Ls%-~][GfkCv[pӥ-PF@8Z= ~Ve„3: xofg8k.-O΃8H'4A7q~˙.|}̽j ~n@fЈY)Zu^Wŕ=B( 3 +7㧀غhR\~vE_Ǐ8v FШy;s%ۧ/q( IDAT3K-Bŵ- P揢xUF˳.՛( u@tHPi,n8/PM^b\+5--9Xԯ2/X!CLG(6dP_`ۖl{gcǎ!!!A yaU9*r2?.# """""@|\p \BX^4.t ;?Ԫx|ony 7A""""""""ADDDDDDDADDDDDDDtl@QбADDDDDDDADDDDDDDtl@QбADDDDDDDADDDDDDDtjWSM/.>q""""""* * HTDDDDDDD|  ۶lVZCa""""""xr15TfGUCDDDDDDTAAbЧU!| yq5רa""""""؀ܹ:&"""""*o """"""c """"""" :6 (؀ """"""c """"""" :6 (؀ """""" UDDUnN&%4)"" 2@ǂܹ')"rY[WU []["""Et$$$R۶m;6nڌstVܹuE|&ضcڶnNiV1 M!l>[iNfg@DB:}ӈ """"""" :6 (؀ """"""c """"""" :6 C$TX8ۓx/lsN ð*G}|Lb&&mo/o/֤m0MQAD@v|sDDmڵ Ů]m5{gGT7y|`4xrqׇKR˛csq,O8l@љ*,baڒlj8pA5Te$w.]o\< ;=@1c/kp+{{ߋzk\txXvrvo;+s#(BљBﰩxŘ4d=jhHY#^߻<nq0hy( Vu>=p8pk{VBFn\8t=(+ŌD:r͚8x6+{+x j?򣚠C;D?;7˳ylS*<7|r5vƑŗIbξ7=9]=8e G*|(q ! p a!quXXl ˓#'1:9IJQ`q/-`@RLkޘ[z1D.77W !'xX]?DOa0]Xh|,Wg.䏇?t0ׁ=qų3?0nL_z2<`Cʕ"8\p|q]@kBֲIX_<x?<8}L-nf5 L;1QX0Z)Oǀ:#P֡C0nx84m]+C}Ÿ#䨯z1 "*w!!q qog1a+}11ym{Ÿ]Vkh8۽Bz'*A.TP M)һ"!w&! $\TE%|'73{sγ3zV~k֍a_qmǯQkz}4n.E[I8-;$\]͐пU ZYEc<>oH`葜Z2װ5Ư1x]Xq*+'vFoB۾iRmp-Z.?qz9#?I;LkT;Z̿NA4_Mˆiԅa?myM#֭Orn[ټzQ*ؔD'rT5mN1U~!E# &7a'+ݟu F;uˉgC7`W 槥q1oƁ)a7f}lYYĖ18=/ͨU?7`xʭmUp7q%esꏝ⌓(t:,~>SwA!*҈WJ#ݜ쎓ٯhZ:vf;pZ1)8qdTdW!܈1 n\\%V ?Sӧ/6 X{ne%qAL_ MhOpP 5s֨ZWP}s)(%W-oňNiKQ UoOSMH`MNoR {JԢнNw?eUzhU4/bO麕LqT`mj]ЩL}!ѓޣn!'l(lųfEY٫ Gq\gvq/JGgVXCEͨ^YѸ{!.A\# ͧ,& _4^c'/%kYIDkؗpAr=pvMvwfTBBI'ͻZ&2/ݢJV3DGh"`ctPӭ[w%^#.vv\g^~ACe"gk$Ϗ}b1eҊ;FS"t\D GF1/ળ֦T!aLs\f C%""ʞf7<ܒSZ4!Mx~ðP8U G#5ҏ7ak$^\KWplQ鱨⎫jp1H ΓKKdyJy+Y2'4WױWH~FLsz5Ƭ@K|.ͳ of2cySp m 1nn.p+݂Ф`7Fߛ|1;0|Gw=FFo62d&}g<2Uk8~3U5$⧙cWBJatn_Rg1zA EPs룘ܷ:Nhu9dׇj\8KTBO.%@Iӓ:BXh W(BŒP< ?!&!iip͋c3YmUtSdW""eəPpu1WRX)TG\l)}!+{{*`-[vjoA% "޿Cʸ%!_;ͫ12|ճ86w%m=S .nT;a9Sbd0Ye^G3 G<$qʖ22j'D6Yk_8ՠi<@dNt_H H9BOaa̓N"{qtO7tbl{#.+DzwJ`rS8Ei1,9W;Z?6H0S{ݔbyI}3/T6,xaSF..'X4<] }Mο.*QSo&RN|6ݤ(鈚3L^scU\ =KݦZ QFQx} WOߠ1xlG;*)rĻ{Xx(Ÿ)yp,Z#ޡYցB<[Z%~qt o; _e!?K.1ˌBr{>3e>`@Cl٦ [r,Z=h޼lJHqӭ*'lOƢcoAWn>C1W7nğOfG6Y%?O$_0k\mpJ4::זo`= q.q3tHdx6PZ4qt)O*X9| 'o&F8b$v T_Эz1:=1z ]&JCI >S! _3&Mَ~♋¦ iP:%H IDATumT9Φ2!ĿH1+939fjwWj:k"cYLԌ! X{W-g Ro3yi@U_PHڍJgZrjQp7f3id;f}fN2LQ,'d]*0tLsj+C%_=euO~=˙[*eXREO786h0j&,΍ Ef:C{xi0D|m_Z@z00sFk5:ҢaB,JŧL1] ަSSw}gLvl^HZ{I3L!٧lR7$ϓnқ.իQzaܞPMjM@)(/H S՛dž{S׍ѿC#jTN,WH9:W vAbokZիMMG% eKӉiK4*千-*˷Y+~o,kϢWTh9sDn[j ?5fl]O4? @%|f!BHBiٶU5t6Tu=n?{4#~χv։ Hywb#O`a4-l@ ΧVXC{Y?؋CG^2ev+v7ǎ`Zߙ2h.]2Qk&1#(ځϾCXӖMSlbrϳr#XGyK&7#`A#ts"{f=[01*=wf0`bʲA#Wpk[AMEޙ57KmBK7 ?3TmHMG _Vvk=V)XkާU Ϡ5>8xWr]9Us6B!"7"W3^{X թ~}W, {>l])T [qlkѣ;VvxTwNxF@Q D3ϓM`K]yW^}Mj'1MR\2nyP`x@jދV8Pa ߻-#x vOQ{_ؼ5zRŀb[%jZezW<yN?01 y,PqquH=i9 ;agCA\x6ңg';*=C9Lj+vؤb牗c4Q uv}Շ~'R3`HjbrwzV"B!EPEq`Dcn٠ţٷ$Nn㠅a]2 #5uڧpv'&<,Q䊳iц)hp(|xU=Q# um x.B! WAvoծ'=!(i*Wpu6z?|\ݰ܅_wӲ􇄆ơ{'$}~,F..'X4<] }Mο&((Luq%8[xv (:++ĵM2w5͹A\5K0k@߳l~^T5k)+jaχxR/z[coRGuMhSz-#vInǨToPYt~Vr#*nz@M͞/'2oo+yI yxpVGmql8?aņ5t|ޒؙo~!{%K#_2g?d!Lȟ|jwkw2},w"|~{=3}qÌV̨}ds[e^?137s.Ҁg馼]3/Ǝ1\\̛?{}J?D's׶3kbƻ<-:*)V3c<hcު=3;?1TAcYN!~;;~nCӬhy&f\ٸL_ɇekufTWs:̓+?fCQ|ӿ3 p=z̠ѯo_ʗ/oY s7>3g|*ɋTyʕ䄓S d8nܼ͛y"""R^_oen2AA\3s!U#GC)]_wE~8$7t"nl֡h7&et΄O+y|#Q홻'X@:}?1:h7d5 UxH8I 3lnd4+kݮnMƲyVz5k 0va,]+Ł[35l۹]m>ΙVa4־57 |_߾̜5sYs9fΚE} > D=~tt4?3%/>>uJ`x1=ƘhD4x%*BFf|b< ;Ъ˫[A)e`Nՙu*`w6RZTmۑ2*N"J7K7»vJ%NG [/;5<> hWW@/ژ]=|Ԙ.vZ'_*MŦ-MRVeiѱnPҺk}M ߿#>mݰ6iy>E(}NpSzhU4/bO麕LqT`mj)s9kT\_+y]Ӿ9Eԫ\p/E_>Qq(ю R.O#>!ܫHUp3,;T'/:q4_kޮbZ[yf漢\Wy%]`oW)'O+_<|*a > 80"!"̇8X7{Ezprrp㉏dɒ;ا+B|B3 !_vKfѠ<䫮$7JUUptrLΡhM^eUU McždZN.|0ٵꆇkjC`0WgrWw\JTFxH8O.-W)O(0H7,dŲy8ba)zj g7WLՀ#N)0iZ*V]q5HEE58ZoEUtM² GJ7O7Ȕɳ/ gƨbM=掳FB‰ [LCoÇh:zwutx|߰Dk*jB׍eʓEג֕n*ΧMʕ+9k`֬ 8rʥV,"Ȕe!#Yjzt{;XYYe~Bu:῾[ypF!շ į)*5x((fЉٟꁫ7Maer3: N,>C ,R9!DغbM8,ñxޟЄwBOtP>^\u$fqiң(Oݗ#Ci[):A>@aLF=LJLc ڱ|vt}ZFu1*ou)\EU)sDGg|ylr8pƍOGQ|x=)D̃y.\ ͛i򢣣~jr2 cu`H~EϩM)x"'X=l{3U?A@絝ko4ZU䏿K"1{TZ!-dz9_ټ(! uGţ^s][ŜcB\Vv܊q+J$&$ NN]̭ m[x |{,D ~ܓ:vo3?Y/1oo(R^qY"5b~abt:ͨzGt-e݇^G-Q#*2(b-_:5ސ^a?{')Px=[ICő?p;~駣|x9f)ޓ*̥7]zy&镩JiMOV9?Ga#l֔لQrp:N KZ%1`%%l:B7a=X+e[7˅rmi Ogn@Muut]Q-W`|nDi\٤'㥻 'MQ)yeꅡ^ fUYRIDeJ[%ߛMiȨdSrψƍK' 4+7FPPիWpSwͿa3qbX9n ީ0uvm\&oqdלq|0ݑb ḛK0}gD]q(c\X3IKa.eAl'lj.85ڏ.BVǁ۶[fТy3ˬ{Jʖi:}ժZf m|:kX:uXf\-[lD;~"߭0 HL~{Sf6&I Fq⽞67MeRsb`t^ aߴ{[013o*=0(T >Xq>p'F5O}U{/bN߂]o6c/, IDAT~+JW~p~)!Ⅶ8|^)B;ngƋ9~27@2舢(=K٩xqlb j[v~ә2o|P*yXt-pR{qGscQQ׻3U֭IZx/lߨTr1ء_Ҡ  E5k j!]ۮ!G":w@<^}~}UL !BG˪1 vD.?ZeDst`gFG _$%s? @uMKccn&m.gT?_Sk7s^@ĺTTPqt7 jk: ve'ɧ77 [ή yGEe!,,*f'Kyv#FD6o%BJuJZ !r= @3̇;X۟/a1Yۙ>Ko *K|CRMR^FKT 7tkq #+w<ܼi?qZЉPu@#A(+'<J1x\4Ti_jmK>_0]_Saj3zᴜxH0988(JeqtLp7(B2i X B RX" ؤD$#e# 흶{tfJB!ċQB<'$!r,e^z&,*U4Oy*SuB!B1atZR3F…eB!B<$!ryo[DB!B<$!ryo?B!B" @3ais;yB!BIBHvGR%|E ԬY˗/WDa^S!B!?C"Dz7rxIpqJK!B!ĿC"Gt]GӴ4i0qpp 662777bbbHHHH$ND!B!?K"k[Fa)!5j޽{LJ([waQ}ǿ"HdžػƎ bQc=vI{%Fc(`Ė(*R&v?OlI|crvfV8AAA@L77ſCv7ɭ(*URJf@7 Bxlr"xtmiˌBKػ jWR>[jtQ{~L6s\AWSb92g$6]%A<ͥ}^1 H w7nM`vr,bDڭ[BGO;Jܖu$|’bJ:9J<ڻ|Vɏ3eQ*65SjY\<͑i.3_?uT&qDPKCt͡&7 c$<#JTU20o@?p Y93t3ᓥ<9ǒ]p̈́ޏ*D4EQ(YK1/j166~i   Gta#=:+Ӿn5[2peM[%2kP:ޭ, Z3&k;ܜqpm@7sv|:PÅZ1 6EIQthJ-'ܚaF}ґgo_>M sU- wl4{{})TҋꁫLmܞѯ7upjܛy~l#7ggfĿ'&old Q~'ǖc G&doC88{аO33׋)< qptɻ}W]! u0C}Q3SA((Ćnh oQc[BQчދ/O7\coWIB&rdzM ':"J< %/uqG,8ݕqX@!zK?n›YCݜ4@27MKoܽ|hk!319b[&z4váOևI1֊/iW?EW'A Pg K')C0w{ݴ'N7oyYڵu^I{,$|tZS eǽ9qdNdEcDS豔i59[KHg*yLO={Mm/m>U o_'-_~.:.!xlAQ_ ›X†İ@EXQڐS Mk773n8q~nñ#(@~Jf?LcAq kjp.fYpyNXǦT6k coI;c၃Tt3=L^CI'96=\(ąLc`f윌]^}R׬|p7+J\׃VRjUJ_>fLJYY֐?Y! PH84P)\8 Ad֫h=rM7vG6}uu{3vGt0 h=yz[TykQZ)T)#BtoׁTȸ55{ S-R/ݦۯ=) V:Sټ&epNH?Ia2x?բS\HiSGЭ=򵓜ӫ2Gg0`~4E}3r-%vDnߚ3tn03l crNFy3?ŨV#' AT-O? -T7G;{^ $_˗|򽔞xl§Esc+zԍش:0vMQƼu#)CEKT4nd\`[p4_uaIZ\zu1y0(T883%wJCB]yc'ZnEP *&+ `Vcou/Ce|ûӀ\LN~x(;,&;RD`X_êҐ2FIضQv#1dB_OxΘ "$|N:;B zU lY(m;N$ajW*%axd#rYZV'Q2ϒX݁J)Aݠ3KEQnsP[fXk\bdhk]*͐~ kĽ!᝽Ž1_]ʾFy>qڅ PҒHn#@2GeZIoN)T4jefD()(9 ٸ1YmD)y%,,PT@LL:5sւ'w^9C69gy2ٰa5)C8_ cei$=$YQDg;ӲTdd2=WoeHea"C=vڍx's?[..D$߭ X1-K3:`rV"oއ8yI")IkÓƹ-;g&'hs_i'0zE];,_ƣTP| ZI h[cm6$*Bg|kV/Klԕ=})c\ǪXt18_ʉnf#uQG+8 Q=I^a싈KO@c]$bt_6nMtIʚvyE&OՀ9) $g}w,|WK[!㢉U02QѨ_mQP&c̾穀/zOf/&$ VF_~N EZ M C6$'ys\<K<¦}t^V~#GS^UoLsfr:tk&$6쨫HUFf鈡 Ylo*QNe<ξ(|FVsG%`afHV re!ЭoyE 7 !9T1-@̥PZ7!(_A2Yčd4O9v'AUϘ=pQ* wx#:nVt{:OecS2/bDd29_X[=T77%kD(aϟO *L1/י uD(ouoK]҇&Nhvd@CRe=u;2±7 gR,˭KT*/=0li[3H}dܾ|(f!Nq1޿#v4KAZ47/ym`@ݨy|8]qn3 &C? {6+MF_ڨd_w譧+>ce=!dC{>KTMіc ~~7;P p|bұ#k9Ӡ,B#߲Z*L݆3!hcZԬێ O:8z#QJ}h~8)5Dy u޻][.P/Ne Qna7޶/h%_v]i^t?Ǿq]ouIdrĞdafףO sUɦmp{Qt^Pa2 c<]]qi؉7]%A.Rޱ#WcON='Hg/ɭܫҴ9_\]g)*2EkrX.zYK|eܓyKSMlG8mdd*7q[nVdIʗ+BZNaRzu>sڵt?jG)?qYa@ O3 6?[E*XXWҴ\+yZo1;wO&r# r1\5V 6cxSa.+pPVAxeJp} .yKK*c_%UFQLA6ZMjjcC)))tgmHO? T>=8;U>QRKة,{an $ʾIc0aU%+6ޡ9a[TAx'D[xb7o^ (ÇspH], +a! |c{ @ʊ%Kfmmﲭ MAAA#"!I>AAAGQAAAAAAA;AAAAAAA;AAAAAAA;AAAAAAA;phz9ա{V-q^p$]7?|%OGAx-ueX, ~cnû,X{ @s{O֢o+{ڲ|vYng$ ¤r~Sc 6sGR/|}jށS P(͑}Dg7^һ6mEO?&L2)?WLJ6370ݽ>x6oSAgX7%Nk{{\fЎımg{t"CK#Wj:zа.9sřΞ48$Of8;:;_&z|Vc=Gӡ;8y+<+/_ǛzsEv2c@wš ĥdZ>ͺyDĢ~֡KڍZ|>SVⳏ:(ol7Gjͨm^A>Mz8|5aSs<1ߺ,͡Qj2:Y6p.gRm ނ ?L@Rgn=DoUm1mXg/!˻QA U|zdkAD+SxwItZʉX+F=oTBÎrl`LOQ Qɰj̷2I L͏0{>BCjuN "4,5d޼<> wK0{VfiPQNL_$@ï#c}?{~if8%dwI Ţ>Lټࡵ/O&oˁeɄ_NnAc(~s-+BL5·D XGi[˯Cpz`~ sfϜ60$+]KޙvcVwz6@ gAt=f'lT|'"0ˋ0RUF}:ޑgWJa$RsT$)jלļFd@FQI;sYm[ݠ\HT0_pM$s|A 굤[ھ[Y's9"7+ߴ -<ؽ6Y vdAЁ<ŘBK?!-h"dBp gu {r2z8ar "$|N>͌04Ȫ4ЍSO$ݻG<K=(烽1jK#eNtvyLTa*b7/yroP%LCqiG[(Z˄&o7Źs jqq @*4kVpnhT9dM)),ii_4a1- HGOYu -&eK>'$_>-;;b$>V2.o@+G;m l$eU֣OveϽQ1uQYoX G}R®!ͫ^#xwfOִ{ؗꁿSQjCX*qav$-6qj-H8ȌGX>5&CR#?MzAWE&.:m1HqmLaZ.ϸj V@s"X`eا2rr)Ǚδl9=% }WÖ%0J+w>31n=JAT$KƠn\ f`]|%Vog|蒅5;Pe_OTf{i2 .%@mLzdYV}$&&9 v;su$IH&1V9YML1U}ffeȎϲm]KX?j52y\p{W|$1XWQ9O"ⲂE^87@I%, >ͽdj3>TI0UZai3M c9E4ƍHK]T2w&^֗izk[.E ^IOP.Hpt]^_tJ)Ėn m)*e^T/=H(vPyD6l2jjӼ> ~{ .]1SƶOp"]W+7JW3f]x; u 9|DV Cl؛KӦvMtIR!@QmgOx`]וmӒ,Gۈl.1ݰ5P5TYG&FBYcF{vag'\}3n&J21P[C4Y \G |C6rhcZV+HK:nlCX>C ۙs95)ܲ{y"F< JnJ"O (ɷޓ94HXԥ &HGd q?&r3Ӑm9Sέ\+Q.CR'X4;g2!)2f@=._z3 `hCҶgH05(KL 8|K/~FԪW캗 dZ^+B8 7cr{AIi:mv23$’̵l-;+yp $=G~ңB#̎cnH~N qhMƮlLgW> ʿČ'$}>$4Dx [ \\S9*ИE+8BF|o /|?)?{_p~J´xqG(sL_w!N=-}BReUbY|85X d_pJ|iZ 愢kLNR&~g?kʠ |90g 4ķ~A>Nr7Ԕߓy͟-o bcGeP_pe/^Yu;֕KjC>+nv+ٵa:G/~we W3pi2k3vZ'Y 8TzQP p|bұ#k9Ӡ,B#3 >{tөn0vRB2.pѢ![wSH*e7hu˟m²wLmqO%ux~?"kOFńie'CzoyyA Himg飲_@]}E?BSԋ]BF8zѴ<<'J4IykTs} ohS<ݽ p/FN{E.S,ڴ}`7Ɵ@#ͼ8@glE]Ya@Y*?u՝meX< ‡Es{OԢob*m|=&iW-ϯXz7F:ѩuKz#޼xy>Oզ4Trof-ɆM+pCVx'ԅf\Iq@_coIq_]cB]+rJӦ|s]wZEf0RuEse-9_kqON-O!R7vg'g<bU2~'2 U)]槹ߒ8d ɦl#9AY?3+0$4T7)ywN9nG@-xa\?r$+;5h/xOԛG؁Ԩ^]7Ϝv-dC S_bd_My!)2|CZf}ߒٶ?[ /o/'Eynw7[/f1@F֢usgv}}YeJVn//Z9u6v\ibŰ8XkNrVlgis$d]Ȍwo߉m&LJXzeAw?41sQHɅ7NɬߓQTvf?trUN\yD p;!Agp?1IF,WUUڊHo eܜ6_|&0 VNOsYt$m{v6ߠuFA| ma|dDޮl)U=gQ51gACj#Eai; "8_`J`Kﺬ2Z9 녛PQ i5.PnFkFi#]Fqt'jү1hꠖ<5;Ȧ-GLw|degzr¸q_R뿜+k `lh11 Q<)3=+:P8$L&BHu@hK-Vky(&5nɏ1˟9= Nvn28;KEZGW7*s_L7m4 zѼv$ fc3knr0DP3Q;8IE73="3b}nOU۬׉sypU&&ڊ26S^)h*&qfƙcvc&Cap2cWChˌWlɂ-P)Zeνm; )$r{p 5u9l$P7.ڄ&kAX>H7C<߳;{dJqtM$kMoatӅcʇU,jÓٰ+ם#F;ӓ=lZ=B P 9WʸhܿD535*ÒjYǡ~ƚƃaoa  6m;ƝD ӢϜIYjaɬ:.U(E8§PB$   {Dϙڂj1b_5f {-Etq&3MD4 dnE>/zK%"@QAgOx`g--&Z/@xeoj#z>>ɢ!7=0ÖqQTibkԟg7   C0>W9z[I'!(v]Ǫ|9,%MIiuI:aD<|KRe= )lg3psVNfM^3o '7_9lB~x h}+lLFz:ʳ8R,)S0F*H;;N&go'74:<րȑl3a 1   R4^5$+ZFa_<@ @{4@NBt;'* AfR!:Si[XDR;-U{Sƃ;2z:饭rV6%8sc&AAA{zr+4mz9um/ )*2GkrX.c]/kZ]{t2o ɂF79ۈILp0M-m^CN9n 7Qn N9CZɂ 'N17? 2 6? E*XXWҴu_+Xrim  AAAA;AAAAAAA;AAAA>kh]?;޼?N-I}A Z5ήRph\S-F7K@!~# x /%_{1IHەDZM^@7'-}ؚgC1>=zpeJF/KhP  [5d T*"plҝo ˤt"%޲]*6^9Ac9l#&n:ڽꗑƃ2V3=K*6Y1Ikr7Ő5[18XJ r.h 7r12UR~9m+cg|JIlz |K}[X_ ȫI  =tr/n1?t˾ʄ2^T4'T]g8m&eym˰(NaMMet A@7s NUe8'|Y;~?jժ0KI\3/9„k&|ӵ)89۷T8-=?u3 hfnu6 9D;$5KE㻙ع]Y}/G4w{#>O*<ұ)KĽ0:c,з5wA:gķmp5O$,ZFeR{R)z1胛}w=CA] AC*"xԭ~d@|DBOʴ 9u"iqq~F_m8w. "snc&x)Y)Q&8f͐a-8Ä DY9I 99g2kCaLkшIz6=bvr/^7N!52@-Gx'U%c v2htX` YaAv?n1eN>x*]*4|+!;PDwkAFNљ,{mk$Ҹx.UetPaۧ9!.T\Ƥ ۰ݬ֏FefjH~=Gnjd-ݫ' IDATģ301>Ӷ1U1vZ- @/ #x| nΞ\ "c):d{v1n,aYoV e@vLc9mZ!a_Ʊ1d?GӿfЁ|=F񫙱;o[47X9m/,%$d(P:5Pt<-OʘFJ~ȅ OEi(nMždQ,Uf%(aztT.r>_TȗKO4n^bUMC% |0OzbiWfFeXV-k8t?^>=:MIp-t{[VC'l@P}<BΑ<щ[V:o^ R/{7s8 q~$*aٗ5\*Uݺf0`R ¡B-Uߎ<*54>EȉD2nc__]xAcTRU;Wڜ]:ss-,/VԩH.4;6]Тر+T/2,Af5N.X"'ٶ$Ive)jpd^$uB@? ;w)Aݠ3KEQns0נ 367EB¬ QayQ)Z[4iY 9X qzڳ HtJ^3\ZRHʸ n 4o(il95 `ldʈ*eeu*%s?VaҁolH!9EC7[T,E'~p7-{|*H>"&J'ZX`ͣ>rqc_6ԧ_#PwrΏȧN9DweS]E1qԯ،f{M'= ,yVTzʮ-9[#!q4, ij*%%&θ r1~*#<_7$'Os+,oУR_YޡƓ?ÙmOz%/bIs?k[tdF/aR̚oes82/eTf߉E2J"SlDq3" 'X[ʤJUeFjI&M~s$[?C,324{_5,go'Y=]JBRE%M dE#Axh92@NkH SfR}GQqw7={S@QzSP` QQkEl AE"J'{vٰI ^cãF q IM3,v'7"a; Nx^ܾb } }ͻݒp4 vpKX\T)|[8}FaSyunMXD8mCv l5rs^ Ҁi$:B.Nx -8DxM;4)tbn[ovvʌD2 Ni~1`)i'G,wg$;#dwIof_}']9BD!/Ew2IOO'#+o'syild##= /|R4BD\~֟DF5vDm/_λc_|z_Wpbn~ͪ[S3Q6vFoxWGc9Sfr]H̱X #Eum]sܴ7:Q ?λi/{).fNl,Q\t<rL;zgs댧ɘ0!#ɼ}_G-zuva:Mȴ;8 7ȧ?<.D ){@uq^G> NW3NuT?#?1o]l7#Xu^^4ՆS_nŀǟfx#.cu\1|ivۀm}O!*2Ч+Hb]dC K ˘&lb%γ_Mw2iD/RT?w 㟸:vHfK2ã>^kǒًٺ.bʠٟ3SPR5-劋e~׷1o5JݣQvOvۣ7yλ刄ĤɔRʣ78Yu|=fi/?kٰq#=u~85g=*g8wSK+xREU]۶p6n$C{k5Ewșau<uT.+as,eywk[(;=f^=^:o3yun`MH0H*/mʈ+Ϯ!"R%MDT쟁ED<#n1Lq鸩 EDDD HG]ƜUYÕWX|:+E|""% H5TԫC@D^*"""""")q`~)ְS"+ 1ީJB Sf_r$%!DDDDDD2i_BͽIVW֐T % JaݮkIK0DDDDDDDiH%˯~#5^*RsVX QBDDDDuoԭS*3k6nт kTCDDDDJMMUAQi TifVmԥy֪S֐6L?K#hlV=ڛ5񨖔Č!tbw֊41M93P)!JÙtN綠Y1K#{1;d޷^Ã5Yapْ@w3kT?z 9-}5"""""UR!܉33RA*Y_Sf;ѷf˙z/lSа weiNCէ)g ҡ-;cWSoRqlMmLI:WSĔ˞뻳Y;{\=nÆofċ_$Ҍpοj&汞c2I^rtU_gWY߻h,QkwB >}輫(2V?F&.OLj>;6#J8'2^R]S!s'fOeٕ uxm$uT%[S})<1 nIПQX'lC9r773fgǼ\;mz|t7-vv嚉7$-/quywc1I^6kzcq׌gݙ}@.b,t?]T.g}oϟ;/<1;,L~}7Om g9Dqy/ƭE7U!""Rt9](!lKʵD*1'_paB/1W@/g]؅`Z:Q{-բ3&w/F؁=]qmt?w..=HY˲߹yy!,b1!++R=6: ~ i8wH,g &G""U"GP)!u-Ušu\`8pn,fz?WTؽy)le^'vp2ؿɅ'bG"^;a޴o^ƚntv9?ֻ?ǓX(|8j$L > #',rYLܡt1rԦ}ډ틈HyQB iT5T^= <]l؊CY9u7׿ [aPj}i0`FDLu=y`?mt\pC9 {ivk|p{S""RnLt ^ UJ!yfL"nGH jLAqr_mqԣYl\2h5F}to5{怙/_xcn\|?_?瀑I9bqE|8 YGرy'Iz΋iس{S&O̵/oi:!&Em} GY R񔀐B3dq v3#aϭE2n̿bCO>ةqm;hȈS{pztÅq5sGd Yp_Ϝ^R% )Dʰ1xO Ʊ<6+p4~rZ2b{\s=G+؉y`skcyq}GQ=ۦm />4^rf[+DD*ibKH7Lۋs!`bbMŽ_&fݍNwL˖Vԡ}:i۳Kgz7OxKSB 9cd bkHDDDve_woN^@jF9e ܳt sWogݿl:vҰm<0 3]P#}ZCf\3 Ű@&As=9,u/)^yx_SѯCx`hkl&)`>beÉ\3΢ =[c̅'6 7v>=fmISf,bݞT `GSn{qmnchrь#v :o|ÎTa2 f2ޜ 4ro^{f\3q|6=Z_^VΛKIYFoQu9ΰO&R}`k<3v?̾ao 2f7 -\,cSB 9i)\zIْ~ylHf[?ͣkqAucs[ҸiI?͗E<O3ny+p "rd睙Żcnc|4)#_=MS^cm'鷋{U-Ƨ1ƯੑYw>T q\^s7Ov |>FMsoP'1f.{?1B{}t cs'`\”H_`#w|һ&if0Ix9D,{${O+3{Mj ŶQ8Z6wք+tx&ԚϴH/3bƇ`˫p4w ըv |a&{>|g/WѴpn+z,?+o?;Y0za&ыLO @ϟ:5 nF|j7;΍E76|}w̡e1㾝Tqg+b׈ضn5ێy Ap/Ҽ{Gþ!4B fy!"""RǡHyq41ms 2WcL^-[޲vvՂfn8 @Xo&6 [`lyٰcb&qy޵%9Y1䘮5Qqm '"̽M&6L'f[O2rO4Qzuy1'!{r;-଴4 7D44%/ygf`;jJ0G)4<39dŧ.]~Af,^/Ɇ{av:[iFaБd~x2wH01.&:f\&cXcgb>0vUt)dSB uyYmcs˷2 Z^u{ix|2IJJ|6JGXa]o5I^QL[S jz;'.K{$lrϺ)XWG7nlld.L(mBM7LǾyɀqo,ij8Ʊ=Dq#R]!` "4;Lx&I?SS 8)ωֺb)ĨWvyYmT5CCĎU7Nwӄ Lxb߅DR 7o}CK!˸X;rtyLW+ib0y;/ORZbDًXk LjLr&džp=yKQXEeܤt}+& ?"c3Mfd?57lԆk=yk4x-m~~3% |/̈́jG3y~j^:Nn0zr$&_'/V{-ֽ+Z4_͌/eOWP=.f,O7 yF#X1b=[~&=p߹ĺ8:vA O9vLQs=== ^ļ pxo({yݓ({Mzw9"!1i22:,~bk hj_Z 'QQu.hdk PKשaFztj HJ;p"VvmZlظi IDATa9A_}5]tEHk֬UԪФ4֭['KXhCa 7orȳ97<μr.(y1 YYֹ6VF@H!3<,6DDDDDDPB h<JLj/rf+SB qfy!""""""RHEGцJ@H!1Ҡ<,6DDDD}9J*O )~MyYm(ηM Y8KË {@B )Ĩqw_a QQjCq+I%!&=f!4)_ՃcΡi""rQz=T}J@H!.K5~&ejCNGv>辰OB J>WN}["""""RJvk@,"b%M5jBCyOr:fգ=ŏ6r;EsA+oïS/+H۴KDrfݗӽS \^gh,{o=JGMtO.Tݬz+u& my9^yb$w<G V^joI- {SC$_͓a9_揺sxyz!""R [?mvk%88MOTURHEou5n#]v!'FX*֮1a_k hx|sK/N|ۛg:UW,-7H7ݐwa% Xs,y>7ԛ66ܟYi<] W^с9VqnE^""""P=RSSU"g___4 *SB ?,|cm؄ 5AN77/vlG=Ǟ+˾ࠁl_ }qGIAћL:j$L >sOB`-jZnHI|HV F6F @ 9AAA:ӂRHyGc Syoa ;5|#?WsƁ4B] 8-v\7xk%40ce^Th\DDDDDtJ)z×u3-b Y[Rb%8eٿּ9fƿ,}v{XIof_}:KY«?In.~Q3RyLR} 7^Oo1i] ʮ?d@?/p4dԩ=8a=:[YบO#:ln4v`H hr\l|99?o ]:]6W~>眈Srqyϲur'AEp]5Q(';QʛZS  ?"""""B?)"U#~GsCUGsMClѢ9sZE:qXd|i}F5TYDDDD % DWN}[ErZr^M6oֽn TbLDNK]3heуֹ3.ʘ6ln ͭ}2Mb|ևQ٬zw_Ad7g̰tԉn0t08uޗmҶZזQйc cuGp_4R6+ނ׾^uS`,v}q + <ӟ_<_ֺ]˷o]L6Sub jr.^eU|t|\i'x>^i}RX2ʪ/bcG<5lw=]њȀ|i0m_|YjUԂ//k6n})|z m` YN?{ǻ̀WKЃھ`kE="uV8311;ܱ,.o9i(^fx7b&ZaةѠ> o{1)#s?7uNlQQTHDG a`rm.^Ȉ+;`81LpJ@iVj}Xk\`#,"߶XD:y[nÏq\uۗO{9t -9(vRf kT[b[ 9qJ@Fr2d}6ռ4Ǻxš>K.]h$YU}+ݛس}'9[?kVka_[C'nsNְH)q:2MSrXk C~&箖~\PN6L9$H`AjLlh04v ᕈL"5O0'r?zT.o0P oMea/w𡱯#Lߘ/ٮ5qWk:BNf.C݋ۺŽlj5ffOe~V_rh*j2mU_$#eeL{?''p^?1Xc>KࡽvOSɺ-,J4ys"þLfsUY|5L`ש#R3kxje͟t}䃈ȱX;4me#KLwdd\ZLۄLhKeUGc`f~ 1>-&b\~7 cjrAF9e2ӛ.~_vf)5}6{toEY3sl8$3;&al#Mܿ+""""""K0Ns~6|$k48qEZAPL7׵o3ܣɒ 0 =N$ţ uRg'ğ}vr]*f+6cVB-l&ytNLEDDDDDDJK әA$2 tPN Ϳ\^J\m??eun9z G=) p&ak a,ټ}d$ چqe򏗈FgfR%6B|qA7d#)kj;}7dǝ90Mgݜ@iHLsM+b=uT6^*MJ4Hʆ!q%ԞN`gzEX0 vFt93Lx@5L$%3yLȻŴl*ڱ:Ġ`6ՍLč I̋j=2 RsXߠcs?ٸeϱ,cc:/EI<33xs7Ccg{Ե.ÿs{ne|y)Bi-jbaw:{EvG=oW9w#&SJ+3!JiQ(k8u|=fi y8 MN Rweg^9ׅӣl_Zb&7ϲέ4BD rssjLeOfM .>FVyoDDDHy3!*JN}v5mFPP:rQU^&""eJFgra~J7"""0ML󘗻ɩRQV>۩c.""e"""""""Rᔀ)}XJ\,#O]DDB pH:O}X5DDD) Un,#'Wi4Hq2PBDDDDDDD*.) J3e;v0}t&<,j9鍲q) % N7֐Hg I%>:֭Gf^a<)wC>rdW7 vfsL$uܶ۹;ILL;䅹s+]سa'Z{ 'tGDDLCD,N7fmNx'9 8g(b[x\٫s|C(yOǾI%{s\1d,Sg9))ɲ'޺1ԉ.{5,ϔێ e}>᳟9TZ>)2%;CS-׺dvd 9Z[."")~Blfsy$&/WQԽMGlv&&t=vx;n`j_j nkeujm=ƍqyG;gҞLLL|:㓩2sHw /?$ޘEwSMӵN8(|rgE^ Θ^k^-͆n/6۳Kgz7v%r|@y9Ts#`ӗ^;hyqt:tn,c<˟y N`Zl"/s$1Y~s/X_Dr9 gƤ5h:թ8a&sG>gy|= ;^K榅 u>u.z\:D&ȖS~|a,im=z4s/]؛y˗Q,(͛FݸsM:HI1}B~ؓwdz;TǎAw/2UlK&cx ;NKy1o}c&#?ۋ7/FW1 AIx>=1?eLs7e0v7@\B锦OJLs8p8y= "~Ͽ-3z]tJfR}h7l0_S3mwץůc5p `^?w !t>}M䔛8\nm1Bc5qngq }i(q\wS~Ds/}\nqh۶-!!!}y7kf}X i\|# &<\<|wEXgvBwd㯲x|2"ywC2M=̂ϗLoWuI1e|y.y3אbk}G9\zVw0>\X+y/b]?I>)'bbJ5s'|;ϼ_-1ɶ,?}Æ~pXt^JѯL_|Y}y{":vJDD#D}c$L~G'&س9!]rYAرz^wڅ`ϓKMa1vT+dU{gصm sWhF ?zo%˷bDzw^ b͸rُmv.nz(?ʯ+.ڕ.]ʧnF]5@nUqQFVmH|%Q0^hG;|8 gLlKeՒ~#6 =+ɱ u/b wTW}{J;^{>*X"vDjͷ;7#m^K9Ekq-Mp [ ͻw=;y/)9 0_;/uxnym4=޽s7\a⺖}aM]089N#}ޏ4/\v\mӵl^W<뱦ipHOpBlȍpf daĤcڏ"Tٶ};FfS~+Ϙάhִ1q34O\BY泙qY6bR!{r;qf;8+- Àm[4v[ z &6"?o=wmNH$f:9\LW;Gfb c{a`fCy)U:+ʱ41w}Wi-059`:1 109z ]q,_[c-0_׾ݎpyJ)""U͗"<)q8س<'Ni\wo~nN4LI$uL2DMɚ=8$dTHO#t] ,+7~= ]`w}7gɓuV~-f*ȇFMyu弄V.+t xp3VÞ3=w\l"\xBZ=d \~3I9=JKW]񯟒c~-vWۙ5""RUDDS  '6;)>q;ak/f5m'|w ?9Iݨl޴u{?1Q6b,!ް4ț/aoKXg)JLbb"111<ĽxᷘsW볲td;4U~+o$h* IDAT̛ RybcdP_=ZDDt!"RF]{ 1lh5:?5W@3{= d~F_8\?Y=12aNPtOyoǽ- u ‰ Yޜ9õW 7c{EO #o xrĝ')F@\1fM%GqbJ+WһgO6g.e\۟.6o^'fBd_MJg܇ra#y?F?Ӕ1p۪<}͵n }ۯ'bUīPX}W>ɾ4♻;1צ@n8/^ןy.gҼ[J7\8m|JSCG\DDB 9 9ƙ,3~CDDDDDDD*""e![i4U>)2RtED t H:O}X5DDD)Tn,#'Wi4HqPBDDDDDDD*.Ңe+kR{֐HDEհV)v0. ka~J7"""QBD Z}6۶mV)D&V>\oWiFDD8J@Hx|^=W{V>u#>pvk$TZlIjjJ*ooQU^(!ǥz?5\q?U".((Hȫ8aդ~ZRG>8M"JdEȐ!{WU{ԪQEZU5kV;TkS) 2 q%(}^%9>y9\_|}|޹9+B!}%!B!Bl'= Ŀjh(K-#ܽ{B Bv(];B!B$!ިdM+Wb0˻y7ob5nՊ_ 2B!B!MoLrr2wΑGh4nՒV-ZRtJoWCYz+W˹~:̖ B!Bdƌ GޞE?-`ȑTPSSSLMMP֤"hNafMӌy%bw( $`TT3 |8eGkެ$cO>FY.{JV}?)3ShuwLsS:4ܕUlGa}/FLʰb*Z⏊=DꯔS:ؽ+B%;Fai݊˖q޽څ ۵aBaJ%z41u NmQ >}5.wPrELLj c)4"t\>Ƀ lnCʹm)ӃGnI5oϻriFzؐrVM{N "h(JR%ΰj: '!:"PT)Fɯ\8{ gkp0GBhQI<`xE_4Z DZ3#_,^^8M7Ҟ 7OGSؼh u"ʣޱ^^>#n>>t(Fڹ4"ȩh6}[mٱtOJ0DlдŶ]YǞƲ)egiK5)ݨn!=obӌY?*'`|O˂/=S{ajB1oʄ4Spvf D!dr-*mF7LYAd^žMS7sΒhL%.d+ aYهG&1cW,**1;'2xvsw F;eIB!KpBȭNv'uvVqBB!T_pۮRA] **Qsh3-D 9v)iGG07{GGE8+յ ĩ*Qvrftȏ 94}:Tmp&|S-6;ɮɹD+ s2 Zo;N^4x2ˬl*%5y4ŧKs:K]__uNj/tH WwjuGhȷRR67ŊYv]BonGR՝gKp;P%ƼM8w/Wڕ@)GX*`P*wo!ՠ-h,(בF#UB!S!ɨ1c1z3Hd!o)ޛ3Y Z{dG@Td;lӣ $L Qp֍I]]Ξ+Qã[򻡪#c֯M (,ߒgK4'N_/0Z((RŠIF"t>>Fcp"Kʹy50tLk^0uXciNR}:浱Lw5 ;JG&! v! d3mzs]# 9vO`Հ'+ѹTmh !hv}^l3B$!^ɕ(["PѨ)mB4x4pbv&Sg<5  (*xlSV&>kGbqf*{0@C^ܨQD =NmjkcMjYCslFV445(QM%qy믄)0&_|8L ˨12:z0N-{r}۷<uS4ON?| 66Y`g}Y BQ4r.5ѱF&󀐒Z"QOISbB!KB!o< 7pKIN 6usCB҃^vr^{;5G*ʖ ' @ʀZ^TEG#wwrưm/gz5 !Wĸ+Ë"L̩+),~WںLݳG4׆/tCxE=z}ˀ!UU" XQ\ iH2yț>WBPQQ "d"N>HLO-<0M}u7v^ !xKIBzךjm 8 }׌.t{9]~o:֡KMϓKt;q~_4.oj7%rt ^@gZn{z d߱_η+t]};fk!-p9ƨ,5K$`]> ָɆB!aȄ&mҘjȨݩif\F_ B[iw2C@c3stmO*}-\!Krj;~9Fyۮrx{wxP Ukјax߭#Yύ-kL,5kg7/M,wϥ09 f};㸅Bwvk&' hNMt2[7yjV7W?㇣Q)ugبΡWs_\3~8޽\?nF77jb3j{J7ʵlP;uiP-n,]|E~=R:-'}ƚmvM߭qV{y&Osz>NLj=T_bijaG,:274u2'M|  } />CaBw|plH[֋9iAtj+73>RO,>^^8M7 s?q AX{6pvT| OC!fjNn^wpCwG;1ؑSΫN0\th:{F-|"iQu7ݕ-ӾG.lP'xR #z;~mص{*TUAZ6Mz1Px8TH;8.[65mQUw^_J7??ZO[ʚ[Yy7uOtٸ9 &n$=-s;x.I\:Mz2u` O lST݈[bOCfm|~F$Oi8ǝui3[D>,:% M85c/9?I$Ƨޅ뀁s.7ce\Lԝ5Oi?;#Gv27-`(Џ5{wqG7,֓kh8cSϟ*f*'wn4'g,T_ `Ŵi2f}jXs;|seX;u17ڎY; ޏإ3Xw$p/1‡wgDbմ(Ad^žMS7sΒJ\ WٳELbƮXTT"_ƾՌsƮS"T k{J9yH0O&٢m$x$x*}g7yC2o|5gxC پ4U(W =~*OX mf-/+,}qV=׶lNx@NNm9|=+'R:crAB&9:Ԁ `@~ۼaPC|3iaTÝuLXӜY)墶2r4g렑+K=p'Aj+hlצ;9 x;VRp gN߾[sz/\-*ْ6VR6xz#[uhhd 'G&Y}:_oǑ3;z-nf=l9X ag f-`[-f|*!yߟ[2݋Z ~ :h>{م©q5n?챧Q`iC9@ҠQ.l5gvUqgi0#GnX9ͬ/4[W`h>ǎt>wCyS0>B /.X)>;_^M>+1mEP![Oo[tغ=;QZ \Thݝ@eḾKTւƒ޵(vOrҦ35&'|)v;zKн&`Z-=UUw&/ \u;tFaESŢAB|?{8>Vo&$G&S wĵDnL`UڕvQ<0!ؚ 0ss@ IDAT3Cw-w@< 4iH޽\M?C@q,0ugeQyʩ=A-hrPn;SQѵ2 hqu-CrD5O;Ӵ%JR.t/ooaUgؼ vAwf k+ /AZ5RҥfrZc/~s,>]Rؘ{]Saڔl![{eٜ((ꅳ}nbKeo7$?L?ގF{Y,7f<ڽӣ^rhsmIG%cWPm^)0{Z=hj^2OJ}+F ("2Pw3 #WsY6nGT˫Ec^߽͝+i&h;SPr}W_4w[Jޭ+ފ cuٱ2oOⳁ"G&!%7Ŋ[q5ܞrRDH@@~8|S ]@|l8e7hY:' &O<a9k}[9^ % V?pk>ez~L*Ҥ&`6uk)R @K jXܿ̓_V!x^T!RdM) w=풸r3bE> Ϟ)Vxv!! GlCr"'Lډ?ICZODn^o%TBC~Scnas@Xg\GR}釗QzDɃug{'_yb DEDs.=[CXEG,F~Q˥|js5f+k-{o8Gf_c\?4645ۮӥ[[G׃je)6JNHƾ :Oņ|֩hjrI-UU^B7N"{ha7l6g Mm^XbӛOO}IP^Nx. \LVr/)aاNhll5j5YUB LLC`B(3Lj:4e~Ms^B%3 rh_~)1K`lXH~ lQ5xI^[h=⸴b9;%*u93px䠺]?4gs#_t X:N/b[.&ǹ>B(8CSΦeϲ_}!s6p"mE[2g'&ͅH'Ñ%ND%+{jW~Rly@}r ?h9s%4U7`hto:'zt=FPI8q)efCaz D^=dT)Zy$qQYw8A ?{x x)[S]R꤂/R|E@}rϿ$`%|%X=`HK~fzhr`kgMcqF~О">W *ϕRߎlۛ:=._M7Da}1@IZ{Z7oqjijx ,Çy6jfmS1s9*4XV#&sh%'˗VL^ -J^s q. sݦ9=:"Og>[*}'(8 E轧r}J/\\"ǝyB!XҾ/qV*꟬ʟNcL|ٴ5]{gA}?pӘN[/r6R{Lg˴r}|-ˆulg0 9]0/_Z&ҭ^{gzV8mi>Yiݾ-q|6ioE|H~fT6aU.1=z OKiYٗ:u3hwIڤ|kKҤG3t˺Т]G:<})3An2 ^=JnL{Gƫvm?bԺKY7]( 2D@tb;Sğ[J&uYA:>^=V6p~D3<ۏkm_:d.#SRݢ4jњV=CY7% gCk9Qݵ'si-ÿw L{5X>N2i3ha1tC.ջnd4̓{A3U"[{XӅZM0ij&>Fͺ=ؒcC. ( ;=eB-ߵ2fKn<چ/i銓{}4lSؑQ $0'Q\nկ5Ź6ASm4zTz;A)Ғo'+5q OP_v}RrAL;Bx=3*eҖ_iwJ&kH黜a$rK!exeڲI+iic}+ ܕ|Bu>|}Ђ =k8I6F#'O٩q6ytHEcS8YG~moϏ'B!՞}cq^8_a7` :RF6&-g;-?Kݳ!aYaYMMKh+Me4X!u*q9{7>e̼.Wq¶*UgB!?U9 !bڴ\ OĠ1źT>וJ+B!6X!|8CwhgV7NB!sX!B!NB!B!vB!B!DB!B! B69sZ8Y! #qxȯ`!xmʗ+ǥKYB![Μ9)_qxHB!k( +V0NB!B`!B!"IB!B!NB!B!vB!B!DB!B! B!B$!B!Blgb Bd'Nogo%biaAeȝ'qB!"BFv, 8K\ze˒+W.l!B%dB7*>>^rpp'ҫF!xI!oq)!'= B!BWݿ˗P\Y (`TB";HB!~Gzx6n\z`F 6 J!xIBqcǽ{T"_WGQbEݻg|B!Bw o{>TX?/&Ӻm;_ۻ !{HyZ-^;QB!Oz@7*mIV-[LMMiղErƲBDnD+m0@w)MHqοB}oF9ѽ'/\ c[B޳WOW޹(B (Q?8|Xݑ;]~iY!=i:CVϕ]q'nOq7_րki؆kc1lIewH(#LnHeWx\ac9(ԋ>څMe Zκgmju[ $|mO<,;YO@N^-Gc%BF4!֬]Kv?~[ߟ_w^c]DFFf(-j:S<'cR:i;rmP%"Sm'YKj8Brb :6 FݘAx]vNISxxPgx1* nGƻa;|$puxGS 2p{ [`ިͿoШ! hIw֓&x덄>PWVօ`րvթstBmD]/O˜Ϻt} 녛gC:$wV}OI͢m +Lb(`OL 9Iׇa4GΌX~X&q`N5?f4kO]mF4sIk'8c@U )LKU eH x,qt*bxĉK |i) Cw57-Gös2޼>׸#V\&QUQ'\ ݛ/Og睤㽽O}Ͼ?YSo[EA)/n꾂{z5;gEz7 }zn/`.'? [r JQfiK>xtdت<6,W'OҧoΞ=B^ٳۇ'O'!'PlA9~DzVŭV-5ygbbb 7mCzT|>w\zŋB!~BvΟYVK-س3QÀ,yQ=;ChղZ]w +WcǦ/ m\M9} ww"ժMs{9DTrB(gc3 ֤XC -P±ٸ8+.R5`^v9n;=HԦe Z ~gDQrRYCʅeژG07{ ڀ]4+yGޱU(hKФ#{r5}?vFU:𢨕\(2gFmW KJyP$6"~t(urv8*~ʄ)n'cx\ps[H34vW9< h Ҷ~G%w''8U7̉K$'){jٍs$VϽSć P:rAјD_B|ۏr.C\)m̃DL?Tzr"xzh\2TlҀ28:&DROp+zph7?ѝ'x{$nR9ߋvܬBb+?뉆<[и +:axmyDʕۧSNܹsƁ !B;8q.tK|LJ*iTyC  LbEg̨Qtl߁qew;wHeF<{+gb9˅e߱$AY 7 Y8M亾"JvLeҟfun,%|LO(cULa~&Mc {9>JA?V0)D)tcNb}Xܰ@JcSIxd,lom}2<1QAOι$;0Ϩ)%(iTUP4?_:T}fԩSѧOo*Uy݁#B kJ3j$Uv/)݉Ӕ,QMС};rAR%Y2FM+QsBddY͙a[`h ^נ\.s{ FFR5Ítp)uMrq~|qC1pn1M%LOo@ Iɟcלg'%_nf yE{d:cgBgjm'h:;>*je^2}DmlJk P˭C{ajCAե{̝&üZ 7ӵKkUʗnc|q#2dAuEF!bׂmgK&M98L=N56v4r%'/Y=%ePyJJӧ7_}mĈT$=Bw=K\\& IDATS]:,pnMX}!&Eś#xu&L8>z]7 aM}wVg3G ;4^ԇeIlaoalEֆ!wqs׳ˤcxDK/㼫ďmFQVg?\wg>1z'=F=@&p;hE-xG&I 4c<-]U+x~%Y9#CA#x>EfzG㷽k¤gTgNK$k>,SgCztd5+.W3G<2s1=Uu@ޏSs&瑜n$jz2wNAkfM լqZ}7gEG]9w`-jִ*6GgO}wwRmڴ_ sz!UV }~;:vCzM]މ૯|X'7,Ǔҽ{w7,Cf͚EvӤIѯs]ۗsCpW Z /򉼏}[8q51sb49#Xz 찉([o-q!YSOGVZVl=MD*+OϕHڒ%KYb]t!;@ "ߘtR{TRnWS&""" Rj xV&f~4p8Ac/낾TNZ*J*JDDSBJmVZZ\uIEfZVZ@k뱗//|N""""""Ryd[K/?7i_VqEuID*5krJܔH\:kadTR.׫[ʔشi֫W ~TNk?ȯ\)#kצUddd)DTR-aÆ cǎt ǕS_D*uҾlܸMZFF$""" Rj 6,ZL z~DbQDDDdRkԨQA| dEXe $"""""" Rj-YoLo ͭ$"""""" Rjr:>l1#صk搃v""""""R! 8Gw~Y?әz'B!gT*@9w3>ke g<͚*;͚ŸcF*"rssUKnZؖ놥ѪMqsW{9v;W]M~~>w9DDDDDDQBI}O䒋/`˖ Z&Ny̒<׎`֭\rE=gTF*@Hf0fx["zNx*fvf&Y8y<ȣ@-#k sfHe2wҺUk:6m?Ћ.aqʀիujvw+b}v61o9/-תUȞlTudO|5O_Ν˗s p衴jՊ `ժUZŋ૯ >s챌f8͛7/OI-s}Xp!yȇTΝ7`a:qݵо}{7%""""""U r۷gf#>9yktԱGM^hҤ;EDDDDDD 4i҄s>s>X~=׬aժUdeeհ!u!8{?dX-NOëٲW?/rɕ 9;9^YYDDDDR)֯")WnMnޭnMݺuU|2εGrʃ?Qi"U.t Kz3,)U%v8 /z}. 7$&=pYtJ쯫""t܆WYvϘT6i|X'UE 5:ۃ 7Q.~˫w9 ؓGD*zDDDDvUMDvZ ;ufsY<6̝mdZ<&;"099}KN:Χ>o漓r}9yx;8r`+pLozӟ n-9ӆ—Y䭘#Ρ]|qy6f'qT#9<6o]<$|yk%?ݎˠ1o(|صzLOzՏAaI90'^yO<^Goc﹐-)˾ q|WD""""R!";`v }͞='΃_Uޡtihdn|| ϝW^`alc?k |I`<8g->C{v4قt<6~~^Moь׹7E~ =8|p<7m:=)Ӭa_B|~eͿI3sX gO~Ogwt/3*ղ8īxwWf/E/s= lHxDDDDQBDv^}9C5۷~ͧ ѽ۞4ڃ}99k!54=+mW#@:ͺtźUC^4˙ԷlS{yT߃.gmT6leSZ$܍O̼'$!'^z4M[ /B=oG:Aa~-oseh^+Dzfj\3vt:z A&zΞ+W>I=Fp>w^ BFGp.[xuLjdQзUЮˁ4P]5k؇$ΝT9 ى2y|ü9} @7z̧s$w֑`f<^/S2tr-OᗞȾ&0٧ 8ˆ_H=rXf }:>ͧ!lʡ< Af"oxoHQ"-0}mW;;Z'Y[ZhT_F8F GbcN}밡Pp8ȺduhX4&'ǿM^0H8{)y I;rTZC:n;Lo`@SwoK_#s3:"H>'>?&uC)zp}pz܂ׇHZ8yxN/>t7܍OJiyxQb)/9_ϘOㆧ)P}ϢmopC+4=rQN=l[<!Yy@%QN#+6aC4^\Խ'nU}7L܉HU^'"S H9}h5H]Ȝ6_֑-@s?Z A8F? |ZiӴy۷CJnՈjyQ'f㔇֑x%d};Ӿ @N<3{rYF^Ef_cY͋< 4ǞHS0iLYs'hx}lg=s[<DM={ٛL2޿bN8{٣-9S.0Xt^N=;wIЗ(,y\5Xu9n./.篚CWnzx[r<\>}m?n䵥y}uռg8OqVx9O:֍cc CDDDDDTExпl,ppB.GSOxupu޺uޟ~ΐ Wӥ1廇r_r_¹_|yɬ+9+e7yGsϘ \P}*\""""""4 v^ '|_O+/y}oBE!8;ׯF ֙׭buؚJ3{e:s`"P%z?/7dpYЩAvib)3z!Ԥu4_?!ӁwIWҠZc9Hg$Y<ϴx4̀@sd[6.CDDDDDt܀쬂48j]{i?'3ii[e}8DhhψHۗ!>K2Dhk_p.Z')` j~D0`8E5(5XKדtx67'QHywa\0p>a  dv^ws[Rt(YLr^<"s?ړ ؛7=N-8_ ؽ~#6#;Us&{8D>O"`ݩ[o.}}jYc6=O 3cKũY&kVa)"֬^M RTإTӀȻf8 laMFi]/{g&YbݖӶmGztiѯo-| {V֤]1vLe&}W5<63}u?׬yZVfmZˢEo)"j֪E}uRTTk׏Сz,Q#'0GS>vG[ \;W6ҩ_?n=i9Izn{hAj՜""""""Rթ!*3wx)_"t:v'u@)7_|%q'~Me3ϙ7ncmƙmбC/Xƍ7>ݻusHcѢElڴMI222k]*"//l85נuV YiֻUޢ"…ʔNݙ`9 """"ǯ.hԸ$X%N{ |l))g+WdӺU,ZW*{w5W(VtZܧo[DDDD*ކiԨqѥZҭqV#6oْΆM6PI4jԈ͛_3?EUFUn܋T.XU[ЯQ)EDDD #<!/Y@f""""RӧPNggۻpyp$:+Oe#D7ײyOYthѾ']rg Zo=o^qu~ߓ ୛Kn'ǤAm[9}^I1Yw7auTѽ;ݺvG|0V CLb]FCh+sJEQғh_Lo1xР!Ŋ 4SRADDDDb {n(o#_@y9y s3\u1n]0xX&C {զ5m۸{iH͛W$%3)kO64z3}P|deqVFTlwXy :7/V\Iݺu 3q5tڅ BB!6[.fz֭FDDDD*ϣ֭۸add3~8BbsTx=SG.{SF붠r^{MGG^żt&]z0QeHbihir:ucpȑ̟?Ȝ`0ȹgiӊma޴up︘iAH>8t֥<7}]ԏ 'y>'ׇ>'/½<..=8zыcDQ ޺!r11dy9߽¨8{]y-y3鬋4i5d=(5'Oxc/+^eyʳQwX9;1w,)֨Q#.:'>[ȏ-O>碡CiԨTj*m-\5jjժ=wMZZm^8uWt'W6=h_oGc@2<k^1ˮ~t1fbV$[)oiNҭ}mY+M-.| {uvGN$y41y>Nm| 7G{y$ހGgr+>E>/;E/c|W=~f>@x_Y0y|ﱼ*Zקn 2Ggq/;X? ?$swHy N=ˋH)D>0{֭[adff]c0sשO]UPn=z9h^L>py*B>'0+fLqtVr ۬9t7Afq߳lY'{g5sHcjըNҙg L4ָ7'w䱕F/듞V-Q\{fgVқң[+6'9ǺYoE 1 t:f4;t~d}{,¿oX77>uvMjRNzqգn9K*{6G5Xm>"{mFly~Ѡ^ X^~.zh ?7DMGgzAH.)yr.7h+^ܥߏy 6y$9DsrvK9Xٳ5{65kײz" {W vJ9""""߰O8` ]&0G& qk~^䐃2L.?}4msn!Hͩhn;q{HJBb${vBкˡc>f471oɧ~֞~76&j k1s xxT,ĶeQ'؉BPVvԩb5x4tD>O~)<7qV>.uldZ2ޔx'_(3vsǒ[lgጳϦk\3:xs _}5K.-(>K.嫯70ҽq&?$7o,""""SpqޠA4jo# x7K#7g^M闝LO6ӕ#evn%կ_?B <(ptБ1oc5Rz -@lfvt?6"++w}`}6LyC8_?NV}E{3-a ?xePgO/9fG[fb Ҡ t[YxnIo|۽/;7MT\)`/?MѻuףE#9c#qpwLؑEC:fԘyh\Mnonu ť_gE۶m OcS`lM߯ lTa4jb D}Ć bKJhӦMrLvxC\L]~Bq5ثE jт ??s#_ϒqH Fo !"""R)"п_捻b$fobZ67!dH* ;ÿ`bIp/Z/<ǔR_j0,YZp j:uh,P(=zpD̛7 '૯:}:~ﻏm8{H)RϠ16!oYK3챛X rI71ⷕ__Jaѯ2hŇP(5ÆPթSG_}uK,e Xl)/Z=aoc\rd畩*@$=v\WJ炡C >i&\rEEAqż4myl.:ߗ,qfHJiRB|@y4oܙz-Z4'Sz!g^ݙ%""""VXrz=V3L?3ql?~',ɅHIo!$ V殻FVUV vuxXr5CDDDDR V+e󐝟5W쾝\~J" ɱnhf~WF(˶]ĉDsufAGǎoذa&NtfȎۍTߒ+"""#v劕3WK\LQ+W(Vo+Vv̇G5[1֎ݭ=dW~bPX} R 8M Y4'4kvu%I9pؚ_aLBTx{xl޼MIv-Zl~g6o䦤d$fzu\|G^4n&f[U0}/+2,%<&no͞c,3[Qx!R;^EDDDDvYkצu}ٸq$%S_繒H9u65}o͹[WxIu¼@`G}ޚEqa G)̒.Ƥt4{ Qxׂ}Nƍ5q2JOTg@/*V넚 dn3/"""""""Q {mh kY~6u뗋(@$d''b]{dAUss]~J!D/λ'/훱bݜ BDDDDDD$ܵbl'I/T \^߉Ivp04wT2P{mj(naY^{;ŊCј_>%R!;£(q/h(\#""""""*֮r.=vsF*;M?^ݺw:gDDDDDDDʃ[?k[w(8)@',9~1(It/rnɌEDDDDDDR)L71u'Z9}=6}wQ*;R(+Nɶ_ aݼG"""""""Q(5ci&s Uޟu:{!L,LX>mn/""""""*)\w?;"um`&("?Dv츉cܙa͝A ј17nbA"s sfbX9|ӷ~l>1?fK)k~y7.ݭ{gzVί5}vE[lsry7>a"̾8q3=oa -Qpy/ݸb|>ŠoP@v.P 3lݘNj}w""""""UB8֬y/V,})Zd fnusX17Eѭ9osFx(Gq~>D.)B9/31'͏n#r~֞)ty|h3q3&cƊTefdܘ5/Effvξ{?`6VΝgKT <ñ_=if{D.3c;̝]+Dȼ~L3wh!~LܻܾƲyf$͎w})"[dǵs13&7[o7_++RY( ͂w[0[ˎEDDDDD*3wyf3k>,iج N3Lsv}VuX21{! 8/[A.,_ݼ\v}a]>X2U^#E;>&#r̂ݍa  Rqza)tq{<+."""""RYZ >YNJAaQmv-$1.o׎3Ιw&d畉.@bhh61{Eѭ^45Ͼ#~.a n01Eq L~flbnoEDDDDD2{}35ׁ&g͂L-8};fwB[|3Mލaϱ lɦjQfloM}r\@^aaEDXE`t7svmݾ_LDDDDD$Zywkk>f}kl"G=?{-HnQqbpeTNypwAk=kkbXq;Q$ra 7ͧhQ$12Ƕ ~i8qw._LDDDDD2u_ ؝orv>Q v x؊_A'Y18a<3%)DY(P6/ݓEsѭ3E Sx0E(<]p \p}`Zw.w_LDDDDD2[\f7W,շoXs[01c&n77U,@x.I 텳}7[8悛}] :lѼۅ X]XsvwDZ_LDD 3hIDATDDD2t:XkDwv=bw\ 3Mގ}x͝gsnߌ+Dy ]0h4#vp6wJ(~<7c>17otvίE;rnL׌_3Xܜ;6bTy \&fp{ln=aaލhŽ㙢@\Fn s|(6` Px,fo/  wnMߎ}w{']h@4f9y!\޺}w/rQH~1l'׽.1ͱ~@`}baͱM4;n+^.#"""""#nofZfl h..`9& RxLS0L4#/fK5j5`q#nW01}w]Tpv̞8Volb._,Ώ x/ D\7o.[0`?go0ys 1 7sܱ[;NVI抈,t;vsb-g;xݒ-07ljwl~1O.@nތqOZſ=6cϊsی]Fi?w~[[&oK|HE7L>fn<^-Lu#Vn@tgE6;ݱ+Q>%jQj'1[7M͹~kqvixqs<[_ܔ4qc-Ż͍aݾK&obEDDDDDvB:؍C\_ b~Cw q>"/, Xq;Oد_sX[ӷvܾ_,xx9 .^M/fy~sM͹yӷcvcwkX S xNj؋oŹ=+i͛~XwnpcƮDy.т'CE֍D9=vI6g=v+^;^0c{7ߎy9$93[5r&T}~Urj}sj}>TVooz[͎<=Μ?rU6ݷz}߫Ϭ`vpG{hm' ]bg^UTZD~fg6zU9˞Fsrg{Yj+}e/ w;=^;=g^Ϯ;wz}{YoW8{# w:;l/b}wWF=noWcuu~X0`A|${rJoWg7=k41]|9mCwz.]w=w<87o|em kw*r>|l0O`b^o7Y{IENDB`kraft-1.1/manual/images/de/followup_1.png000066400000000000000000001773041450127457600204200ustar00rootroot00000000000000PNG  IHDR^f pHYs+ IDATx^wXGw#XA ޻1DM3_cIhh-^W]D@quwg?h灘E}s;{GA8|h0ԗͱcZhauр___!56!B04D%a XB蹑& Tc/#B 5D%¸XBy!BY2* eT`DG _4~=Euc;_|]ct?9 !fn7mB!ah/ݤ f/9Jq>M{ͼ/\ӫIFM4jҴy7?5} 6WCu.? |}CB/̶C՝.l?zdm'f9yѽV;}&,nexwǢUgr_6)ExBy)Std6c{fQ3[ts#`>s ~êŬP/oǧ;kӲ~yQrƒZ&s5 v͘h-ҧ^^3p0)д˦r1EP5?!NZ j^Cжӕ{h5zۡf01,9c1au'd{~ = Ǯ18{&sC7oMCC X:8w Gb}X1ƨ.毑N58#ɊwF?1 5޿ΩB̼@7nXۈM,RVZ v(`˥Aר8^T{WC̯vo[ zQ=nw1#G:dHhh͢ Κ9KR'>^BG*'Zu{-bwRܤ=w gG$S7fӶ۶Eó]o~ú=gO"⭕?NVMG,xޘGC>Vܷc;tkYq-Mڳ=nvhmwo߽c0}?# ЦM`;ktܰ"2iW/CG\ԏXl٢=Lpd* xk6}flߺ Rܺ$*r!fώ.=kC B=OSZl96a[ywvsӪsrB~ƲϙzWcں!vfW˙#oY/HB7{Q0MR:o!45S 2߶ckx{Wdj79rMh0rg~mGvy~r"qmثu%GNiu;^w>n)i`/ǬS̈́=7ç@^g(*4kXQԹo^MIɏ(?F~k)O۞ٱVa0'k_=Ahh# Gp%"znk?m;nf}}`^qcI$ 㭓,iW]̅i9''yܒTE_(h24Jk$wswČLYƛhP~sVK;of}c?`fu ,3bFZO&%:eW$B;i\,:M<<٣,ʜc9_L.o8,[eֹpQ:+,G#a 6R$DywWκINQ^Mm[Ui1|#F ٳ1<$$rȋx<!.d!,z Y5𓟇7FN}OKYby1~Wa"^pN[L2Ճ $..Ljk ׾S]ػe(ꑓ"N}{1vUszyv{k7'1zbS ԔTղ!yذ4iV?ƶt#@8h~^ {u8pFq"49r.^'/v9d43&h(<)ܢkcr(P-',W}*q4@>9f&?+8qʿsZ4xDsͻ6woH4xmRE_^|˾U%UjۭZgx`{?lԥuX1NLy/]7:pb1svpv|aǬaܭ yf\=.4$ƕSiB={8j펈{߂Թ[U{;T(-pu_e_.\i:pKgKB.:o0cY&Ϙ2z#S@R_&sciʅ@'\ݣleNT%{U̸0ƈgq-&PzV:|Rr0` Xѭw'U9m5xN#g{JMO{10nF}qи~/LQg/-6R+(TyF^r޴7*8hh STB=05-ࡃի e#8d!<0e݆uGGQG֭Svo2B!xCj3̺}v`T!dLܹW%06ك !T9^0q!B!ʠf԰]v!5CmSϜME!B4amlJC"BNk"B!+ B!!B CCB!d!B!VhRҵvm l ɗm׀1n#B^۹}58Zh׹yn[6MMA/$I@O,֬l?ײɞt }F_Xrѕf~ųhOhwe ^۹}5Ja2Fa_սbqqv>leU @@1{/ITǕˍyF:6]tnNԵ$)ECg.'UB۴ t|̐x̉tީ|]%@:]U.,\^A4ջ˛~9{VMW(ŧ]v2)%4;y9(#ꯣu[ȉ>sK+٦c5E#'fKpf +oz}Ȕ(;s)'‘36ùC*@ȸs"*^&s\Y@yUi{/g;}#(cZl!19R-{) ˹oE疝^MȕԮߺB{?js:k?kW~t;ĻӌM oD1nſ7]\k)o;q1GO$LGb%.?U\Q8Ujsܶ{4nvX-'ϯ_ekVgfM9sz?.vx5cr%r37l7fڼ+(6I蟻ߚ3s;)B6pbdԷmQp :"(-wmufnO~ht֌yɤLX|` ߶s]c937(z.|cvI^{?[[Ar2xz:헢.5u뉂ws`@BbNsz)}[loXѳh=K5{>brO?-޵Y9mF;2rۨNڳl=-%B=ιkǫ7{$y;i?L^f{6(1Aѐ~Ou.!5VE&Ɉ¯zpܵGv!vں^mD@ܤsu GQ+i[\zq$A TQgp+| p8UI6Gg ͜"r7\ u"DߩS /Hp5]0y].C' ~-O(k<D qMcn|U,Zmĥen'{/*jvjIsߡaZ{흸䡽q{{qbnC]$ skvJ\Εsq/9j}6oLsEGK[ kv;yp*BBWU![!Jo6[i9`dw}STo׽p5h((a/kzOzANQo ZṣVfe1sI6jI@ۨCCK'Sr'q`=k;޾mw#~75w'Q{lReE2 W}ZI!$rbQoLw}w-_Z$N러[\z>XrkG!r>?߿{le'Mc\'o21PSTfˀd7X,TfF}pq˖2DˑS"wRtw}7jNrd2N "!T5G]=`kEF@*aB8f?$ ?O `M.XgBI(d*u^#bt|b 0&Gun2nLsOh@ *Q1{18ҩE-5ixYXQY7sh,3NS4ς^Z;w6x,7zA毎RTl41>-!>m+)%!G5.4G_^Ga2_RL< Xfb᱖2O,`VkQ53\y'A[Y,TVr)WoSLl/M\}!;Kv-DT!',BhM:pnvH X{ZVۅܛqOAB>7$q\@[3u~+AUp kdӝ5lSezCZǛ$*tL75BĎ~}lS(ӝ_8<޵[zXB\᥁+wҺSS)@q{c笼~ʟ5pa73tc qćOLu{g ˊk'Aɽ6zw:krYAwhj ?:׭2݊/w'87x؊?\Onq+slPKv"}Zb;hw BC3d2j _ЪSƙ'] iNݾy .&9vED7~7T 諉;9~hwCߙsl吾U /- Iy$ٲ|릝״#?NmHQkןzniw7p-:T5o䔕׶El8ѦO?.i% NͿx[^ߘͰ.i#W h?zm=?umsɖ/hӉn}+| sBtǖL[:{w]9 J=d7+NXLV RBE֘><LY0Sb~mϲ> V-5B<5>*Ec"TМ[7%J5zGB=YVg_d.zQ!Be4u+>Mޛ=TBj&# B!!B CCB!d!B!!BY/ƣt$dRc*Uz/XahbLdB!2B!QC1f*%ahB=s5+ 3"?U\ٴ> B)=uDBJJ5 BԞ>1BmSF⿀!B="’`OBȊ $j9~SƝ2O&(];ovTq@nY$K;/U4+d5r&@|C4U3`Rsl>s2#kpp7Y0W lpVt% "i 1E/B;)6(e+U^}R G|cRVCm8́7-:j`*Gw3bD]cMEJE OBH ƻD^ǯ+匾#e4N4QMj)4>6:Q"}ͻx!ѕ@E@?R<$ yP[hͧ,c\_#D%?F;j$M9yMM4ߨtuH{3ofϸ'naenY=U{*CK8^-7w}Kk1Q!{?TD*n@u閩=Ws^~C&Q2z/Ÿ0Gi8u˺`~-ּAW<q]P*j7 kbN::;,nFUyp^y,OX+PLnv<{eImUwNd-͕ q,3w~H-C9y;` *UtXPY/'l o_ רJye9T3FiTǥ[>ۦ `ܓ"pJ}lth5=gCٌGsW'P=̓)X@cRyՐJR16QMÛ55DG I.k(뫁7 צSAmze[NMųs C,ɦ_ /Ͳ6#JIZS9H 58=fY__%fĚ^4 R8)^,䎊Ad'1: nϫ+4ba>x{ G9=@Vl1kSL|PA5(@^EFF~u*DҪrR7e_52टP]ޯ"TIrsL񕪪IxnW~Z/Uu0fT2^YSOv

g~V(m8X[ Cn1 ;4>gIڎjALJZ8WS2$~}pQ*4Pcs%j/z(. adbN(/w`dޓOw (jLsHH /M$ÔGQs Nm `.e4o妃{}+`<ͱP\`hh,77pҶdITo4OUY4iG BԺϮ:ׄ:){B6'(\)PJTk?Dx'SRf\r&sg.TS-yIC"\9ߴd#27ukY$*Oڊ QZGzMy>p,X•^JcK̽̋LG|$e;m@U^:ڡ1o09`(_+C!Da5j)r2iL ň:جER_/F92D9!:(G7AT 0*'Iٟ_k"3nRIzN4 ?:K]9L!o{cçG8Ը>U ָG R7(c ["0FUvSd}+KS ?z@J,ٍ3 =g 4ЍLev G(?q s.\J,K4o EB ]͉~$L8`Y梩fP^V4(AYrϠӎ} 0/`98OM=[)(L6GWoE}iPh0Iխϰ;s`c/v:ZS|]e\s?魄"Vl5yϰS'Ti%6N@<".'q}# Z~s{}*sS4ӘyhfN72:7snZ` &$)XZGb8 ̻EPQJ "c@ERPӃd(@rbN5(# p=pB| jh\}Եs #&T!S#gOLu ;pѨ2 T@7J1dn¡3&ċ&!e*)PT$ @g273aKlB9]vw@n|Y ͼہ[t۸ i"t7L @\&L{$*Ĝ+"TTrrg՜Jd `@t/5Pv}"K3D&E*R(:A2 E&zxZD"Q&''2*&'$x, X)(+k@R[Bcܥ5s )c[Y ZCx(eT #J"""X P\uk!L 䭁L4l-g (uRAg֜:=+'F9)|z^# HDFRYv ϱ"uR1CNjy9uFM3'$A 0> VQ@Nʛ0(P E;z2j8w'ٻ B@[/! DA(P`D(0p'"ITq۔vTwAXտXQB^n04|Hʊ J8K`FS9m꩞\KuN>zsDn\1Tt#8P(UwŇe3 ޒuڂ9e,KHf UrDS^DRO5TS%~&j0~zҘQ8Vgbl!ߛIwc&e@ 2AqOxo dSL O B P`t .K' 8`|PD?D0uא&%@3㠣/t$^+GbTVROۼ I!&ta^jXK,Z-J/3w{.(U__ g3\D%``L)QPL/.84V' iP HUb3Z^ӻAqd*w^Dwg+ ]gIj 4i%/#tj? Q(*Iܥ8>x`i̝k ɁʚYXTjGLSYOvɼ7MݧGgBryAlA' a"Ɔ:&(1 >{8=هIVeEIP{~mykHFgݨj/]mo*{,Pɡ4&KCSHyF6h PևTu:sZ*~QSaEN&'o.IgDԇAe]'f[;p\6u 7?&䏽,2sGO9, 8rV$%FL|>WVC= sU%j`).E+LΒA5Wrr`٦섆 }s:*uI]"՚U+M,,vFfTk7O 6/9?+ng 쿑J^v:m%3A5Wr2F3M Ϛ`c\PY项{ws' M+,;k<Hwi-6Xр-s:[ڳF5Y}qg/T-x:(y5r!ɛU+lJtzaa`m̴udf X!{QB0Ϝ1B@!@a)taw!^7ybAMH\ZJ CCk^Wd'L%S!B,)h֦ji+?! +UXÂtKh].Ȇ* fAP `hBl!ػ T0w+00FiPT "P{)] N(#TJI!Bٓ׻0:!N(#TBm`lahBEuKw>6Q) -}*MX57J2Un%Zn~[Ɩ["^o%w ,#2 g>2e 7ߴ~=k{.||ٴc8uh7B{hzv/@e[A(Vൄ5!, yC^ѡ}p̩Oyҍ>wQWxgcs*#vŗ/o%:/xm~&=ywzmHz:{1"*mB/B~Q5cR Qc(RJAER11):t2GxoMo."['6W8pnU~ أSӇL9kFpqDĘo:r\=Lxi =ƌjvٛ.>*:q\Jr0? "fc֟գlD/.;p#Tm?aW%=v+L`I""Z=L5ClzL_ٝM!cUh8i/>S (iMy%Q# G`Wﴯڹ{nDdŅe]zԫFgEw]xs#|ܷΧ34RlIĮm+Xi*`ўC.ewmO얇=9{ifl;ϵ.M殥nj7/pԮWKt{sZmZqAT Yѱ?T?b'Xu hs){;o\?mzAlT4N~6T, :&٧mkHs ~{`Wn_5p{7?0㚚' z#WTڿ͚ IYқ3GUzeyȅ+dyJ IDATnȼ[e O#[#{v฀n}[c _,~2{\Qyt }>k n{5bM+L~IzWUsCH&YbCyþsiZaB"oX4M߿|vK&Oe CKxNSBuc(!ѺHGG32Gs\s;wZsF~c=fn|FkoRܺ!d8QSVuHCuu?|,ƥ;vX.%胉Cv-*;=b"dzn$n]4Xq.̀ 9 2J8sN.(ѪgVUj02<\==[5sq+o@H~Kk!qkѣi??020_wlp6xUhpc#ݽ?nZj'A+(e[U:[ôb-CIC'|?)|n^AMbznoTW5 b0^;{6eDمh(-TD(3"#2RI{v9?-d*ܞ3{yf"E +XX@UvБ긡M%_0 _ 0b8ձulѨ#xG, 4:wޮzy~j;+q<#MF-^EA_6k8mGU߸`EEU9N50RJBx^s,z[&ז=j$y՝7[~k\tS4쬋JcӾ&:#tYTi\z*a }&C6մn xhR IVylh,YVE{q!.,.)n~QANÀ llbe"{-V+gh Vz[A./+ Ӭs*«㛖9 O_!z;j$h_Rƾ*sC~^kQڒpY28A馜׼}-k[V!V&_RyEy/tCS 17&Ds/H^~=qG#'hį 2gѾ 9v7(0)144$<`b<5ee$`"VFak7^R:8Jǁ$ ua"b4SxE|F)_A?ܷC=T =ˏ|gQ5D4Wg=vZb+nM}H.D}IM}% . )%)YZٳZZ>޼i hl@W _hSW:B{3w-lHYK4p$_8~BTh|Ky t;W`t@;R:-XE~ 5P& ?eŴ1{򒢴H‚byAv:U~\M*BU}[ӧufC:]cznɑν1 )^4DTEhh~zGQuVi^65pա;V/p" x `W;pzYf<|6hUmDԦе ;j +˙`FswӏECȺ[m=JBwǙG7BXc ObŒs ^)C}Ekon^a\ Dv Ύقm 1 U(#H7y? hliso(-XFFoz ȥǯ\t=!1ae_iO=<:"M^1~~~hnjrSީma_or SO7Kul'"'~gYBRy>Z| >|QTIy9 Y}Ova?^"ag,({:X[8Ph*iTgrzy0>sxfJP7^ĻG\_+{ |{Rk e1WQHK~}ckH&B;ٻӿ5RP JLp8J◞.bՔOoQ1Q-s[Z䛹CM P'.6z2i3i&/((.*>}wKTVEt4q9ڈ[yJS9Ǡo;U;(ᶠLK!SjV$&v9 TG~)V|%#]HFWj?+" +5aŕw\t\vx{|]}qMmm蛛_mu=9%wWO>{ȹfe@irxՕuA\73PY͒VeId:,EH& Fk;MRu_3I.{WGRʷ,%N:.$)ÂSpEj*kzr9MJ F!i=I$ E6;󨘎XSi)KH`VeYUif{lm!71԰c?Y:wRke-8U9L|ZւSb:gLjL\.DD]up/o(}eZL7chfULIh5_|lA~ΓebW?a {jo f? U^q d*s|m؅@0PImȀ4 l=)]i}R if-UӂvXGWEg`tr b5eLj4^YVAtMBw=ji@++HȦzb8pJgf^ErO;tצ4 Ĝ9/w.&.KKJH[y_Xt@o- QVZZ(|"{ ƙ97N:Qh4!| 8:_maij6Mu'= :_?H߾7{4Qz~U '$A(4 [Hʜ̈́%$x*JHHFL)aT>FGe1; GTg{18SI(WF Pň')Ld=:?o2c@,cyw$_3N71X1^7atzSsk+ +gn,+[LՔJC=*[h)P7_s:Oo1)m wgƿ'b:;oyp?}_J[g00VO IWNqDoGBQԡ;%-$ɨ~Eef*t8a9Y_M% -9Y dӇ×Kƙk0SnȚ{|vƾg٘{%k/0k |pNTu>$`d1MA/ySU-Uqݨʵ,Ƌb@6ԴH VÏcRE^kó'k _]p=5-`d>Cǐ m$Y\Tj Hw"I\P!6?a d`o|pg&rlgg[@SimQ/Z_]uajd[^4|}M\CDאmrf^;YڗK{ROM V-P7yZs?y2aNGD%F~>/Q6w:RdÖG-\{$x\**7oMۚvϳ כHay 4RW,O23 Z_\p)۷̘)," n7i Dal?Jm[[C-iŅfǐ^~f2Cl\x{Ӷ2U*^xFueKVC#E~lkZq#Vo$5/3PU+ p ȯ8e*Wװs6'x0hPZ~)돬 w+p1]ћv)F<%>d߻/oj1})e/2Uj$р94׆F~)f Wkv]Ջp'긽*/ Hx,mkdWTMdϒR)*JPأ^8a8g c=ܥ7AAA~3!  "6HC0#_N ȟ"  (4D>St1;]cla AzT ҝ5W\6eb@;\tY _[`KNW_ сԦKt 0>$}/9@inڒ8QW4l??ÌF+H KT1ĸ=\_yA碎rAփ㛬hq|A1FNKO})T415)3,=9Uw8zDf9)s"?κ|>pPwTAyETWz_I@Kv&:&v.1o;CV nܛB9fx9`0}Leۡy)'kZ LހQ@fkMDaQg 9܃ l<.~ɺG8[Z- H.%4anȕ,tt fՐ'ᳬ,,,,ui}0Ⱥ+DSvFM\O6\ klod:uՁ{h3i*/)_ODfj:EyWkKE^>/lr2[d#uul^8w8Zz!Vpͭ n&ݬTtA@mpԐC꜄ A b_sEmhe'mL <}q8`7=f7B;M0qkA @Q[׹O6"8x=J*&b,e1`Z˕hӛ I,#5:ḡ>o{ ^ YjTp #`8{Ʊ[J܏̜cTɪ;(Lޤ+ ;(A IDATA Ui;cԏ>ɦs4X[`4i8MEo,-X"q8s›\dhN:n(;"a@Sg[x&ҫoXaliOc)8jƃK $ssؓP:φ™͆Ph 1++j$:Am۸T˪FDXw#5Dq5$ّS" HVeye]eX9]:KHs A|QZsA#ᆱ%qJk[N:.$!!9L 'Y'mqVDX@TU`ҽGBZ%\Hf UN?Nl;}T N0u\B~eǗwmquX:KSDBrSÔ@+@ГZ:achY^-j'@훦yܘ7 8/0(YUQM,dc=rI8 ]Qq\lSPQ}9|Z8RUQM 51 #sC۞Xz(ww]# T/qè#-%ӏG԰;$eh1pai)ڰY[xV|}< mtLea&xă2 $Y~巚JU@T)Q˽+YkW8~0p JOdV2Zbt,4ޞ _7C+ka6ݿp84 V!QyȌ~͋?Ֆy6B$[@ iz(F0rɩT0`ӁiƥMpC` -Sl<ruph56^f۝5d UWyQІCg6"5x\ԎWiѨ~v ̐g:NKon'âMşvڎ QxHJmN)wC}Mlw4hc1a_ҊVCu!zt:J:) )b*x*(/_:xo)&aWsL8; ekJ8N`4zU~/]>~1#Ŀ\۷"ҭ=97쀝׊;n9nof*JNx<_] д)z2pݸPW^Ҙ4^cA1 mGKbsͅU?Wbl[~5hMu]5BkvUm%'An15$0?e;a؉6yZGBZHfIn)j5o70>p$'˯)0HqCh~cu_{LgX8bg9h[/NTs\w]gsjs}#c}#c}JWL45Nt߭O;uY&t}5l$LVٝ}nu&M`wy;pƋ'jӷ[yQmK 0鹋Y|+pz9430`fEWF;P4P"gr4=MI|>FPvZvvve$%ɚE cFr1 甑R ɯ$jY%9#:+)2ƝSZ"FeZpQ +35&V>Ih]K#KU 8k4u%.bvTD-I1!`< wd1#]U1{ Ӄ+ Jqh~+*g</ QKt~fh#yޟXbc=vUĭ5qsyb*Bk>rXOLP%^y};<ْ͙5H0ޞ[=|[c}8vCʀQƽ/x.|kkBpn9B JR$T>>ʋQB&P8rOfivychԑ$)';XݪaNgl3 3j Rf?oԏ#y4'JKyh9CA_ڪG{z{ů<ƓY{c{Še]&%%e/^h8_vDXa w9\P<@>[)prMmudSS r_ȕnq6;e. r 1=Fť%`*' 9 kC1JmmcyL%#Д^2duE5m?DuEPoYZfEiem:4v,H0!+:ГBChK$MR'kKM$J3W6.$!㸈6 ڱ /zN޳S,.75ZJI0e͙ۭuhm!&ҙ]_Np1q KH7|;2YSUȶҒx5-y#H "!.&' k1)/rw}=le]C7otNNJuttLMMupp8y򤬬,Z=Ms5+NK8ɨ&5[_?R};R/}J"|ATAA sX2rAu^4: WTW5V |̋4Q<,Ii'IaTRIJж M\1=R%$zMqlϟ 6jz Qҏe|RREt[ޝopڿx$;d U @4IAť$ rx]^뎈"L_\;7:&J%++ Y_[O`4 > $!_ Әb>E܏D_7R+ӳѮt  eWL}T_c{ џp[vZmZ N753;JlxNojbkh8أj804U!k^:{עt:`fў&]['btzSSkW  !g3ZZEVIā;@6wXZ*e܃c{>6$2UR(~ߑ-$̺O_wG`տu.Hf1ek+Wqu?P>}mжlq uOcYAz}NF@4_<^CMm?'`5~|پ`>yHDbޅe@6;u#KZ{{*$M h.Wܩo @Td>/Xr8VYE'MSF ,9(YswڭWYM97zmh}`֗cusb&--ɓ{kL^+8)Qom vYYG qqr=>;O+h - "վEOikT.0ji薽~^:踸ʰUw|\K8RUiɑɳ 7O= & 1z$C'v.0>" da2k t2г;zW0zpIk ];o)n?~-Urْ)3^V!]~M$p˕K 糴y{+i/޾XKUyÐzBlż"VLv=NOڦoVbMy6Jֿx@VAM9wxtF~ȨPn NJj[7|v7g(((4hPT֎hoQvNdߪo5>E^]9{Xaظ7l-Uw.bDĞdKFMݏD#a)ݭ` ޟڸ9ң QSu1Ndw}]AW d+_KNOvh.=jŒkw  ##cڴiSAsy^-uYVD11+;5WTNzu^ё$Zngobs*Y}/`soZ mȶr o#ǰ,F鲃vL6ѷw;t?/%t$}-]y)0Cv- (c=ꬷՒR9R{pEv?vxKNV&zyFfײəVFSWOk$c#jH` k}2ۛm1n_{{Y[X9?h p2100p^֒uݍ֝X_KroX%t TU탳|ւY&zz".p>~Y|o|.p$>F_bM޲exIA>SMKWPmp]mmmTv /˲e=<&8[]MMLLÆaxg2%;|ՎȄ݆U\GіMNp f0Z;fĔ>=8Q|;9b^)𵸫tVNr3%.ܡԚzQIgVo^JNfZwrϥv(|c QE>>fIns=](8~c_n&v"O ͮ'UZw&>9܊$},GQ2I v6(w6Zt)A }ML sxo 褔KQ^iӓ/' yNy 6<@:=CC{ӿKAm ϛo6ɔ&.̍Oכ3SF\dxµY_0Ӟ2T}vqV0!Em^6"8iWX ܘγpZEj* UY7/`|u4}'t"AL@IJV]nQ?>"9Ta҃W^m@Q*`BCƫJW%J!%(_w%}bN IS6[r,q饣7,.W9!Ma1u;u@1a,5Y!~^ֳf=iJ"8Қ;=n(YxWƆ D}]!&6?&&.F~ 0ddd9sO>!k^~Soo޿V@B$KJj$AU|q1Y^C+q!WI^b8* "@ɪ,`2\BJS( /,LqI %\Hv:H'Isvڱ"h}CqfNf~ r?چK .gaJF|*dR:p]E 774v}ՇWOy\et{2eJFP1i뷭PnﰤAGMMք ֭ DRRRh̿sg×aԑ#sjX@?2˞ h5 IDATuLw@j% קxaΓ ZFG?QfBO<(c@2 WvY#F+˯'?"ކ{@\:LN̓KXh=;M=$QDAi0;e_'6(ݫ"$+Yzp4< K^*Z+ka6ݿp84 ֗xFhSRN]Χ@=-Q.z{P`1Dmxb;z߼Ԑ-==}̙W\oh위 =l/ 8s'A!X,A|sBBQ'~BP;P',3` S5e;baӌK(ᆮn: I|4wxmwZFZTj8A7W&^EA mZט?X=NFmW\g̟8Y6fSQY;ܵ1^BB=l+Z_Zhs'o$"/aoycgcmy}9gzJ:Zoe₽GM]0ׯW G}ӧeee;/w|{k}A~WT|m1jGdo4R9sxVRy?KZJ ?QjȖ6gΜ7~Aa$wCF0FD=3Ww   ??s  (N |]B`Pod! O_{s: uC =CM &_c YGeozqdխ|K=] 0>d[@jp@>`d;xjF^yERh7@=|&Qa-!(7vR=(sծؗ ڋ+N窤 TzE $)7t uo60Ra<A~؜N$]gE›悔SG=xW'ldR(d?w\=Q_+0դkMt\Uie'8H*mt@?|ŤAFe2]o$T|[ LwԔa%ݩ ߤ =\ q!h韲ّeY?p%9=9TT㑲/.Lx"YNpjOBCbK%DK/'$Z(uG '\­?#Qis`jX8qlOM+8)\3n1 U=́>u/2󈫇Q^m, ,FgQyhL Sc %)7 sCr457vt?HfR]Ⱥsdbhh.3w VO;QxrL햅q3A|:}]O޺u%Ğqz_Bw?;Eb䫇#l:x%cO*/"3㵜KZ t|6#iWع 7ϸ 9vXyQ!D&$8NY ȼUG]/\\OL<6S nWd-&[Ÿqfńyۯv8;mn, >,DlB!ֹ{'cn%q ڛ ڑYcn^czv}zX x{)lXW 1N5y?iU#]g./H=@Vc>Q5k+بUfqyFT׀hJ046644x>Ca$%(K*iǁ"=n֊zЏ5m){|0ɖ&4|j/^UEp5NcI3@y0>Cq7N;uL޼MPTbՔOoNIg|ʌ8協Bt-Yޯ?!K̘8e_wQMd]̄Z*]Aņł;Šk{ؕ] "b)b{EPDKH;ޛ$s4=ؿr)xDqu!Μ93}tռvuqqQS+'իWUn%–0Eia>+&;iW z_Y ؼ>XلrX,u ~[\nTˤGn؞=dڞzWu(VƲ@kvJDc7Y{#04, !'+Cd4 wky02F^Tˮz"t!;3m@ǑӤ7֏޿e3J>耧3KN6Zر#((H5iӦ@~fΜ٫Wj5{KzȜ(1Ywvx^et:Ua'"hZl DXmj[)ȓz ۴ιQG4v8:vZ0zgi"t`R@%INaL-RB}=Ce3KQ{s]#&514NIp ʧI=q9/)2u-ݖZ}mu痬PWRf׾ n[nۼ.ż;:v2kUp=RW.nR`ePzfge3'rIMIclaZZn+]TL Ucb'OqoX2q<]~6`{v;gH*Ռ$̊{"i];S4s|v_ib͔3xnzcrŷѺ =FU}ߠ޽ۿqѣuttT҃v =.Dr{ڨUS^"Lڵ 3־]5>Q$ 5{5{|G94#zsX0i>z׌kD"Qt^06FrH$*˾AZ:t|Z}6oىwd|Lr~ݔR zZ~fǽK9O^Nu}_?:]$gi~zfj}[hܐ (r&ͳw2HMjRYyVfq4oKJ[6=dP0W1e0VF2ԝt7gOzV#:;Â4_6Q$O^O|( KsssU >Կӆߡ+k>ceAUao\^ S.6.;t4zअ>WDK] &ؤIs,tZp)Q 5ƒO{vm=Mjx6J߇ljӽsνNY#~I?3ӟFgMMkQ@ڲ[fktzʷў}=>}nl݃_xK=;jK1GeTZCH4hРǏhjj:99=A׮]o޼YXXϟ/((zA"##54T TOls[͔u^~γ?ЯmU[.,RkߓWN []5݌Ϥ$GWF=$>Y5*E*UoA-~Q&y{_TA5յ_ ]i8Qmũ$뺮Z]ixE٠눍 JMfc79iimV6u Zs3ISmj_i*jMrۈZz>+Ӯz̟_RmT92RPՐW 168!˓ 85-FxIk`w61Z흖,uM4k}Lؕevm'iӧ7n(}E똘 ~ٻl j~4&2ʸjbs?ExQߎ_ZuzGFiއ'h喻j&汭A=lrdś5YhOd$&[$pA!ոUcj kͽndySCHzpQv__DBծ*A7j\w}됡W`ܬ;k1%6*`$1mW4$:Nt5hт5|m-xd IntiM{yvfB\b!WuL0ѣ[~ݰaâxcΙ3I&e ~u#GH$œvɓ/S' inf Ρꪩ-yX(_ 0,0 4-F.gdXt꨼OE~=uyv}l-_q>0tttmִjج@ϡWo6;͎H#;Y! mmκkӁK 8BӑN\^6Sޠ pKv4햣ߞ!$0 G'f{|Ffh6 H(ǤdqDH=-uA3C" 7|65NNȧ9:N\̱^iL朝đ|蒜i:l3[6x#l=hBVQct_xJhtZ}~nк-殘˘4 OS jwd[AAvytJ]&9/ʴuԵl5sἁ{5oHh5#Zu]>ȤƊ+IAkψZJϷ_"X:1ՏsáH(CQY P%=MJ|ʏ J^^ސ!Cq!AvRąǎS^I&v vuuU\ਨ!C)CFQ_8ӾI+/`n^IxsJ+el~~kmmfǂoٿ3.qvKO^ [J#:}tU10r%cwq&JO?bԞKO1h6]7mXW2xmlX=1rų#]l8rcSZs֝r؍}/}pꁋaၫcwl9mZX[in[}Q񻄬exzv^ytP:ئZ3t%6[C78:{g/;w˽|ޯ5?Vן.>>Ç? p]&ڵ Çs(@Dѧp })!!q>б)=\,In;q$l<;Pxu*(ulGNǰ[zHcko/_y0W:9X}lgܪ2ɦ6,*q* g.ftwF$gDDİi^=2V7lب(j dPtb$pƎ8 Dzw='*ȺCjrvFC |4ѩFjb2 ⻁!TqkfA!hs}SuS>TcksmH:&'}7Xx9LƱy4%XiGչ0q/a-Hw78ڶ$׏Z[\];{F$fkIgQu{)}{طoɓ'Yxb``j!a^L6$z*R._~Æݻv}6.>:{!6-{~+2Q0y\ Kg UIAiR$"z:Yl?7fJHv0YYC|%"Wwc Ł2FOhvЪG,rݤa1|1*) yLAVܰaɮԌ9%sK\V[H`]ItA`Xe3y* 1Y! @ J&08$K/)9CÒ⤑!͂l9Ǚ(aX&⓯k_r9H\oCց35kZ^ɟ?I:uJ&6e3?m}.ㆋ6(3W\||kZpT_+_g.]-|)P{IHOO;vlFFj!a'O9…ի֭[]~jq!@MR`ͩ潸#jeeȡi٠>Sv7Gˍۯ<(*R&^ IDATJuqa :x{io-&b3o\}}t@g$7tiZۄY4e&7[yFe9T&P&JPX,tbԔ4B'c>.*?)?רa/?ΘJGK52hPL*.(l&B@l%~uRtϏX=\Pq?t0 vY&??_]6^Z[Cֵ?~߲ynxxDUB`3BܬҶBMA #τy#=t~ I*>UCoɵ#[eeIޞ~M>cK)A˲}GҤ,籙 [,&C)01mOHS{NfCӱ ȳ=rosEc` 4rsl,BXK/?M ©w?ϖ5uZ:XQ٨l`di2`/O`Y:D=K͓вĻ\7mGBmQDAZmIu&V\LGgg3{WV6nϥ[J畬j&&&4 hjj 4MA5!~f7ҿx6J#<A%4soxm}x'q:HRۯ8*E;4sƳ/n&mxʇ2ݭ|ڸ}*qߴˍc[ǑY,+ \9ʮWO[7xPD\LtK,ly̓s2gWi -fcVM7\><6i~wG 1^=M|ew_V6s̘Zԗ7lM.7;3N7/+[WUU<d=8}] K [7eH9ld"G m<(PtdskJqhvq%|^򿮺L^eoo g޴ij oԨ,]tҥe͝;w۶m  /^ءC?N^PWZ/X(_L^\P /fāѕA)p墨5DGk"4W B'yxvk]Gq&-M4)yc~Qᨒ"B~ݶmAL!Ԅ{&F7xI?4loeESr2Mӊt !@{\AW#S ōؠ\Ejh5T%=zPMB!BUCãG*T B!V B_СC!B{aTTTnTS@ V **J5 !BU4(7oZy沙_t;͛7/B!TUаqƊ倀??_/ @ܸqcCCò!BHU5jP9ggviߡYf'-Wz}.=:Ūͪ[26m{?n+,=G<+8 ߰N_ !Ty&ɣ=sE_r5 [=.xeXf:F<-|Bz|/n?kAa6{$>?Ybc޾'`>Zw:Za7^{RnIY[xnZJB^'r;S4t;p"L7IV=v΅jhq 0Ig/ 9аsjhfg2.#FzˋVOe26Eg7lx^Z]udöK[jW7,RDO L/SG)V&7pcZ{)KQ!BUsPKVP ?k6ZC&#*b6 o/Xrl-D "=;7 AsK3cY͵H֥ANR.\6I7tq1ψ(i>GM.V=&&V\HjTOn.eDN9@LMIP&h X$5[ r4Ln^}`Є5@j6fcDYntdSGPz F)*a`>C]go]AB>Mt\齐Z8Sc y;ֶu3dDr9 X0ʚ=׀ OK۔@ӷrYe[==~aR?1yEI<E Yˬ! JvgG%>4W!pZX^5,F,ۇ[Y瞡uTU^m{)ΖOB@ {q4ځڝWCQ]A>5l:CdoMT`hBx0%|c&& tؐӖnsp$p('WlM_`K =G_~mR̻#G,*o#H-=]Fn>'5RjbkY -W4RzB^v6Pަ<3{AߤL<Χב /)ԥ2Y0` \ H }j5Z9pA!~vfIK)ʌyruML!8G}C ڡ:FntaنLWDI>ƙ^hTV<6*75]^rtl> ,1`rsyu7֥{v)-zl9+͎{˒]ZĞ9z'S zb iá/gqzLt0)c_D|>#_JKs΄'3m^uT[uʺ{@q/UU/'Y{SPٻUXkB?YѠWm.OӨ^kjQܖ6,ٰjmjkj=keOt52K7q9ndmкsFV}Ӣ7K(9Zu;]~U>#[/vZ|Ҟ#+*̆b|X WB6-3Ep[M]N+$yq]káS4vXh6k3$nsmM<,^ńqGݚ*qSu> WkЮ٥SNRZwT[i2ɡ>V@!W=G_ Zj*8ÜUSB?]i݈bRr9Mӊw,:Ux3T}r/-VLqw\.lsR?s^u8EQE)H%(mP;(ZC MDU$?/٦>tRzkwS4LftM5Hi 3;*Se5cBW=9s9Kkwá6n݉byϑ1$ϰeCp' B f#6~1GToSB~--Q6a}t2kt78^zSFǜ5ȋSlmƬ_=ؓ)`Tn]ٻY3ܻ sޭX)4Ȯ-iq3t}eץYۦ/>WdCB!W6[[w%Ock4ٙ&÷.rpQq-_/i? T:˵u40x鱋7"ƪ[qE= =ٻVa<`cppRK !Bo S+';-ыYagƆ~upVv2RC Y`BynvSNTB!}m$}}xѐEfI^]nG0 2vvWaζⰽBI<brryu[4R= Urm}(B!!W4}kff*sWMEt,[ܠX(i\NӴbNs^u8b^=P%}J{e? +Bkgf0e)USB:eB{?gj@vOWɤ_: waaWMҽ~aZA'+O]=4+lğX8̿^>0MYك=_wZ[B%> #V(]@&v98Qmt) LLGUD>@_[ >@ -͌f7"W[9Ib?p16:$<#"x 5@ZhRfdoCOغض fE^_w q)#[!BpUkP?ҡC' !w:sගaIg8/-]+Ru,]6j׹Dm~Cc\F8{WEF6qߴˍc[ǑYW *p;pobe?㸢`YLŻvK6#NNe;vOaZ5Z6ئ?Ϋ8͐j0rjzu=`kɟ_zO3|2Bߏ{Jՠ"T5TNG%ؼO U3#kB_!`#C_g!B"#pRME|XkB!ahB!ahB!ahB!0[tr USB:&!5$<!CCB!T CCB!T CCB!T CCB!T CCB!T 'A/Y_5 Hhtj*BU'XkB?U@?LcL3j^xȔCٱz}k)~Z@r IDAT[ :T 7q?[k ?~h\W]9vڪy!SmE nKj5٣S4TVנէԇY ;Po>2Y՜U#&#ߦ<2P&O!yo8:uF!%%P5M{ Q]]rȑ#uQCbl3JCC(jUA_˲Fi5&~ehhL͙թjyɷ.4$jjyH)IZ0D ?P"Z*99Y(Z[[ EݻVZ?WRRׯ]pBlmPA7IJ1E& IٲUZD&pjp 5ʳ=) sGPO(L Wmbg:$nk,hZ^9rM}4 D;ȲɛVJ.[5%>fTWZItԛoǥ`1ŕJCm*p3lVg2!jӻh~,m{7'jH)x+@ (ȕz.mTIdk/ 6'2 u8B`Ⓥ<ѠUG밑젔;GdDJ;jjPVQi gwL,|^ΰ$grOgf}uCbNC)Nau5f56P\Ǣk"; 0+)0192sSt$CKeu] EB`;1P'F‚D$+ 9;kn[Zk i%},ӫHIjAW @hT}eh0LZZZTTL>}…\.W@\\"47o^޽U.]\\_BAp$m[kD\+|XrMo{/&vG>c)s ~ d [@ԯ ;,j75?p>CnFϿV[Ё4ohS-4yqJwpf.hvSVQ-)Qkv-rE]kjaΆT0o5F]PuŵqqqÇW*dee:uҥK8pRYB9뗎V< zRR0&9li"Ehw2G:r&] +fK*Y'7dɊAbF#u H()@H9QU!+5TlYXeC )#^-j2BcRl0R'  Hcu8^]gd,i~H-⳯fKwTy++aIe6C6Y8rU,-ؼ)i@jņ$,a@Պ;%/+2:U6e(+C9@5USʅsUVݻСC/_lllcǎ1Mvv N>B0g}҅*J~_xDsO)yP' Sn.^ i5 z+#+UrO7Ps$J@zHͥ!GC||͸5) >!Lx8$ٺzA3Ds\h\oMH3a L^nњm{AW$-(dϺ{FloN5TcVFeàT-)M 95?E!Ⱦm4j%8 AYOY$YO`t*iCUWRfKԇw@izUqtH!( E.`\lMP/{]tI&mvIq?A[8q;wҾ`䌌Shhh$&&Κ5O>Ȋeռʱ'E=-[эv{{ hET *PoNS ظw_T':+lGLmu I+hF΀uP֟ @,Cdڊ5 Zhl&H$?$m{E6u9rOQM3\遻{e0}v}ޕ)Y)EtޖiB5e􃘂OCHh//.zQR-I#&mMr̕슒'誏4&u`cS Ԙ^g &.hu./6\ɑ7"MP1Z_ɓgi@E{WwNj@Pcٔ\酨 E ?-_FxVޕTtWpɄD|Q%_߾}CBB뛕լYÇ5* `ᚚM6UkҤ U#322Mv9@KKkŊ3gp޽{xxj~-L5C_TmAJ)J/(iZ.4X1pTׇ Pp$\6m'51]^Hꡚ<#.á((P+/ ZC>yyym۶ܹw z222O~9sΝe˖Q5m4jꍨ! dR 8r!=ƅAt6 |Mhט=rT5_?ѣG/^QrVzo555-/RҸpʔ)^^^Ǐ{… I2e F!Ct2X6!]E8S +( >>/VPOOOo5}gR5yd///MMMSSÇ3&**jg>!~qt޸hTr_Q|ٸVZ͜9SMM-44յ Eə:u3gqʕ+555Y͚5m߾H$<|D!BАYf-_0##GegΜ!I}ժUOdYI&'OlժH$;w8 B/ {zz/Z&'*I&y{{ Hlٲ#G^peF7o\$yxx;vL1~!B}/  -[N:UCCrJïSPP~i &N~z Xtҝ;w41a„K.@Æ Ϟ=ۼyBG2OqDA5ߟwTWwf#`H" * X`(-HlĆ{7J һewc`f ,>dzνwFa?)v ,222""~ʕ+rϟϝ; ///g!e1*z+Buv!@vN#G>}[(D)))/^d"ooh |||mFo߾](FGGlٲp̘1ϟ6mڜܭ[ `:D!N(_r\.w޼ySN޽{EEwVSSSoTg N>=::$I&m޼|__P@0f̘ 'XXXDEE3&%%姟~trrj׮ŋS5jxnaW!7NhWVVֱcy'8΀<==\9Μ9- \"ݷl٢\N߿0aBxx̶o斑0lذ͛3BgmeɮB W^@.]tttXM}xYYYEEE&9:wlll =x"_w%+,-->lddW\\|ȑ<ciiـB!P,r\`7t̬[nZZZ6:uҺu댌 //;v 6Hͅ4+++.9ezEP^!BFhح[7x۷oYMڵ;qDddI lmmMLL6QWWԬ.MҏIOO?q@ pqqٶmB_B!S,6LWWYhY#ѷo={jՊ$I&i\.΅M4a7#BQ6ssI&mٲرcw-))a};vΝ;ϟ? b7RTT4l0!BS( ,Y"BCCoHԀ>ҭ[nݺZP=zkB!; ׯ4i!B}@ڵkm!BUhXYYy //>oaÆ\v?B!MQZC˛5kVtttee%].[l߾}{챲ٽ޼yB?FQ|I7!nޓ]cW!WC^TQQx⨨(ܹ_UYY٩SW^%''O81&&iԨA׮]cIZlF/I2ʋuf;b6ބyxti@wзMhxÇĉϟomm]XX8sLMMɓ''''֭#7.==>U]ufډ N2I@GEEk&{؛4bw&\(UYQI-#.=M-5sN2Wk)a&Vv6#oWŢalllQQǣ\Fuҥ .̟?_ժy6mb"зC<5(uPdvud!?>K<nZvv0yE3T[ߊ0rܴ6?WVP)$u~ֆG0E]`}*e%)ݟ?]veM1p@%%BfB}޿' $OӨo߀aﳛfg7uZ7eUD772 (m*9o{._]4=isz;91h`>M H̠W࿏8 kN*R"Ehk;pL Bw"iːU HK2վA#l] c^Go{V~mS!*|D_^3Gm7xBwW>9VvV)3g𪳷#vO 7ڱ?Z2hF9?Bp[Xҽ몟0R,affֲeKccF!onS<|҃[OPp =VF_xtmʖ9[n|RQÝsּpX2c 7\ny!L}^Q#.T=iCYڧWF':m y\To6p%~rwn7MVԙV#4Kg~|EU8L=63 >wݓ]pӣIvusK:qFzkB]?Ӓ?|,TNR6n4'{C@yۖ*vfxiֹjl}944͛7+W7oHŤB!rs Uuu:moM*_䕈@@z4xUnl"#2~_Z: ArUqDחNWJJmh)=;DTe9EI *@45X1QPmPQ&y[E*|xM-qnV/cX#v4keHo|~շգ$=~?PygW=0( mllƎgϞ𤤤RvB )D IłN\V~F'PY<!9pپ1-5l$IPէ E$#Ui}aM@YU!ɣ TA k|HRKG#?+G!R*"6BEy~c$&AT;R]G/QIq P,+++[nر$I>}6BH Y6PenZ1cÃSiC_@TQ8 z=VO78r@y Gs(x{]ŇD@$UKʔӓ_>< lylJ}`|[T>43lAj%2O]QKr+~w>Rީ_-z?9E|!mVڪڛ4՞vVyg"ϧ9b_O)6k:::aaaF ?{,%!0T"IDATde< r"8:v^X\uqٮ?8fq; U- {:6pd7#oz@_S͠6g]uٴ$tsxb!WeN,tYn[2cj5vXk?ۭ͗5WƣMxnkN;Aw^7_Un׉vXNwWhʴa[W_Nt^)ڛkCZo߼6-m\rTK26ٳf7۷oMMMy<^ll_/ַoDv[CKr9\.'4f"8]Q BP BkZA ºECT\O9k[4r`K L P(LJJ,..]v ѣG#P{Zg;tzjԩ`llbhh2u7o***k׮[ Sy֦Mص1gv-B!Pf͚8qbΝ$!BUl2ycǎijjB;P& ʆ eH$zYtttii)DEE:88x' 4iu?COOZM-zZAAmۄB… OvsM 044>a!!'plǁ_L9oT5v證ұ$fΐ6GC~hZ B S,>yd֭K.9rdaaoaa .]o߾sWICCcԨQ RMrI$I̙3R'͵޾@񜜜>vE// &ռY3v3!+pTtZtvaI#vǯm…"]5,r'T1 6T<9oCrQW.]geΖ%DEwYa6U5o7B`Й3G%\zzӾPߵOO tL>#C:n Wx*ǭ}6y4kՎ>O90yaJ99bɋ g4fNH]gfǎ" uZ*"3ۜ>Q9VϏ"~yҹ -ɬ7әLBb욞dST˱?w^HίNsR(?!8$cXqҎKl6K g"g7G"93J:u@P$,8 @$cVNE1<{diiQǛBk&g BN+<{ݥݿ{;ܾw3hjJ:pu4*+O](sWmx%/]u !x}`+6OԞtN.&Bּ |h3 2)HK/grzzt" ֮=s._~IqFzkB]?Ӓ?]~h&}vٻoR˼o7, gܳWkM.j2@6QޕSI\';*]QN.-~p7$1R;=%]i4:0|enw9|2VUy7.>65S< Hm3uwLNb3);'/5lB~rb<8"""99y׮]&3df B{j7""*h5d(S9tW&U+0hJSEI-]ArUW1rH( ss?\_>:_ +)t"ut8P%'utI$IBCZ6$D/bc/%8DYF&e'E*/;"9|S$,v,) ׸{j&:'IfNVUS*/oWuuvq ~?~͑'R}3(k7j۾u*tf z'vvvϟ_lٍ7| з Lѭ8ٻcx~(7!6XЉK*+=ט"$4.7&y޴e;6W#$Im|e"m>8#V[ؓP'_7H}XoN -qcjl$ nb?mKo8u`A>Hhhr)hJqlzbxsR/ć>3N(khhl߾Ғ:u!cCV{D;h.r_8bƆL"67Q#aqB{gK~;R]_O6^(7oqobc\Rp8QH!٫\yhӓ_@NNPWaұ: œ;n瘥 9[9|u@gL~_xx+95/{w*1G$zu|u56ݺ}ǴMk$9˥ gAJfG"5$i```iiy退ӕVTTB0 `/+55ڵkAڲBH*C $Iy?BAT{ͺ4V&Jߝw6OzόNt;WYYyҥ0$ºW~ "...,,ŋ;1%5jԨwƍ344d!̅aB0!i?nqگ1]I׈MHOЩS͛7kBG̈pBMơ8˘E:fп ~B椂*ITSkC/"E9jjj8:Z% 2b!M#tDDS᧥?)_}[7BSSSki؂2'j>Č( !B 942zH?~P(+U[ W Ԙ8}/G';In Ɂ! NH(D₸? JD8ZG땨W1Vx& !T6M(N{dY*f4$/ӡd4Ę3e+q+] M1$Y0"Q3#҃LG@zGF:ҭt. t0"$317f'B8^dnɇ!>"j>ΐN{Wq.>+]D̹Cq= u *8I t s;2 !B{GHGW!|RV:t}?xd Bɬ& dGXq%+}Q"J!jAԜ2ke#N8}LĕA}3V '.0'YYO `4D*֫8xPj.d2 RoE?F~n2CU\`N(ҕ\|eXeFC~&Na7!EHDFz4b8q U,t=T;$^2̉S Yc*h(?:ec&k'-m3UvWQS `!U!$Rd]4"IJhoDj.ZFjzwR_i2sEqArՄ>92m/ʼk3 B_7B"JM̞WxEf= 'X$]#g.zy ;C*#aJǏK7L,=|jНL~*NѾ>:}'*~vdK/f.nB DCVEiO* KX_E]af9)16B5' Y"#^je,CL~(IV=5P4Zzu᤮ǺI6m4+}GrGS=٤i-ިC;~ 9awgYڹ LӫevQѵӂ':іzFNjzIJ/phr,#GFZqcYF.!$Q1Ou6uP֪@!\(yde&n*8-K:F!9C"@7ψ!EIudK]DR5H4$jpf-5bfU)^ak}սſd 5xYY"hyIRCWWU/*)*z:£9dЧ%^dBq=BH>YN%Y\Zjo 7^- 5Zw6 As3Z&XBKGMr D"Y}TztĄDUL ^+zΝj` Avҁkcѭ Dy-zE$q ]\!$CFG5E5H5S0aâ?-]a~hFij63׍lp kWcX_}>;]k}_д<h/Bߐo5!BshB!`4D!BU0"B* B!P!B FCB!T!B!!BUhB!`4D!BU0"B* B!P!B FCB!T!B!!BUhB!`4D!BU0"B* B!P!B FCB!T&2z8IENDB`kraft-1.1/manual/images/de/followup_2.png000066400000000000000000001322041450127457600204070ustar00rootroot00000000000000PNG  IHDR8 pHYs+ IDATx^uxoRwwB K(-;(n]wwww)Z"PwGvvw܏WɋWLpER `3'COz7!gĤbcG[yYHҤ85FGit7݁ϫapźxߎ]wL5o>p8;ץee}fJho]}!c{7Fyyn{99o&؃Ogm:v*ˣW΋Wmϗͨؠ?[UݱVMKJv?di.͛y'B#(Ѹ- Wߺ`o8Sh.E::5n),@c`:>&s頣45:3$ӸKY:FNur ^YZkhj3*b>9b4F Ű%$}bq556RV-ձ (ٷyŒy<Ϯ^{'|K[g9q_|m`3pؿƏvNVr:ZBЭKߞڐ'O 3SAB}[]vn PYy9ǫaӨWdžE)  Ը f분,Vkڒvr_0w]LFGi f:93ڴj14EK#YL&03v/0H®XS=@s"4-u%g@YM)H=[8zN.Jpƅ7)KSbH~6}{u7>{4] GbhSm:[vcF 135=z|HXO3^]13|pC\mЇcΗJJ d[پSԪ%󆎞LnF̻wojjj߾LM2v?B_ՙ8z@(~{wԴtG{;%%][סp&^?~"=G+K)FƕKRRWzޥ7fdd vlܴcؿ֯k3i悬z 4njj?hkWޟpGX[B.͛$'}zti]GNЙcb2,xL# ɸZ[s9OaDݚ87,.)i޾;t Bǧ:T5UfBqͻRSpjЮ\\R)SE%Q1FtzVvGD"*+;7<:L2 R[|ï\p5kBnWnʬps qy&QWW ؃(v"77w#8wҦ>Iwq5T}AdQi:Ҡ *ØAN(.[FDQ|2 oPMSRY$zpAQ~]CBEbUJ(;+\uׁo@ $|ej{Ff dPW ,̏N#@Ť>?}afݼۺ\z((,(444`&%]9{3`7s5߭eW^݌ Sc;#V PpPtuNt}'w$IR(V3`F_quVB{MT;s^ϟ3m DbItuUXmMHˣ(jl{#=AzNgt  ituuhEfd= Y*$A8;54kڥ +I-5f&hme&O/(s85qn8u[v}=XBHWGmk]i/B%~=|*#b-: m,cY9d敜ܰBt`"csMd%=}k9k7m******MMLں$NG[݇O|>oyN***<!Ҽ c6lەFOjjQ1E4nD_+Aɥ+[޾۳ I|z0b耾F!MM k+ $*CiRe~I\1q]rklx`UBwmZt7| V/1R1_SY^~ R1ralADt @*&3xf*MM&"D@$/ϲ а]Ġ<<ۤ#7n1q<,B2uShđfNIMO_uWRm:snn޺;G2sIA4A~~՛5dab1-qee<~ԙC{rrN_g]&?lY29LU455I$rtBA'ʱ4D6`WH,+ʹ,/-Ew_T Aմ@qKtZhYVVfeiSuձ)//OIK}SNbFN sU)6l]:VձZQQےS+5{NNG2!`p4444^cFA#>>0!֪cC t:w0mXWXTwWw?`}=# E/ m݅whaQ-6qlCGash&'ݭ>*JT'!o1ֱOKDP͈Yq| s [S/[Թ{[Fۏ1 Q11Bhf4`knvfXp-~DB-a 'S0 0 !>~0D?L@wU*-]9aaU堋!07Q90 0 þ\dD\`=Iae0 0 þ@K.R|\"^y| 0 0; b>zO [O&{aaQt\KY'"\ݺu!QȑI+IG^s7ـ#?*~pʓoAv}wsWV*ޚĪm|wNhƕaaUZ/i"A7Rqp?QwV//OҸ5Py=7wӒTk0Cx:Ϻ0ŨȰmP%i1aa`T(gӱENݱ$/ st"Ұ^*r yjZܡ_&ouʳǪCj@0 ðSTB @\^| U6hĩ EM9Df3c"D@Z6)A5cBDRu,qJ~)玍AO^+Gm~^uPW~WM^;|U|6کţ 8E;^_ aS{ZdWaﳳ1'PVZF+6.Z%_ZZh$.ܳ&qXmߋcѪ%+:$t@ڎ{-5U ^(?uK?JRԶI#dQM;w&-M~6ʭg| \$H}}x_(a/@]O_117$7V%)-"!!~sw5{k*pq𙳨sfTU,o3m]Ƥ}p6^C%__ݸ/hY7hֶgTS+G@|hSnÿ6C&q"RKߞm-dJ(x7 IDAT:}W,\̔1 P O/|RյiѻmئuwMz,[կd҂;’)u}x$@z_T B _=wyEv} ]bϛrNӋkίwLH4aw^E$ M3}Z/$*][:nBEqO^,X9׽t+ͱ;[Z{ۗ[puKs\2kN9_ϪA>]0S#NaŘrYX0,Sg|Ww̹q?8!GacNڥ_^ܸ2a}.bT5۲n哬C~5Gjl۲s>l qvh 0 '!UɑA%e!!pV%{`ُһĂ>j]MI27Sw/\=`^~aiWPY/6.D2ʇw/\>p9n]yE8kDX#D c2 ɛ_eA߾ľ<,,\09B (4Hnoݾrk̖ch*ìIC/P4|KPIڽ ƷO*xd~YzU>w͵rB͜=s_n[l~]ҬVՠW^8kp].@u5۲8\12"$]vopaX|E\5U5vVjr'~,bC!u[a`QwZQZxsZp.&Ek͌P^r|x``l^vMR4̀Ҩ&J[BN?:72&)3Қ.{hTUf>P Wx%^CfGO?!4aK}*@*wiaFfݽtͶ`.,M/Z]A)-IR K9T &έZf їHuE /n?\БW{i,9bÃ$!۠svڥqn= 9YqJ**ıѧ%߆P}iʍjy֑ ?YBl99 [z@]>Hꡲ<ݽG>&4p <姼02 7>KՀQM'|"TZtԔL}{~xNIw{ol=rb *aV\\!CZ$Fj?UK~E*IG\+݇'8է3?~HZX%SF$9SŹ\= 悀mBJc ȧ8V7I0OÿFYV>~ZX"cv .OmtSiwϠHˎl@?l&\QZυ,][ n=p)+OUEFӉ{vҨ@NZp|4Z~aȇXWs%j(?ʃ.+]; j>t{~:( UY5q,91GYV}7Eg\rBp.-G`͜Acx} Dpy*j a?->9Ȁ)tu5>{Kr~W @;9Aߨ| ԷG ?=jd΍AD僞HS*%z?@yԏ(s;ɉ/wf;_H "7ۆ.I [B%)_M0gj4ҴCrjhQ-Q8}p6 J8uI"*Gle*220}wҸgӳJc. $ O,|*"[L޴[sMp;xXgu%33ЪogF> )2kX ;H֠-R@Wg(0 ~D#;+ 운&I]zHDq8*M\=rs(C41c=rB@:r=?v{3NKaJKN*ȔŸ2SYYbRJANQiB¬Bi ayE1':J*pLY!9@b1UAN 4/Tn ʔ TTU 3-BKˊk _t1H5$jvMF&LQ9$4 9$(J\LTK:*zb Z_>Av G57UUf0a[q8Ebye.$x&N\(R8 <8Sl+85SW_B}/|3uzڰ? r#"j[KӁoTgΗI!vfAOrI^ 潛Q?"5X:E38fJmWy` dGQia 0 V9>$$A&^Fx7g!9*Z&|7ܗ~~Ć cL5vp,| úͻMXwtߤ W6ma_K.Ae>ܼ^:r}4 0 ) S(rb...>qR ;^c 0 7Uq5V+(ņZxymboi&L tr2f.1 0 Tk@õI\Z[ u[Mꭏo0 ðߖp@ƌlBXHSfxWB4 [u*Eci|sׁ1 0 wca$aaᦤ/Q{EQҗTKKea0 0 ri̻=A573cB1Ŷt/%lEEE0 0 jCWWWSS">#IR$ɏ}a>&? 0 0 =&"Qaapaaaa/JSyOLw~0 0啕Kb I Zzt0wrHaa eΧ>1 0 ð0 0 ~Q8P0 0 E@ 0 05 0 ð_0 0 ~Qv& 9ڷšW ?!O!swA)Q6_%`|z^Ï"WG}=7JQ6l! ;T7 i ?u>D~QFx,y"O6sB%O^!*^P=S|:{yvrY~b"P;k(ɞʼ<Ž͸ɒLe\~o=^g,ANoqCFpoƣ k$R*>&vޕBU+&F?R "dϖ8֫k[G]ٱTQ 5'zn[ S3L9s>WE;RX?ߏle>8pAÜ㞿F µ>߶jn]L_s[~bpN^ރgS[x״:{u;vR*/]\1O;97;Pb[7[m>_ڹK>^2h?}$xywqr+ :/ 9hΛ{Aytɩ̷gsa/WvvCw}Q/\Mӆ'm^GtiU:kۧ ٩߭wȝGaG;R+ .9wPZgӳϤϢ7zv䴏⥞uٛ&g;_ 4gt5g]:t8c+I0/%կ˪ɦΌi?~ Tٹ 8x0ݽ>KP^f6O Όi?Nd~=ƝO٥#|=z\s'"Q;{zxYp6B(*9d5^"H$Iz: 2bVr?^2ڧW'NPrxXfQΝzգUW=IKe'/9[zPv}Ql^N"SZ*ot<1m`o]z =,7Vf~+v:`"P#\\ "ޅh!\wf| 4͚?pTq.>@e>u[|Av_ 82}xӥ_)eá}MK_<\ޑa*w{ǾĩU'^&*j:oſ?YvL> |l+nRpj1eOLo@} o?|t}eo*{H:y7}1As7E7[zW'-k_{ag7kY)PaE^s㻇qn.h^aPԨх7O=?7=O ԳFw[~翯޸qvw^׷GmA==RlmPM9k[ytH祗>u`NoݽPv];+zkFm8wAT흇 2F,[6mpGUיoݸSC~t*^ۯw\w-/w2CAevp+lBg ߾I0*C?spE/'2jGʭ7n];BNjU'Ruaj/ݺzHvz xn:G~g }*p.aMs{߮U5+j6sg~p]8k*#Oyޥ]34'(ymwƭ7n^ih5Y-(9tmV_f4KA;RD YwȮk׏o'#y7nݸqyˠvթpP)7]"blBٶ_c"BC肢o_>DEeQ]kmq[~|),"حakwo Aٍ\iޤkK lKMt9@۶om޽vgcP"tna@Xy%%5{ч5nɷ鲿=tV$5, Uo~Úsphc,#h\3^>#RBݠ H uvhXmC"t<*j?bhc]Zt#o/3Իϻf2sˌV՞@Ikw:]5׸[ajj.URs,;VGqΐJѻC}p!aR?< ItaB]G0}QbQ_^Hm6h7ܿ2aijAaH T'4Z5T'iҦJvF"5_#V5oTުꪔ#P^kǠ\mޔN3j֖ IDATrW \f8Kmߚ&GJUv6y̘ӎOQN`c=-Tqk5JqGBœZTVܓ|?*z}Gu0^O#ltE~;Im+{k-RǛy[8֝3:óEHX/@fuIE+JPo7vzg[]5Ul(/`dž׍4nHya-:w ڗvDT^* 9Ѥ},ˢpQĆ|ǻ[iA鶫p߼ $9XD8jT9*K!R:N lǫsGbB koCD[w#/ߥڷmM}}|7_ fNj$nIQ2qvfN}*M )n%t $ $@Q`TBˮۤF?zѤu緒̬ԗ#PҬY kU̗AjJfHrHJ9AwHXN)vp!tH*:;_s% M QP}Q*fCjIV5IHEUԄt\]qһ3, ?Dw] m]m*342y)dhmS&jd6Q~n^=cɪ#t x-ʑ$(J.nv![ ظîOe v0=4~ݚ[vzP־#%ZjS1%PA/$lC$)*Jw__ YU&D<*iS"ӤnV<*ti mh hʚ[ ʱ.kxUܭ'201".&e?K+K2>]b\zt,rD rD~i;_n|\JP%Q+] %tseOiFan/O Us=gU[s+Yg~L(֫|{*%jԤVNl1 .M,H>Oy^=I$*M;Å}44D)*7Ɠjqs7 :cTahRpS@`!*+׷u2W%@~p)*JP@jX83P쑨8=ٱ3O9_Y&tuH] s!GܺUۊd⊖J{O\AX>=]vBM8IOwM#_:е5)W¸kNaK][QaFrF!{)Hc|)TG)@>ʈI*ڛJOy|3!N|x? 黙ۻh wTN\XBmio-UP7NhbS&lQFf/Nٽs/H&}}ûsgg[VP3rە_b'pxl R"4i@& H&R ]  i$e^˥ y\f2e88KD)3( |VJԮ*ʈ U~s@O_mh=?V%W;sԲgj~; c.<ɷuٷ`p3&'Ir ?u}+3QE\2<L EߚŗR:}Y'OՄJʾ:.X>,9kH;-h́5=RBI@ф_(a- oڡ!OwtZ(ۮo5[㌥7wZ~x#_i6 &2&8bH'>~kqaG&yqn5:'q<^h#~ډc'< 325j1kig$=#`F5~AML4g1djҜW+V8H?L?L0wF<ӌ橷;}<:rʬ.Njen+x̉ljyZf]S߶gߘ}=*4Uߏ^|"̾Uǃ_IAѧv9v=dUu7}ewuAc,~?gZ#p7Rچ3$ylm䯀?v԰u*<<eSA28LףnrØ~CW__[cV5kwScQ>xkK}[k_vN7~lEL6l$B=ݻyzzRJA 7?r}M)%˛'T%&&+CxxɪvBً|x\u0!^  ,)k k XvY.~ԆOB(l<!\9Kd3΍!B{®O B!MaPC!ʦ0!BeSB!) j!B5Bl B!P6A !B(mV+19gyc[=o_)%)'#BCQQSnlrJ([<4#IgTי~(B!4<<<<==SYO&b'B!P6A !B(A?A~g LˮfNm>;{?ժQƭFmK)rxFXY0 ,QgO<@! ѽqt8eRX5{bw- OAc ]dc6xU</:xbqђ ݎU%BvӯS% lrite{X']tM~~c-3SօGUz|< O~Y.ڂ~jND8WRM(׸ׇ[?V}:}6sW; O ,OK."oTEvc%xw{ ?;!D!?#buG9vȱ#wo4EGk1%C,įYjzɕ{Y~j<CH5ˍ߻a:uޛs""T,*Qy<*,K;z,%|*Y޿66RO}c$X_/}=Y^c}1f=xǯw߸i;𤛧M^ Sk?X2n@3<Ҁ6;cN%u_sDfBc/ ']06hԸE_H uoܢ9Vl2v;,4i.#{hkhѨa6=Fm&ڃ"QæN^w!-s {竳\mRNs;gul9 FҪaa9p?֪Iz-x Ϣ-٭E&a=ǭ9uXmn5 =uM?ś>hKj[r~nqvm|ۤ+ ]9>W9o:ԎEuF݄]k0Y W8`osZƟrhRN4{:oOH9XΛZٗkRPkD ڸZ`ĭ {{7ѢHATԶьxW~{DВD|CuA(|NU 1)ZP1!Bl jiGf [tO{X=)~gv}]wlF]GHZu׶Ճr2~H`=637޳~v۸C@_ f۞=W6.Q~Qc3"C2ϟv}oڻ}¦/LՂ$ i_ct@xn3t֐jY4ն) ׮^T(*"_UVe枭U=H)_v vk^ԃNpNϧwbSO/x3c|J]zxRGyCLW,b˧KFw,"ϢRKN ljUb6V͟.|\?tr;ۯ7 /FcB+|ѳ%:{V|`m+{Is߉ub 0O+8`+I&|w'0@"FyǡAy .&EqJz1~~mTRcGG8N~fyUi3 K>(N2>ޅ \Q/orGrdbɧ &X[ Z3] /"v)ZoK͕}ޘ^}{FS嵣GRrnef0kv p]1{Zk6i*wPťN6ɳ0IVBݿ@ H@} /5y\ /nM0x\w^g۾^u()%$h sV>XHol)W@w>UiٸzSyG ,FY__Ϻ}0͠-!Yo%jٸ.W)$StpT֯d2TAjO جVH]Sto6 #^iȨ/?e=x~ Ż(]ku(#c )D~7r{>l297tFS>ZMnlBe#@ji;Vl@9j&MʹHX~+W3O봬v}킝G]tA*_8hn<ТZ9fHΥ"jesS@oc> 9w`wU|8۾h-\կwm Y#. aP4w̕u7=}}hޖkK7|<)p䏟_O: |" yݹ~;[H!?~o]ꋷ˚ zܟǟZ4t>UdZV\Y}ǎU;n۹u,ߨv F[As9V8ȃ3ޟv5Ijݺvdzp߬>B򯵨E=`V堐>,k^DLV$ɯxh[azAeZ~0t=mK4:mUd-y۬[Ibw9IF#`?~4au=Jt:n [vhH1 EߚŗR:}Y_mڬxpF[V;;_kzU{720/8jp͝wFU\&Æ'o0W=ū/:ܗd_5:oeLi!)8"oE e )x}G" {(D$S.?_fכr@ B:TP](uQ!B.}&H%˗.E!7>&L+Z4K'+XV~5E1۬V} BoȎB!MaPC!ʦ0!BeSB!) j!B>-3gKRِ"e.Yf \ Be3r""I.1}B{hOuќZ}BZA|+y~Ttbb"50p47iB9kc1ι\fu1$5!/ X}9;?R9nPmQLyx7~4wtKΏ<|&Ÿ!BL=XBDNhQsA\+˄E428nZ8kɮъP.(fq݄=ӛmf{뫬^ڵ I~{eCgVm*9ɣ pYC;{O_]~.av{;4ؾ8ju-%?oKnU"Y(pɸSQ$swUs=U2:mBe39E- ]qu*8,1Rqڻɵo>XR'^<|FSu*arC:ʱ [c,:h{6޽eUg4²Wvߛ?jiq=dwxwݱi۴+rH_3j;鰆~;Vg MQ>_k[$5`S*4uaG-%P%Λ#:+]e{RCsNћx:UwDo+عom{m-?#C~C~f{>e%ydB%ӓqU2WA~KRk90#frdP||sv~מĺ= @tӜr9hW׎p={du ķvVE=,[JJe)k(/m;kuCXXXՇX6[|2SK'޹(+ ߶^έUv}/w^m0x-PYsph&i/;БǵE$nmB㭻y)\ԡ27V~P\Uw_HQdqzz+ߟQh'RB k뎀|W ϩGc&V$%U&9>!PNú>i-~~&[<(]<$ކ"3Ii.W*kt.Jw.YN pιİߌ<[3HQc,+kmCaS}w~m_ H.\T9ͦ,i59{n] oZ6w\0SU{;lC2mLGբ\ 0(t =g"FO0h4L?hȌrB(n@ ԨP$>α'r!czdѼeG\ Q8Jp1}pp_j`RCr4G߹e7)O 'wv?2C" hG v}Z5jԬ͡ H-~3}>DŽڵYЎ0sp&* 0ɛ21ֶ}:uo袇Bg62=bߙ*^ݫy tY]oSgC[Z{ e[f:ܡmo]4ijF,Am>!k'Ǵ~3*MW, <]RKya+tF=Ɓs`OG[|l]`kˠ]p_1;ѮߝXiEOۈh2~f_&y%hoz=F o_3M 'B }g̈6EҮoRmr@=%_/^")Y۰ެMn4uɾk bPH6(/m^wN݊gu2o@ j5oR7mJZ\jVĥ(U_pkJ3ʨQ͝?s8'jon]ԑ8,E{޼G5kˈ29n)Rqs<,iCB!sD\+zw/%9:h԰qNgo|q{lV~ꀄsۤo~yQPMj1h9;7m e_:0oP疍6 {gʝujڨY6_۫tn״Av8rvI_v;|Ss|75lдm);n''vsԁ]Z6mبe_BmAuu}3 L>͟߷%5Ozi/~T 善ި*~,աgcm*$cZH{*FoR*op:Ecoݱs;+ݻV} ̥:ҺbLW9܊с{wdE<"~5z`{O ("<B=_/:wϫ8xČK}k&׾=ocI pzM֩e(,olu-ۼ{nW FN;_iڝ7j|oF|seLۦ-]C9W6>1e (ٸgk6U.\;o':ςT*q<5/$'#-n<=Ф+}ܼD1g,FBdLw4^Y)3w [7,Qysy^zW*Mۗ?R7B!r"FWZxFJ ^N mn/OޝK*>Fz" \vJ pιİߌ<[HTo ,)6^]5wr7^3뗭Ik;f܆)  _=s&=fkpX _I۝ksOV&AxσR7\V~ -?yW$8vvXt ~A'Q%Mw[ާp->>BtT4 ('1bD98"c4{u~^;tаyÒ; Ea^ݸzۻH_+F|]7_[?, ?-J{ yMy~%C%u|FXm1^$6[fcѲXBeOq9|&->}?϶g=ږ|ިXySϽKWR8p-YݗU5E\snZJ̎owvpP~e =._28roS l <ӷ>vjMJVV0q ~g֬:W+v껵^V8;SX/~;b~RaZ6ƅMC}^)gW:a(7eܺjl*b4WEjZm'yVm!gφ/8{6|!VB(xa-jZ5TBST=rpc̜ڵYn4` |G7&iMP` Ct]5Krž3G-|vk=O-i\w*Lc茲}VLݷ )VGwz1=^n|;mu扷N=^ڲX3){zͼG~#OZo*-Ǐ7yRg|"a[P}TSҁsurHnXҵۓ͜zBB*6lƬYgφgBu}"|Ymĉ0iDLi!^#$⤉Bz`DC!21j/9+vL]&S !P%j4x3@Lyi\]q&Ag3몢j"&Y|$(=/ B/|PlJ$](B7E!`P<==<̓'d\W5DL \*ʒH p]U5q K}ušS9$YU"%gU"%!RQrvks]UU]*&0 IDAT]UU8_\H^~Z̗93_:U˦K݌x5m-]9j'::!P.7޶Yqm#Ao{UJ5l$ ["p`7/_ ULo8`JC!-e|{o%>;Sd!kWLrR, ##u{TԣEZq=B!( vh>,&f\WT0^ !B/ܚdxXq$!*DGB!sE97I(Z@|@;7o5}B!zU+W_Y!`Fn=3HJt؃-(wr=۾cuINkW~ya2٢Eb?oK ܡKv 孱=<-GӨLjBOwAՎݪ@<ԯY:POW暑纪1"P PA2fI$%חkN$bQ(!l6MbӂPѹD>4i\f% zru"+lqCq<嚪h fb2IpMQt"fIkxW?vIoI+un^@װ='M?A%ItU5ofTB849̀spf'ؔWL%Q뜊sךB8OS9O38쩅O^/B($.LhWSَ_y?aĿvc<8d2@sz\+Zzz' ?U~guZVvk ٣\kͼLI_TEaDM&lrJ2 m\S `u:)Mdi-#ιqvԦ9 !_w_v@)e̢AML0uF.n΅)P]zK5ksZuxϔr]ד^}79soNJ.N]k4]'UEՁ T\eYvdKEe =y5'tb2k;-XLSMPQ6I$ ik5]LWUUg I=tŮg9TUBEI,bs RB8S)ܚ3BemnӻWOOOOA(R BJGْA$ \Jf)esmkg7M2ef5#vѴG19e#BEٔv BJF!B5Bl B!P6A !B( B!MaPC!ʦ0!BeSB!) j!B5Bl B!P6A !B( B!MaPCEUCe!P:{xM$]'ȖULgDVk*J$⿑B= j/*M"Ι(JL3Cv*UKA ;QJB !!T2h"h@0%4UږuUQu@ \eYg9$Iot*?sceIJNv%*F IE|IQI ٵhQ_TTlهY}v؍Ό#\g3yusnCC߲om#܆ؖﷴ:NR*U5Q6%ZfD+TЏjӥmm?`k-|eUU,_zpv6|ހ/ez"ǩdeh1YtpdD=˗WH!@l2]ʻ A le -b[~tGDJ|#"M%|>p)R`\sŵF<mmJ#ږ㧍U 1te\h:`OQ{R箪D6=;''"ғiheP-eFb~-kV剈0Z8u\NvNBAcҼހ6LTJD+ԷL˰-Kh˲3ʕrHy/LTekQJuJ(DVfQeȳ03+3^D:۲Y5 *4efp.> [GҶE!Vڲl4ؖ%+}\.S@貼۲̘C)u:.@6 )##kLQ \咕r.nIJ(ǣ7]+v~1L; 򪪶2G>Eۡ?$LYې9-{uoUx LuTu^CΪhuX=QG#DF^ ʳ-E)ÕyXVa=[~(>/;f}>ۈx %3, Ky,mzN:UDOa,SY#˾^L!9{;: />/8t:_[@p.8h2˃/rX<֡H(gh2 $[܉ȩh;4)"%ylU=`l:<'`.eYKaXbiX9Dnm8: 7z._œY4߯]3nyӵH UtGx\Yg@FP+L#I(WDTc+am7Neq劈 [ᎈ +ǫjH9?-GrpGFfL]Um°59X"¶Zc Q<@!́6s|G;Q(zb(FZ 29s= 1c[ȉP5/=ǝ'ɝPУP5"8A jEPp(N@yLeJ)! }Y[zGZlsDDlMP_CZeʥVb*Q"Z J{yrPs*z%`k[DDyL,mH J&BS)Z!"f!"J)LK[ZPa >Ki(º\23f~KҶi(/I sLkxaJD%5J"e(2.Gl*PՂ7 uM,-PL[jٺ2{,-RJkDIK1o!f2 g'Gkц"+8ÓɸMDB-Gt@>C`P*wL:cbi%(ftΠsPϜ-QH*8[稉P>D=]!:~}@NaX3',y=l(N1~lV V(幯A@:i pFGvd7QGP+R‰gGP.D4(F q5\hhP Ɂ#@ADP+lHlȎ|A~&]PgPh.(jEPp(CP5"8A jEPp(CP5"8A jEPp(CP5"8A jEPp(CP5"8A jEPp(CP5"8A jEPp(CP5"8A jEPp(CP5"8A jEPp(CP5"8A jEPp(CP5"8A jEPp(CP5"8A jEPp(CP5"8A jEPp(CP5"8A jEP+LI/Ŗ^KWx N#L]3%|.CR."!l.|<>O"8A jEPp(C(NNNg-*2rˋ+>!(6m\\RJOo߾m۷UrLLLsO\JJ ) @>)]tjjZӣZk^J~08A @!@>72 }(P@ve(jDl pHiU~62/ PړxW߈It+@pڶ$4iq_G jΞf@~唒ӹu>w>wyˎ놅s6 LY4^ Nn;Zxc{_}6{n Aď{76{W1G{M=gmM d2 =y5*|w|~u__a6w>6rϧp%^%kCiRںeK-76ﳮ[g;"5|C!ުiZtWmM 6pKV,@u݉_}je kYtnT^9QvhRQ;ٻ:񫑝?|owu[ˋZCSҺI4$-"y͚6iޱ۠yT_k^حcfk~ݘmIN<ّ41*QO&|W%ӏi8xշ|zk]mJIN+=ּ5]Vx#۶msU۴,w[ЬyKT7{G o:s@cSZ#Wsϗ{Z=kVoUjV(ǣN*_zax<}o_|EZ<FV{No}p+)We'm៊pU=[q/,y/.~b5_˘įNßYG6?m"֡_7%~Wt%?a}eɓ@vܿTG#sΜvYՁ*F}5}씏'݈Ԩk^VQYUELr]\kw_UL;guMw}:Uֽ5vֻ҇3w(}j%+Gc 㓉gٞdҦs=uWIDD'`GQv^Փ_|!L/v886uMڦycfg;V^+io _+6d?r7.Wf/u=b~k=""i_9d~jM[!DՖ( lxx/OzL}z7;]ya;Td~ȫ6v,yWnK,]CS)l|oܤHD{8\wr>} j{쇺e֑;g=ַ,䈊{<{sWfG*]AV+">"qȜC6bCk0r [[3{񶋯`V3|UܥV,36WAo9Ï>zW櫻&/^d֓V ~qֽ#o,Zj l2Y(R}3|ن`OY|mTvu"?̘WzohsR߉RH_x0?k]&.\b~ ߽ÐofIZDߖ/[m8PD}ezN_tm6L0X9t}l u9,[k6u?j޷UZj'˯7y1-q>4N]ju~zo[DD'g{>?_uwR`ŊO^ /wٷhs =],^j-m`΋}oػ-ݳW/>2xwUJňoؔ*{Ǫ[@/jީ^٦%H{<.*~*./bEwj_e_ o|_hݰa6<7Ha>^җ=~ђw_Q!%ErѷenޢGu;,mtWbnrmޝقxjcԗ˾OI.6UW%7k8S*voV.7V-Ɛ U4ls5.q{+[L/^2 >WkDGEzW}.Uc [kgDUrk1Ĉ\{V,bT&5eZ6vTT/x{G[%>p1Q/^}}uM1ոJDᯖoe#xJ7xk_ 9ا[pcuNKܥoYxĈA}gOotd[8&EVTf.0ԬY޽g`J{wlujbM-yCc-.]"֑C vH( xDTbUTq/ٚl;IDDk_ls2t`޵O[\3.:54x\OVe]ONx9Rm[9Y|xlіϬ%BĈ+9Aڶ|ٷI je>z)#UJF%[h1A`J mbaiԺu~~y>[?PbE2Dzꠊ(m?~欕{ S%N=VKJE\Ҷv#VɫB*d9މ1V(Z#NJ.ZSd1D#KҡQѥJG=tĖKDT7ƋlHmJ""0 S,#}OwewC11rH㲅@⑤wh24D6 8w#"F~_k-*\٨!V;5%UD`֒.◖4C +Q­lo^5mzS~ x[>UHo~tܥHoRZJ U}gE=:G"Y~wt84(+%%H\jԨѻw&KD&Lxw^5j= ;%cÿP>tC6wvțէ>R=ʌO(yX%"}%Ad}a["8ሸlq%?9R(Zxd{pZ#[u;aƠMU%t2_S&u.uȉ7*i[_H^cv}"F|rSD>dx W(wc+fZYdеEDP$Ulc["7%%ED'̻Fo-|_ i?5k\Ԉ.k>xXKNIN w"bk1Kv+HQd Y~["K)^;0m2~i'|! C[b[{s83٧y48whkwS18'"Y3Knm ryeQQ%lQTG:5)ɟs`.5*+h~7xͯ/l:ws.:*}!2珿| pH{ڷiN>}no>|9CSR(R.h5kݻ#DdР5k׾Ρb<6⾈QmTlѡ9o[]8%"oNuTæ5WZ?/w"v-p7Kx_Dȟ8oV?JD^qq//}*٨}?N^G-bضuwe[SlٮEiCD\۵_;sOI}Rykdd(Ӽm-MݼM%՚60?p{Do.T۳zن'uM,rO$pK)b !; ۩7WJ9?WiӬBwB%,Agm>T|[7&">ZsweO' *h^qۃM3h'?M[Ŀ9xԚRtoƨؼycmg˶<L*B;,j-#?ưyu3g͜9k7oۓ帴_ϯo}5"iiiii>KTLVw-|~ݽj'굨SDҶ⏾xX_ZZZZ7>'lo1dȭ*/]\YRFA8Ȝ;G-{k=M#M)z ]hUR-6)i[Lr{7($kXϬxWyp߈ώ\:rUA6_'Վ#ß؉s1*Y+!D&0U.1.n@/>~vvԉutLҾϋW=gW V F6 l<պ~~n?݈cc>Z$iTm]ZWFz7x}oE(]b)v/o_׭#|ݎtm9 Xwn#z~ipykuzKSDHhc&83Ti4tѨ6 +)smJ&'n]]뉹dG~`w؏N۟\ N5$fPZ۶,`YVfIfeY)))o=#|57?վW^E]>td "e37-w=\{]+9. g5lzyGxy|RӉ;npk׮R醖nmaa_,4 ,NBj)"|:i$["8a%k]U}h-Sm셿_vM"k߫ۺ@)ߞSwҀV]_O*.Kr_^3iRmr]U?.u'ۑ OBVu ]MD忣Xgg՗ս}K TS -:zRr yr9Q-=o^N7~O&|!o /P;AMDbbb>~_@F5W0* @FP }(䢢WT p_,XxCPPUZ-[~ p֊T۝__"CPPVV-999| n'jAPPl 78A jEPp(CP5"8A j°\tpIENDB`kraft-1.1/manual/images/de/numbercycles.png000066400000000000000000000434031450127457600210140ustar00rootroot00000000000000PNG  IHDRaJ# pHYs+ IDATxg\V_r!2q lAT@Vhu֭ZܳEAE{=Z" [$ {s/$$$*I샸U B7od]WBc&BXAD aA!,C"AtH A!‚ :$BXAD aA!,C"AtH A!‚ :gj|2IIzV /?+UFsN˗.bUBzV /u^/]jʺJ~:HLJ,B`eUD]W 9M.!,C"AtH A!‚ :$B-(WcԷ+ 5~̿ߊŸZ7,w%߬XtAȅ>kVړt]Jca!`JU@uʙI`Sy=dӰ{>*\]؉6ϣHGި_uq1: |V!-s~s/}O|$ I(I&%uYlW2kQ Û N}ۏdOL\;ESwtaSf BXQH Y%r  IHe(wzbZ;;`ԏ!Γw9jY8.VtuBG7o:d%iD|l ]^̀K8m }Zz.w+mf]Pc9{ڸ9MqX9%='3%K' Gw|zN!FګWlEa*x;B% ',7͜iIIVx_/(Kn:{f lʕD\Nx[.OdMH̍reJPqjgd™:^J@nNgS<|\5&Xiי*P j|~;W2˂e* o='o",tcj`}rat0kAm@cטexH>{`zLՌuMk-'c]nͅS+v'd&-2eݿ(V#}1YPDZNfMX!v7̌fX .*Lj| [3I//+^5R9&R3B%1O텥^ԒZWټ YUdd f&@%UEE!^4/.ڇzTKL(V6Ѻ!پ(ŗ1 *L0>ieP%s7_I|+N~O=(!bQCŌXM'>-XbiY1lTڣpC@U=~h bP);5jKsCe߮e~'1ߑ x+K8x T&h2if}Bz fjT@~%~|D--0 fiҋYkV߻2 (Err,R\F o@k}Ą_x5qER*Jz:?Zo _ Ʉ-]߉*hkgҫGscB-TTTq|8'T@%&BkM1Q頪O[D/aǍT@Kԡ]foBY9PSc5bAUm"/̸iOζ aiߒF3?:)*egܙҙ{dVB뇲x'ƲBԿiJ .]zklEs3.^& Pw, (V܂ȓRr%(cnDL4mQy"?Ns z6w©巬2nW}juZ;v4i?ǣQfP.nN.[tsfn7\p̒l: S|lIZzM0WQ"F*Z'O(U*WLUy'"ʉ(Q [*;s.]jʘޏ֊ᣒ 8&)1)_ՈqQUTUu-%lKA!G%)#r>."<=E >**;"/ [Rs%r  I3ҞfF&H3ݴw׾j4fUSWxf5f|im=p8rj,mX>x< #"fNv,h޳/etô/ez m'tï)-5/9/$Rvu$}pw$={hD5:M' ^w ߾],A=m<&993C=tN_q(94Z+6%i?$2.;N`y4αq*Xv6)crit&p|ڵn_8oh@cjvK\wyh₋?Ö{_;M K[oۃ_oӬ-j=;<&p0Sӹ2sswhZ{oQR_PL@N:qN:E@-Vbhϒ<#oǛv7EؿiZƒX fp/x9k[;AA_$ vf}RD@Ɗa#][P a;JL4r T|rc3uu;ۘۑG],)G8536 TG0ҷcؼu }N+-k"(5p ;Ã$}zڼ{?F['DVJl0u26OUF[ʔu%֋rsFSRv$;yD2+'u(k-{yW<3Gf(Q;0t-t,m~d](dSa\=Sׯk'7akVmJNNr6C]KXqؾVҫgOL ?}4SЫgO uP/g0BVU|g'm ѫFu)cWEC&mq,6v1uIO=Ϩf"Ai>-j Z֍Xj(AէXAMWٻYǙd@RC}Mf߁ ١"ׯ?vѫg`ɨ,~#8g3k $ ZnuGD6o=Bdiʔ2}PphC˲$c`ow`P1 r֣KB휋E];j7Ǯe$$J8/^E%z.NmMW"#S/w^'~[ߝuho4iצPs+xե8>Y'X Zc2Ek}Je|HSA]J%*/4޳5k/ ~ԬYS5r#jrq| Om+B\>b/`GYLRPtߋ&|<{S5TILDQ fud@-YȆWSd^-cx*꣮2x;\~?O5K)`ʔF/~06{<*`1ez=b 1ח06ՆB)ä;=&U1 YP-J/Yf$MwVQ(PDΘ>1E-з#a!z_I'Q5Ψ9}Y2I\Z:q6נ\[L.,goqĩls5 رԬw[Yrlw#2%Z {mL]}%)z3Ubq1+史`'+B}:=j?_jD|2<eӂ!^]$EN]O gYŌѦ$7Sus0۶)șj7}Y]0ݷ^]⋖^S1 c*$\bīu(hׂzb+>H~^ b/QP9c/Wf4E(Q>gN8Yk+ 057!%n0Y&?8/@.oŏTȝ>}2zX[| caVG,8tk1ZEkn/T~qU~ x=7O) ̔1bUՋ?Vh(}CjdD:!SyDLeh:uMzx ﺭmMLlK>_M5 GKW ӫJ}i$mV'cP&-;xS$PU$+wFClu_}U!iu^ڟuaL:}&TnٌR)ZșI ̜PL]Ju 4 ͹ը^',4A3;v8 {_ 3;;/!#Q L?^E7ӡGz} GOř#p$] aq=jT%rbbr>5S+F3` *Q1>i9_`VQ|<%E 92~.O@tG [-a##D߼%/lO‚ :$#JFܹs…u]ݹ{3S]W㝉>*5Ws\tYUޑ)*@Uy'"9j$!!AULLrwkX111ws :$BXAD aA!,C"AtH A!‚ :7CXfx:;شˮArpdoy±72j]Mmo)|;/N޸3"F*S!6P4h[7c]Z$}7$zSV5ʄ&Cu a谍(ך!spc_QĴ>mqwvCV';⯮w˖9V Gnv@{6q~۱a@6݄bnϞ>g֖,^=l[1췍ܽ% \Ʃ7$nF#~Yt #96hFFv~[kv}hQףJseٷ/^< z4$p` f}&B1 _ο~s#VI|13}o_V3k޺M :5{ӏ B.*k_u!:#cA?6d3 L.) $5N |u1p~iԠΧ5;A9Ǿ*`}ٹO @fHr 憔?U"g߼uY&w{KzS?Eк{7ƹU`%3!h9X(+&N%6ǃz(w.rz@>˲T.f6- 0[od8Y!K&4ٕ+8e]2`D/6bÿe f]LE.ArG IDATOQÕ'6e4_ !ts~m#.g\ttߏrčrr}fGGGW3'ޓȅQ5Yc_D$,QU4uPZ0^Eg{{wbĿ$b{ŋ(W8rcEXrIUv>{wǎAzk9BځxL2%pT]:|[]Wys伖pΓ'sA*]`eC wc.Iߘ0Vs%]p5Math/'N֙9S%}QS}iUߕx~)߶mOovA]TD퀠Ǿ(f)y;ݥ`񴙳c3hk~~V7JhD5}+=bc! \SgX8-z6*gJCW tt/8/F+%i?$@\B' \6?&9 ΝZp8;v&eL=M`O@8:8- \hޑ6_n+2oM]\pgә' -h6&ËqxNYr$^nۻ=; |ˏjt}2B:_?n;:ӴẅI⧲w;֟`~4߶֘i|\ppmCGxU#: 'O./3?> 7ݼ<~33ʽ8n[]pԸkD`r^!^G Y{@=lAmްb藫JpUpm }G/N98fDZ/)l(:e v˺:e|3=wέ9-霛ﶾ934ڳ$?H5Ǜv7EؿiZƒX fp/x9k[;AA_$ vf}RD@Ɗa#][P aٗg1aӘw˝7"hP}ʍͬיdOlcoGHt«]vlyYr?b;KL_7?f7*ql~;uJH_޵LZ27fA;w<ÝYMR86ks\qg5k/e? g0zm([q9N%kP /F͹dIU2BOQQ%C8ّG׏3pYV*p36[f"N%mqeI ًk-'3PB.פe+oZ;'$Pbٛrǂy7s"Y€V [ WL}ķ)D-ץn] %ű>f fLd0(ݧeTmA{[KúU\ %Bu+=W *{w"+$#}הFg߁ ١"ׯ)vvćp& P{*{SZNppF-[= t=͞j}S(~ ӝ_ƖLC¸bCl,a)8Xv}kwnM2gGjH%*"K {(/B8ǒL+R)EN忓0,qEX{!?/Oc,9"T.bI:{J$zbZZZ̠Dѫw˒ og|p &(cgDU4#LGsʕloD'-+ʱ! \!=('$;Oe ,3Qe SKedҳxt]&25(( ߿GYSĭBHOIEMҔx:dK =QFBh9rkkd%h-VVN>  ~L%Uh \2AK:v; x UV2-DAs~?xf.%$nj|PC/IDxE^&% KbS#K>yaC]Rg8F]zPhtr f l<@g^ZSͦ7.C2%[xSVTs;vl9FJ%️=֒ټ'vkٴdn!CѸzRE ;\Czio{B*%vr8[J P`>ݾJ̑Ӹs'B!Gg0:NJ';,[2â@Qu{&%Ĵ̕Ҳ0c3w̅N`lA?tN1޻Ye= TKF߁q{2_1l(X;*O|k@3>BMhp<鿨/+IJWdw#>`\ VUXΙ\qCܦ%iJ5{dn  SԵ!+[X_Wbqu_ 3+史`'+B}Gi_Lj-1?wiS ^nhr" ZZ? ެkI$ZȤud;aU^C \NRAMͺ/WƄ[ѻh"9{> *~+Y!'H߹B2eˢw#%Wʔ5!*ctkPuYJGr+*W&3 Džۧt+2*w?fzacUk+_^ϤhiYVka̞gxT_!  e?(rOߎ]PJ5F釢)?5wp bϭw a5E#qe(0aנV8;vYjn_v]/Fs-epi:oG "jS7oCZ&3y&}鎝#MehTTŁCBΒ~u ʠjfgIg>yv3,SX7SD~ #Wop1ӊyzd\e ӴU5`H3jOh%S;|9WǏjr^X]BYwJ{)IU$n샸g~wqԯf!$]|7:{;'n(C#(g[d|b7K 6LU=q\]tX; 7o#ؼ¼_%-aSn$d\ih9x5G աEw߫lKFO IǜŗhB܉;XUnKYkkG(ߘ?Rof\EʇEЕbÈx %ڎ^/)G_4jyv?ro3CJg-M~kbɗiC.(""#Al"AtH A!‚ :$BXAD aA!,C"At(υru9_{ !8];?ǵoY^\%r  I~ň ϑ^ϢƲOsF"IUhݍm|iC.jW)g.oX2O= 佳 %dVΗ%_tdr f/ğWj]]K*/Ϗ_!~Ơ_Ѡ J4'c0NL@2ҡ&$_9 :t44)C3F}7pa%zR4hRwZ2 Nؕ7~ͯ Bޥƞ]pф;%MY@DeϪT; #J@ⷝؽ~Ew1|6)&^+fLXC=lɞ;3DNԹS=]HFN\Hz(Y)ܺN퍏 nt˙Otho+7MptvY^9J*{Gc&~ያ^ȌoQu!;"K' Gw|zN!>#QnALwg1d̯Edz%%})m#]2|mמqutٷ/_$|jo|9ѓ.¹m%/W'3xImHVnۻв\fuϼdY lӍBع ւf#v޷'&ǰ`lSjd =پ4ƲDuqk`n%vģ qvT<(ĆCzд)zh0C-1-E %$85C"?8%;Ƿf[!p׆%844$",ՓТRm*Ԁꁥ90f8Kyz$Bpuu×s7~*WnǢo4ޖtuT% fZhj^,m'~ZN6Ǻl] 鿧*#V`OLZ-eʺ3Z"ZK,b:ō(RņU`(. >N̳&[ۜ:j+)]TdQ={E9ɛe]sHS|<(?3CCX˙ [ߎvP.+ [H-3ɰ>>DEDp)ZqGؼ2%+S4ksX:eڮ+m\!|ͧ>P4:[!?\=r9 V sj'N3E a 6,I2 6x %Ӱl,7odO!rsQkGصd\ Es鯳,j* m ї?q_}O#d KՎxZ#BR݊ 12L!9婀OMpE=S*f\pQzp$7rލ9 v,{%C{3iϽq}YOOC1nAS9'iXLΏ|ÃJgdd }g%{QP.Mʳ$c^c+V3KG-Y ˠ(JtyA"L,*꫖@6dI˜zvr ;fYx&7<$|Wdt*! hZM!! " ُEF=-Oʃs;4*|0c$}˻i>$Ci,- =f=mKdKTtw:Ƃa84* 1BF)Qܾ`VKKsCe '%9U~YFZ& / Iw˂@z )2sSV8@ƈh`Ʌ)W6?$hSRج> [?uA III$%>6͝I ^ĶRPq՜ኝ IX6,{1ߧ>L"))ZTFD tX>++DRr2\m g II4ίkm2ʤ/݉LHGϤ; 83G;7'T Ւ렇УKm"'u{V뇱}$aj7f2yT{fNBѷs+-ï|鳜V)Mˇúz/_Mp˟V(/4=FOr3$ݛh#Cţn/~|"㻹3!^P-oF ׺Gӏ sm8mH/5klNi!j{H?Q-Zx&zV&\ }(WAt#aAʡ}>Bu5A艖 A!‚ :$BXAD aA!,Cs¹VS$$$*SRf}I!B89q%pak]WEtΝ;\t+cbfIDwD. XkkkrUh 6{| nyX-aA! ?yx!,CO8}‚wpn#XǃaA,yH-a!OP/0vR?5Α>C%nk^ Sp䅈D6/klgOV3/Q{y/Pջ߸(L Bɡ{N* #TR˜<ӅZ?DPQQ.Z.UhQ{X_ju ޹;?s*j<N%Į1M{UD6>4+ &3/fҾ G86luZ%u!" ( Yłu: Ռ@{BOo&I%qet6A^){bGi%LwAخ&JցlȒyAbcmr?Wc̫ywDona[_AӾӤtK2rR svĹ:e%'Ϫ6 KBȤo3 Oe7H:_Wqz)%?̨UNm6FbN- !V2@23ia$hNq)8-ȬzHqEZI_Gkdww=o&Aҙxj~i7='F-@Y IyO>h3)"#~x֧n|l:4溍d m3 j+oSh y0{ vM˱ķMone]O׆}IO䛉p;60_ν썄nG[CB)ΪR}IIx, NМv+G0e_|A>1au#~s kud܊`Bs`~Zx.Uˍ1 XeƷ<[VÔ+bv0aZ0-![Yۊ?ֻOu*:7b[`l_7~)&edh4+B^ t8?cP$GH(f͠9k~lڬuSvSLgYU~\z3+xnN>y~fL29|.(i 481#.JMwt+ cĉx1ATVg˺Kx$8[|920FjN옜0imz0(uMTU7IE74e s#^^?mOFj^/ I% H=X2}5x}"{vbBfZq]\/vbNܼbJ_tZ.ڏs\Y;ޜ9t_FܷVñ.& e/Y ]6$tۄC83L򨯱g3iH}0;k/{~4ᨁ\NƜqwP)@e/j1u9BJ8u[Ne2o1ȺofZzL#iPRڜG⑗> ߻1ڽ1;㛌z맔OY{1z,]:C xə Tu&=s&Ak~s߳ ?O?ʪoMqP>cci{IeBl6>#7,N\c72q*U Pm1w`k;=}Ə\MoӦQTTd / /!77uӋUkՎI?#|$h%,"bBXD"pQ+ByyPO8',rJ8(~EZEjG$@/}Jl"bաÇIO .sS'Nk:t~v)B8a.R?n~?Pb ( %'"1bND"E a"")ED,RXH!,"bBXDĢ^@0@uUuoO#"rFUUe뿶<|Xwf_eeoO%"ҭ@0e!.#FiDDz"")ED,RXH!,"bBXD"E a"")ED,RXH!,"bBXD"E a"")ED,RXH!,"bBXD"E a"")ED,RXH!,"bBXD"E(d5t-/XIENDB`kraft-1.1/manual/images/de/taxes.png000066400000000000000000002071721450127457600174520ustar00rootroot00000000000000PNG  IHDR 6l= pHYs+ IDATx^w|n r"`XPkbkvzkXU{GgAE(A!PSv~dfK k9yfvwF6y] HZx.PA\u:""""""5+@sb:F"""""" 5(Pqc """"""5cnPlk|EDDDDDvf[sA^|L""""""۲ʶxs=u""""""R36WS`so z5u?""""""e&AMOZlEuw/""""""[t7 ҽjzگaV-Z]N1lMjc^]V[B[]Dj1j[]ӏ(cɨ}Te[U6YUnʶTT~DDDDDDvUxTUVe۴mmUOUu%d ܪI*SdsKFUUmUm)V8-~Cr9F*""""""R}R)ʓMh>YUOUcvx7U)Q^xsɪ>*]Ere2m4sQVUwoAsAq?l_m,v+sߕڶM*"""""",b;\#h'2Vf*\nj]*qXxl扈H|͹rbzl+"""""NU)zm47A붠u[P__OyZnJY&dbn&v~aˍ'AqINP! ;m4oqm$l^JY&5um̺t׍y7I2qer|7emmuA;/%,`w29P1/w ~Y->_ NDDDDDdk8<{9A1/]I&/Mv+ιc~y8FDDDDDdKV&w9Ҭcn$玃Tw^RQ&drb_@9wT&2Q]UW<ձTTGQłĒ-m~sn;L^29IKG>+7<{鷭w0s~Kwwsq*HmP6`w]s31KUwRIf-K4oKݗssmAsAq?'"""""%Wpf {˳Ҭqwi%ZR]9It[vz{s猰s\q6}~ʪTDEnD_-vCgM1M4!ٓDKuތp~ˠu{ 5#޾-u[P+tݱ;g+ܛ3ߞc}-mAs"""""" q8gAM}3ܫ [;K/7J`TH-b߾!(mDMOtsfmbO29ΕJHuHLac|y͎σk>3vͣ3ۚ+(zr OP*ͺ}Ȋ1o>`u̹0 {4]U\Λ7yt8澥4\6혻nsn]4OZx[snmd~y&/f}x۸""""""[8Qmb+L! a&fϹM{^*}Ua?p?f<ט(kB8 ڰHMlTM!"; 4&++M秉__DDDDDDjP(Dw޵3rrXnjsO:}f?jۍAX̙Zֽ;neϹDiQ s\~qssdͼYL,GݜiWM!/Fy=BaX#b;kˠ}HծMk.9,wNѮmڵmás ,^j"P`n5W85,o΍Ap<-a?dŠ|tm>Dcn7KQ&w2z΢n/i=,%ieDDDDDD޵3C\Nݩ wݷ 徇gͮEf̙B4LMb/OqUw"c;n|͛Zw6'6E AFr:|oJڃw¨^eTCawNmڵi.uV|oKn!;;Ī|F -^ vptCgݹkأ:[nBviacNfYʢshP>67@P hjPz ecXsfخ [-%5>HHpfݍcf݈0_{b?ME" A aQSBs߁ӾuOw*9ezqSO8!""wuQG5ln縣[Ykצ5}$|]9W^S^=75) N+oÂpt5wnz`8 1:2*t 1k<ιJ}u7jȞqDDjvۅ62|(>6~>#GQTXEٝ^=ٝ;u)qǽ1iVVԔ_qǽQh]!}.!ԯuo=c]M]ܸ;̠WCxF۝yv!:Mv~*LG$aY\ΩGHX^3 Hxydfd0t̞;vOp9gsپC{N;4oCxOy=9h,'/&|K;,)z#Ho9aeGumӚUy<«Lm:/xwՓu׳{xjKxG[,\SO<~'OfoN}~c!^rWqmYȁKFF?3/+?ִA)*j%i3s{j4|7+.:ݺRNZGG"wU }gvo.g4L܃?^/""쌌 <`vށ'F=tMc!Ẁ=sKw\}z0xI ҽkF^=5! [=S}iF`͙XAZ!f|<Ҫ6 &ߺ̹-ޜiBD*oܕrSE8o$RBċaZ& ԭ[۞0L֝E2Y>d|y>X^3 Hy@8+.bU~k/Q1g|6m*Nl|?Zw;na(*.挓pЛ~>I ƍkg^~`]p+dPVYq{1yhڤ )MI?ɥCgSa\۟q tߩ 7v7hղ/Gn]b·{`6ĩwZ吏{'^u}c?ةKg^ozq< ku3#c=w߷ˆMeuɼ9=F><%%3awsssGayxwhݺ5񧞵+"ej߮-C.us۽Qv0l\3RxB34x甛Ks7͚! qypu}݇BL \pk٠=gb:Lـcx륍̙pGe;nJA^lU4뿐v BlH1U/<'f]4* }1nn0YY!|x-5DD6OΘI$R>e괙?-)]Bi٢9W<(`~V.,_˄?ѷKg|w(~e*%+s6k6۵-xJJ_fkoK.`_bi-V3ڷ6i+}K}hӔ_ѯqK'h:rx^}k,fU^.nzW\t?xy<4mʩ'G'~isw""[=vܩJr1{[aet9~kE*ڵuåpuo󢌩A==o> ŽumșγASl}Rޗ}ݥߺi.^.^tQu݇;k]{\; dڬIo/""KXϰGW1s̝7?6 7(D_u XFKt2fL|̛ NٯQyx^S@Joߑ/Y|< ao}\,U+sWaF#G{͠K\}=qġp{ m_l4lEUٔߦq_w4HEaQw S~]ÆSXTs6svƴԡLjl01qWD- w\*IW t3~ܥ͞3;f#dT6慨S *=ne?_yQ.\.G*""5#yNouW^naݺ@p7iҘ׳Ex&i嘟& 6ҩcVV6?٧̡`m%ظiSǕy mT:e 晃pwscat= Ba۳Z]!Js)KbK/8)k>Lu:\惈f{3w / )w/zt+sW4yj<+W WN,Ytn5rӹ3))?{p6nMr3'޼{u?t{̝?c]}n y|ݬ]7osp7S~=֬)q`rVq1s/>/gTx׹輳8CXSϿ~_Ɵ /o_}#G=_>ODDhSMu:g+ IDATGhC!;+Bӫ'7_M1+ݟQ.5W5?{TM{ݳv̬9^xͫ'Q^м}Ђ+;;IrW<8V?7L;zV,gCh[ C4AfC"%E aw4~}q#};t,"""""R[э{t7˾vz[]XNaxsؽ ;fߢqcbf-ZRRÆٴa%%7i>uZ@6gM:RQ/"""""RܣgpA^v>fJ7YDDDDDDDj]5߼sk_7׭oPq5" DO 'Zxwp<"""""""\m4g6{-u?+6~O={`ywREDDDDDDɭQMmj̺t_V `N\D)""""""nae5măkDN<6~',.H f2(n/ w {iD2{ ݥ-nH: | <;.]ASS cwn}T7ZnṋgrdiQS ?wppDDDDDDf(_'[ݠ݇טـHItNnwc """"""[6AMW<_Vmŷ{ܓ-z27trРa֓Y1oVn sp4ɜVm,XΈlݲ3BئDDDDDZ'qśqP9߉Iĉl3 #n5>1Vn=֦|}8745!-ҌCs8a.W/gݗ|48vS}o2i{ل&]/3^mwq+l|/3ϣOB_DDDjϠ:m6g3mLdyևNvqRb B~Xi5,_ؿP>[7)˷E6Qz4iҐ'wj6ņuY}%a4kMQcxuӴQ**`ʵFl0 uyCD5l(ɢ~4 |jܓ @p=sW)ԚC/6KeU˗M;12%Idlf~knaTAtD&I4/5@MmC55l(n~Ev˝ &~#zc6/:sYnv<{#dH1Sɤ٬X#DF6HN>Srmd{x0~*bk'PE̢nq-qTd ?~oKX[A(L]s?Ӽ/E.?Y@f+x()yf?,(feq9"kk'|B6EPMLÏfVϝ&Œ:9t`?|Nޣgӗθ&,kw8n%&Qh b35ЀdO@y lܘaX swndʽ!܈64ׯ]kL"sƄqoosہLq׼;"ȦU~ {lOfeeT1B%[&WզDUh''U4eT.[xq֮[ǮD?ز;;:Yܩ=czBz5+H4lޖm7>wci( -/"Ԥ uB%M\Xmp{K|Ps\g{A{bW(C!"GɪI<1^?7x1مִkb+wHCP8T9ɀ}FԱ5xsK gf.)8|p> 6Kסi6] ڊ X9tDDDD0֥1ۻ,jSrRɕzѣy6ިQ#yݻ\lB9pG혿( v&O>}'h0SٞF%Hs6xxc8y2䭟4|l 0Mv9ל]Z3 ͝/MeM"+>㉗NA*|vE 2[뀳8z)NR Dvz)<..yNȩLٱ?ӟIlX_uxk'|96c|Lz\6:psP蹮c&"""HL%wQMvW:f?ձ/aEL:՝-RxjNX5c2;{:83DNsz=މG̏t{A%y|,.n}`  դ.{A*aѧ-ZWnɡ7?=CE{؃蜽uJ?L]c9d!\7vzs ro2_5Grv]阓Moc^ EmxLz{!LpݑȖ:kOW@TIۏGvC&O3ώ.pOJAn0+~eGdB}>&*^t 7ދƩvk%uML%0}:رQJ8]qR"tӉ~dw{!s1WѶt ;%4w> s9S ӠQQpk֬ccQ  `utn UN+ß^[]9QLDDDdo%oSwZ:OگqDn(ik׮Ubk՚}1O~Sm,}~ *Y~K/Mh,v22/L;p97sș݇kn#x1>b^j3nIr9(LDDDd Ի)oU f'OqdKՀv\JvFv޼%c\ 3dž 1 >5zP절LO^Zd4p#ƃ'%;8"+\6-Ir|ظ%y8GG%i{u wzDDDDj?_h[cwVwek׮_]&<˘I( "j,_.7 a>vC٦5)(ńrk؄xt~,Dqs--xC4G c &Gn۽ai`“je2sE|*~'o{bYhhWҾq&1SXqcί$u/+~jhM^}kꘉnnͺ֯[[0Raܭn+Lb.qV˫;InՍ=ޕ]vo-ҠNK'?eȡ:Emۄ0dXxmkb֔Ut88t}~*/?N[F֑tLܦgidwe.|2ߏcz&{+M* 5ӎo^caWw}K?}{ҾIWϹ×|67zwob'xߍȨe۳o#.tؖa6-bO2vaʠ}jm2B,x@?2qcuٸl6߿Oż{d?a# egWoRc&"""Rkl؀y;ϓ~p6"lX6M+wCSͧ?dѳᄡx{#EWñGҳA H!=6p 7r2Zp[><D~Wn2 G(}ޮrél+\Ƥa´pC)(^;x o3eZ8qEiB$?W$>׷g//:+7ʛfpS{}n7Fl^#l֭[熤Jn>Ȉ+vE 9-e'ңq8AK9DF:´:Zn<u7 ӸٜGW5GyhB(DvO&YI<]89e8~mUhu0W]u -$/␸j䘉Hm\E "R%Yy˼g|$~;$o K2(wמcgv@4{+}Ôy(ԡI8Hvklv~}_̌K]WhҢ;t߅Ƒq na7o3i."Qs z 'ۃ~n~7o?NE+)(Y1lO^{#8|Sw^GILy(2ۨ9vngӥQٓx^//f|6Rm:k8ūA};eqH^ Ajb&ncf~C kƙ@5Όu3oWG|~\s7 <Gy#w2 <Ӝ٪Kt˗/UVnԍ߯qCܽwc7Tq[ӴP (J"gl5.Xc/3ק^ͰlCDDDDDDDN I;5 DDDDDDD$ԀSBDDDDDDDN I;5 DDDDDDD$ԀSBDDDDDDDN I;5 DDDDDDD$Ԁt"쳼n)SݐlԀJ2e*SܠCDDDDDDDNW@HJߟYӧa_fǟa I;]!5b*[lZJ qC"""""" [0DDDDDDD$tͿ;: 6H I>}zӇnXDDDDDDAz ""۬BN9wJDDDD!"Q '>ugǾŞ IDATFX?s<-t"K0;j$/>zQxQ8[^Do؟ϿGߟMY·ȊH" lsM`Ì;K}2||t@_nمҼ~=hut#;~@gzA=]Ƭo˸dC͞W~ Xk {&pPw Ep1W3i#8yFɂȊyfz۱ipi;8k8ܺw.}#xg26x4tWy%Q_0g6Druuvn.~gШ-#@ rWʥ>&HAEy&>|[Gh2[[O8E r[|Pk@o𓌝447!?ِs7ܝq !22M1g_11=YD|Ƚ^y+)ؘI榛Ne%o0tK\W0:pc'2cykyM7~Z ˺zK4>H]8Kn[v-| y:Woo {#xziyc^^|}# w0qڭ2Ïyoxּ,vGoGoeر|u1˻c}=9.d$|LEz7]>řu>g'QjH'Ï?k1P2o_4;}cP~gZ_4wܝ}qK81u{ʁ2ij< Լ3w;On?OWd9O1cĹ%Po}EGѧ!5do6Q~ʧϞI)Cvenm惈Hl>Yݸ౑\,|]x;"7 ]סelgqon,ge&dǀ* SyqzH1ٍٗ7>+k0N9YȦ{}rVF 2 >g^r0gݨ-۷O>Ѥ) ܀0a:ݛ.% -Ԙ&vm<vaS? &}طgrJxhzӱ>Pw( gVxFμ9`Bo*Ԩ n~a3?ɝ7^ʒ{^dnfܕGyf}}@£4^U~3]ȾJplWQT7N֚'ih->x_CCXAy:~y73G% %xLY"o C$B6-1gA(y%=(%AkZ"L9]&(|*V ӄ0VMyQ/~ʯ7dTv.Q>7LfMKc(&^#0x f9t?z0sO= ISh,]N'­2 {`%kVSMӴ\0NUӸ"r. GgsK3Y=Mn: Gq#sCSx蔛]+=wO5eN?&?!B;: owIo@HOB/A:(")RIQD$4At䣉BBI|$lT}sd33; +Bp!sfeg [\pzp,]@/Ƕ;*(V6EmJaҲ`ϖAJ d{C%C*lB!Da ]0ύ!(;_V|2:}Q'aIk*@rIE.(k5^!R?n$))NIXNfKת5'΍d` Vd0pKEAcJvԣMU}9Gأq(J> GG^6|>fOڣ>KfM*U0$rv\c<p롂㯫ͱY  7jxR6*sq{zP*S1'u|m?T5E|T*ID7ƙJ>⣆vإɻ0^;Y"5^y }-L_Cq|?v.Tӳ%5{ &~m)6vlAc3iyk'̜K8PW=bʾ XRciF):=`]Ҫ*k|:ѯ'՚^]d _+gӷ*<qV-%gsHOrjJ !BB#fMS1t4m>[a=Z> ИU-LAMZic"}07nqOwyNTTB'g0<+CX›ژg !B!4tH5K &i}zZGZ_ecZoVO7WrLeFB`!B!♓B!B!9 @!B!♓B!B!9 @!B!♓B!B!9 @!B!♓B!B!9 @!B!♓B!B!9 "PHLPXC,IQ #3p!WĠ҂Sbi@~mo2/HԡWKB!ghT*:FjϔlǺw2f PR mz1O gx鸼Wlݣ*JR?(Yaw׬|Kc]ؽ-AP7;L\ڏEff-Bۀ4t?Xv ؊6.}q($\_>~jHW3~!B!xIP9Ӻ%GFB) ^Gۯp^֏ء,8cDBa̺ߛ)N5ZI5;-bX~tʪ8nʷ}Umo7z9+dž_rsfΑ?&Fk]A_ !Wleׯsx*;Ïk{,zH=>F%ۍgRR¶UK=%te-k޲!l4VsHb̋n8|cxBkن1ec[62~ 3w 7c{6O`j~G~cFE~;x1$t|:,e=SR!B!%$QhXDD$sp.{E{X^G4Jĉc|5;孲,0*\zʞjRܺ]zTQ ֥@ · OJEP޽=U.d6U'/kPٔE#}|,k{iH׸ur?C}_ci8ԑACZTuD5Q..茦!9ٱGK_A ٕZK*WNXH)z1_ZeׄP[k-Gw~tEdt0>RHEm-EoOŢ!B!Ŀo TbsuƐHll*=L`IѢ_Z;:t1CX7544&РVbPP DE'qc{4~PE jw<2cYj z  Zn]mڠG4op'˖| >bwpH{*1Nl"/.YĚ7hФpIRfy.!]qP9{n>ȹE, *4dnܤߘګ h=Osݸht[ʒWˈp˰/h %Jp b)\ ~-[kVPrbaD\L@AAQly32=`ZEХ*\I?"(zútU*h;߇:ZDj/[M}tw9g0>+3.-=16Nn߰^zlRPrkJB#;(\9}PSJyUhB!BQI BljEUaz},T84ł_2qx[NŪh :|:AVwԡy-d2VMi:<)iSaSyOcX0t_tfݨ}W-{|8>ϫ2hBz<'(7z 'mщjacd^ZCɄf|IdZ"sP3?~"Gg_^]F3>G[w]͖I{̸)S^kD)ߤ/[@Ir8&okl 0A!BMvg77M= WWm0I5`iHLǍƴ[\S)jf-Dg7YN0`yV&᱄71~"+.ST1⩒L!΅Ǭ>Rg@,iuH5K &i}z:핅iIZI366WrLeFB`!ݔ7-Ѵ`~;2 n4{ !-&ՅQH4Fv! ❎!lEbB$!xh913gr3_ZW5^_ҭ x3&X oyZN5|D\̇_!(>Am6p2kJܟlw= Y#x‡R^=ߨ%ÒCQ<p݃ao6ҟ6F` j`3ھ>_M(BB˞*{;4W[7*KTVVdXšk3 W!ZnxGΛ).'W\4cޯ縝RÙ81EU6 樆||m+^ sL3ܫzl+NČ/Wq02Kt:~]~/5o`y* C_-"W2y|;kym zdT_UidꟜT6w(}zU p+K KnnĈljJH#84Ck4"PVH42ۙ!Ng㇥=sRsė 5}onJM^![' /NNyi2&\}ylCCL}-*[F.܏5 ^:Uw^N^5.z1朘i~^}^!Am} lWE,kz[iԀ~WY?sҪw¼o !+T!( 7~QY;jכmA^B'لzh z/|; =ku`7زm ߽nͦ98FTtYBؾc#sZ%bj.%Xv罎*t5njbǖ1}iFmbi]IΎuTnhg*6leԺ.ߍ)#R+և-*k2f˅Rz2~ݾ/eCX<^nŊ:PYSrMj&ϊ(T<>gRٶ}#ˆx=$c1qϨzcӶͬo&1ʸ_h9t4_[:7ђdc$cpƎcW~olZfOLU*Dqf&5 >h6i,{]M4iƫUc;g ǡrV=%[2e6Fօ!CJ'n[]}˕UG"+NAKׯm)Eeٳ{dIRW|n*^*¿o !t!(7N#::vOltɤ 5jk4-"oT Sr],QaEI:"&cr+tE-W PrP\ Wz-zY W XԠWIkĽcl8Dic~-{JU5XS0zUW^ةA2լ ќpBvTE EQZ5Xl{ܼR Lx;ňB-#; wtNݨV؉^H' βX:՝ԨlѡCmbb+16*=aś)Pacxngy+K]rcN?C|D>/'*ڂ ζXir>%sr(F6uK}3z؀|Gu>;zvyl|%UIŻHz*F[Y IDAT{eUz33f+]cS_Q|bsXWENX[+, %.BBLɰM\v$8sԲPJ楠F!U)ov."AѠN劾jfnn6Sj j_fVn8We_yB.w } -woS7Kr =+s:!j7JfN9cj48f\Q@QR~g܆:><6&ekCz^J)%n?~ T vmHʮr1݇GN/VRbHNq/]*#(CEڼ;68&˭)+]|||ޣ2||ouҔ0b<9B/vʟ1K6ɛWu/nBP=ni;XHIܗ) (U5n{=BBØqQ'B=qߝϲͧ}e2SA-4%(]"?cݷ5F]9o!]KWX1tߡV `U/~\X„C 3k,/;k0\ފ2UNS;t`l{kHOSpВ,fͻ8#&V.DuiwJNZz<)JOYGQA1\C̜lB(N.]S($%npuFW~3Gii\psO2֣AhEoD>\eBa-^Z%Q1 ^yr?s *Y8sO}nmL}~ɩj?0{}[(6J#s_~eyŻmVDOgMK⫯GeZ,)Q9+Qu+^7~ɬ>mo±u{crהI3wۏ#>UM/_}8E󾧢$F6s Es_osɪ4~k:9Z|Mant2tr.98C-iӨoz0tAplЏ`C48md,r݆s?=ޤx 5@lL)8\=7MRq+C0XO[S/ƾ%/)Ϙo:n6W lU$ma6jF鸱ܘv7|j3]̳(t4r8< ~Y"*>>π>>_τ:1i4 =j67LPLzgle>0ˌ򛗅x Mcͳ(t~7ON˵SgQR%1WPVEb?([WkIoeh|W !B<3r!'R8d4E(]'חW}&u jhd|[!iB-eM|!^0JB!POlB!B!xBB!B!3'!B!B~ܿg;$im5q;Q@ϝ_3fZݐcѻ<Y¨Er./|eGNb[>1{8C|3qFlEݮnC?M>;yGF ذ޲? !xL%16dGRe;V[4]KM,9rgNS;}0rRTsIwÙA '68e"yl;>Z~ =`Χ!;)9r-fśjVD%y|3 Ɵw3^'g'nCa+ϣ(7aҶ½"NdOq>nWXB'!Q`WV-ۡt9;99Hqpwwh["?'^* MV)$&hf-Bۀ4t?(;{$~Cw¼t'ܔqR_\Ő8jiՂo-]ؽ-AP7;L\?2L*/USaeN`QǯC~Zv ߂0fӑӸ+8 \Em Խv˳ikL& ߄Wr& mmBN!пqY5*,֣u7qԻ;JeC6⼋T֔l;hM kx1lGVQv-E)m£>߄8.+):,;XޯHY!ODɩro*b׮]fS<]ӓjժe;ŊZ0]Sd^HfoJ);+4ћ;t-ewk/B?ڹtqϜSS'C4ՍM-ې7ſ#-7gs_`nt7lC5hxȲ\3Qո~Z,gg"$.[zvDsV)l3 ݶ5ʼnW$Ea skJR_/D߲R,YnmoX`'Q+L~(+OO.qC /Q GrJ!ē(* cp!7@iz2g7^iF:./=g7]jC%k]/-Ka#d9*Wq St=c(};Rh:u94*l:3yp k.ﲃk7 ʡ2'kXݚwb1Ve[&s҇FGrR v6&wXZdT0W<.ԭ85' \gY hdÊd[蹲B$! iUÃhZm8$Nk AZsK K4꬝QZGfoc%** N@URwx D0b-KSi5>xs%saXThTܺ.1 .Tȼr8Ln7!oYb O,WNIAVx= f9I R @ R|yvn^4=e1өe2EפcHQ/CN\N{,+;B''Q`]ǍrOOOs>rVVr/RЦjZD<_v>dO!@2pqsźVByl@eu9 [K3jݟL w3cDsWgd3P@Q AxS<%aoYJilUZvn%dP9xv2aP\2˒ цԀB^i[3yœ*݊#\^ԋj A079דB?rI" <萓 \5yVmk 'Lrj<p166pTu/u3[TMj];x[5zbmf,_yc >~-^IEN#R$JD ":^~!ME]n'JrļY.*Jrq)n- ^Ʀ? 9yS9{|t6)$%* ֶ86&pmNHc'no]̺; W$ys$"j5*]<[2f5o- 1eE4OBtHBXvgfIV$$$d*U Ȍ<.C)5#"3$BcHϪxM j6Y]1D.ǰq.8:RԿ Ȏç3`t./jw %gRg&`@l2?& W7S @( *]//B珧#x9E=x>m*l@ن3qpG:cW r5BrdΜoFꟼtqfuK{V|UNdKkxZ0c^,Q w7 Gxo3z;ySvtM<&Kk$B<?t9MMCfGU}6U-LA X-qc1o*~gyJM\r)"111C!ϟ?1OvTILL+Q"y7n3iz,wfAc/UE3k~i!pf0dfIx,M_ΏWRxyvt35k<_vνimMش'_!T,uݣ\F.}fiqc$OO$7I+yƷ+9 Fi2e!- DvM*U̳QdI, r޴tOF!qV⥒htMj ѧ8mَu?)=II.R3QLB!_F @Ʋ{M+WFp9G4j<+_ "?׷3cpEeK O@u Pɷkx\*^b`B!Ŀ D姂_jU,PTٖ=MY?!½hV6m^lw !B/ @Q!iE߼%m*~B!B!  @3L;wx^ !B!Ȟ D ¾~B!B_%Q`NxDپ1#?'B!%Z]W `(STs*]?ߠk9[`}ǫu)ټPHD+i(P!BH Q Pre|k~SXNSBUiJ!6}ZlUA3%*8nfesZW2QBL @VȒF-O_ӷ|G%nݦnE71ۆyv2Zkjga,e |1nĂ}ƘNA+zzCV7l5cm ;v;ZsW60y$U3CbM'l`2yѲst#mH$?U&nr !x|}̳Tjld;}@@M*Yw*Î3ȷ|M6FU1Ϧ4[NO$w83OVRھ%8>pjxY7/~6lCSzϞ pVLCqPt?ęzsm-.#W~ #|8v 1& 19h-V@u'OCvRr֦O;b:e׏ ;=?Z4wG1꯬7RqΫ%-DV}bԴ3ۤgPkBd̯]ȓy+GGGGipppqzJgx)z[=&up 4KIq6wİ4iLȦ'N3V4i=U;f*cvw_YBxk J w])onH]4w J"g׌wpCjԬpEJʥCxU~~|{:;nFemMɶS֤=q$:^w0f%$_}tr2+Z]lTlJѬe-,o\w_uݷ5_d6m8NN!пqY5*,֣u7qԻ;JeC6⼋WBde/^;/ۙII1I6!pxzXhNB$! $ ~ݿČ666$&&f :777ܰ*#m:>ԓ(\ҭPf?wǥ7NT&hہ*]f`# GNo5[Ʈ훘\A_ !WleׯsX??9|^g/piI)N@@qqz eʂ3Z@!~ϻEФP;u9JAGᫍ9wl70Ù-7rbW/Vϝ C20\E+mg,b/]"6#N'QW$Ea/)Irz._ɣ!ICN4+m#;"[Sz7_oOf-i?p:[ ex iЦ7q-B DeW7OGDD9$&&͍72,y٭x(˟۸mn;{yUiP>Gp{nRO^: sӶk9ivн=j,pӏp޸yV{3Ȣ]z7%`]+s?:`՟/{Gfܦ { *0$'bem4*lmm!9,3s҇QF!9)k;;jmINJz_M[oŽm| .KTG i~{ҒqhzK1!13 D4]~ܸRL,yO<0_'"S֬e] +v/ ɫ"Ԯ_k[kѣIw7,dD|#`|5GmJ%E-!8=u=ov-3ƫ֨Ǡ@3<{d(;:wƞٴyt)eQaM&Brr2.'q~pnocΆ )&daC<ͻ|S )EQERN{oS^( -6)$%%=*xm !UI!rbi@"+!KCN%3w.hѧD}zlVQlw;t(C9aZZEMB"Q`ٵ0 Y ,ɸDmrrI߷=-1Ū.̹4zT +|hZ)ݐ@Tn*@CQ,^אP9 Tܾlֆ5ySWV0㇄E=m(ѫVUZ-'ɋ܅1':6 xR3&"r?S{6fiC|v0%1Sj6~uizn3?bnZ/s#ؔ*V|E>}L+S4=/_cZ|[2N X,NQ1]'¨|J!x?t9MMCfGU$ma6j$m>ˍi{Sɧ;S̳SZޣ]$/NNNbggeڽf̓_*U… f% ȫTnnn&S;wغu+rٺTxzzgg9`d?G Mc oW`V^IYCiΏK_T N|mmh("B!T,)g@,K@YtXn0I:@zgge>0ˌ򛗅\ne Po !B!, @ɩowȑ,p%GիW<+GHB!B<_O-ƼCvmjy(8 I^3:Bbޣv괜~bᇉ|3$mv&'RAW#zҬ~=jiH:]ߛf+֮C%RIY҃~u٠-}m@˶uZY4^0W60?~c57b4nP'z ȓB̚~VjݗpE'!O@Z@O)ȴyZ?Qȩ}GU%|LB:BAB(6P  V,kA}uE, ( ]DEDJ̼0L~?s9s&=^1syGY>FM}.OjEF|cfHnd7C] e w_ky#|޽by>}&5MmG\s~k/'O4uOǗ&QWYV[Q'j}o! !ؾfv3|yzgi4Π:mI\-v{>j3aw>F3ec8N<$WWe3ϞlMf\g, Dݗv|>.GN&Op3\ڥ3e,/:폢ef{Nv(߮-|r>{*N>*#zK.-IF~/0g㛷o_/D7!xUے^/N ;]7N؞֙mhVޘS G8K+lt44DݮsZP;5@ uܜ(y#sT )ߨø_=C ΦI *s2 C "*ڂ,*IVecw`"alc3猋;R75@R6\ye{>o=j7y~j#h~fRd_-Z ԛ듖Nz88'EW)ssL:C/ʸn\ \QeJxcT'>_Iy_' &!V;.<ʘ 3hcx5DɁr+W@.ksPݍL|L(AWF=7FqX BXztCZsj6ԙ][/6i_ }YW$I;Bڗ_~ʕ+wj/Ў?c&6Z=fb jjBGn ʪEXS l8mnx%-ohϣ T"eDQ5Z})  BA"+XpmDd#7乡GSLe]JǷb @pNy.=ɅC4/e-4/QR kgyPx/YXbN)X3y-@]· evgp#a~~7ÚY1xLS@-KmMZ(bݺu6hGҢ䏺As{*&ċФkGm`TY!%l?n{o(h1eo=;1e|Fќ,_Fvf3yOnq&H2{gG(yft5VDdڟykq0'Åw 9]ڜև!q/xi,GXӫ<PC9|8d߯^%CLfуߣʙrT^XHw/׿yv|~<W3IJD]1g|-[5khѢ^!i7Ƹv9"5'rcwEtc%xby&gqqӏz2hعx w=S^{N; [k},w+Qd̏D{'،c6 Eg3mtҩv|ch`A0-֕=2}|3Nc5өT5;`*@!g^u{7]GTl9{?~F10>fpMd@:?v 'ZL^AѲ`z{ooY_N/lT['c x-\{b_ek9XHf3qԩR͞+rTTJuAݦmxsrV7SN)mA 9T>.j/*/_2[}J(킿Q ߇]G`wnsU늇B{tDfboc*WkfovD Cx^w1IyqER$2>ѝqϦIx,z/ݿucU\ /@^\9qQ{$.,SpRmQ9S-\V$Vd[6 m0>ݸl&"Kgƒ4kT,H$ig!I!T~J|ubP$Icj$I$) $I$IR@H$I3$I$I g!iEtm;Mxzq9-{(K^qcnxo$I+@HڽD%萮F\M/Bek{w\|~_} gӗp; ZqԪVC<ey q- Pg򛯙Y} \Pw[HI6#oIaw>F3ec8N,< i9z88 bp?ra4816\UNkJߗ3G9]Z%4U 1{,bڷhݺ'Kߧs0}d^1z5O}b}b!31o=u+8<͝ʄN౷&1}+\6;\~6Sr0Zk܊wk1;thfŞŒ?WNgwxOQ$nՍLK2~Vu0Yܩ'؎ $m$vK@-N<_~E g:MƩ*1)Ҷjf̘K8I-{rw*J|֒6 3uDv*O$y?f c~C>9LCRON4կKzѼ8)iKd i擸3A",|5j~'rDwNmFȍJphp&k2XN"=qAZOKL)9OnҒ.OG5saoHp-1#bE+cSc5"yP뻑sKr/HY89ܖ7J $םֳ0nn`Arb=]#4egtLۜc1ͤVsdVGc'SFUVd-'Ya2je-/LZ_P"a" ?3ѝtnۖVG]ȻNp1@+\!:Y`EK/@q>~.:wGФ]#*֪Esm4w)}_"yԪMߜwwtz&c+.bз/!!tPU<;KW[WC_dVf8`GJI}*pɤ=nVa 5lM0ndVΪG…޽9$U+ÒKRy,Z SRƴolg{ts M G?:rfU K v VUEC A"]_[P,feד!tFLo5K|f?uGz]͕wgsy&8%j⏬<('?Xj/zcd*$>%I(ݏ'ԭ {4R)b-e*S%e~&Jh[Ykך ٮ aƴiQ> ca䏫OjtRS(Kۑ=I^0a.ͼmgd cڝ7ԴbYÔƓ|S5klu{c.Fi#^a/ȓKNU H_qr+)w^kRnmVL|yތ<lPxt^ Ƅ_E޸7m$I;¿$֒vkН#R[* =jmۙ"Z};Nuy00s6CPݣhWߚ @kk1lu-˛wAVf5'p-9'l+s^Sg̒Ht 3~]UpǎBe5:]6xE@0.7F}>Eas^'Z>ט>X;:ӪukZ|Cg3}k*@ecmhqikLOwpW98nߞ}Uqj* IDATl9~+X nquEcI1-$ǔ EE+V6aݤ׈0Mώ`@UڿślsrZ[WV>}W <y@ G\^+SR].[cݤ.?疉 ޢ"xf>@l*ˠ˹%"Urw0&fyT(Dтpc]>[&'9+Vq^.w|Ĉn OxÂ`%UG/Y и$IҲ .CϿ_٬Ï5$QyS6ХR>GVs1nm6%D:A y{^>5Pfeښ((9$'s3?o4/¬Bt}R%-۲lUrXDn>I$IJ+ e]sR-=)\C~|O)A}.. 6&*iyxeZ]2 !S4ok9̃~S1'*WM܆eh rzPV9g%l}$I$O4+'H ##_Kfr|"@sP|}w>_㛸2d2hܤu:o/&sN (?eof~uhӼ lԍRSY(O$I)GL^Z+LX2(dV>P!j=JFeUxEٴ$DY&BIT  "??1kjI!WnvB -ua~^%@(HP_VY)[͋:%DqA?,[s$I$I\ Z'V R%)@0,X-X8?5hT,X_Vܤ,w*O 獯W1''ʷ?2C*Ks,[U)er\~TKp^Z]6}C0%>Wi*e<<+|^)ZU昼(9ka>/b/.*T債b AȚ\O>y# I$I*]zwS6WWT8'nq)'Ŕ SN*bӗXy?ۨۇUniDfbgW0UbKJ9\vh2I$ix,z/ݿucU\ R/@^\9qQ{$.,Sp,)G "V$Vd[6)$I$) $I$IR@H$I3$I$I g!I$IB$I$%$I$IJ8I$Ip$I$) $I$IR@H$IKM_%v,Y_%I$I+ $I$IR@H$I3$I$I g!I$IB$I$%$I$IJ8oéMyRկCCjw@|$I$i/ MWK$IR%Gy<3B$IedoBH$I>k@hD]ø`7'Ԙ󎈯$I$%v9yLB%2?J$Ib.V$I$2` I$I*m*!b!I$I*e*A$IT TBԋ@H$IJJ(aW)]O<>J$I0P Xq ;λ /I$Ia1/1Kc I$IҮaҠ4,1$I$IJH<4,1$I$IJHD4,1$I$IJ$`_c$I]B%D֠4,1$I$IJHKcC$Ik@DKcC$Ik@D4(1Kc I$IҮa1/1Kc I$IҮaҠ4,1$I$IJH&JcC$Ik@H3_El$I݋JH<GƬ{`oCcH$Iv-s$I$ TB".g`?\I$IB%$bc9ut$I$- TB"VL%7 s+$I$iobJ{ߪ}*}$I$Z*!I$IR)3P $If"&$IRf$I$IB%x I$IRi3P $IfF$IRf<C$IT T$I$@3W흺_#I$IJK$IJW0B$I$@H$I3$I$I g!I$IB$I$%$I$IJ8I$Ip$I$) $I$IR@H$I3$I$I g!I$IB$I$%$I$IJ8I$Ip$I$) $I$IR@H$I3P!hq-ǷH$Ic a~y'MJC!sd`>}L~6+|~_7H$I6b/Rػr* Eqmxp|=*>2?7ZUPDY>!Xx n]E봦}i<}mH$I]ΚriUf5Q>z25>Z@a\D>`g ')d}>-ғ PQo˗s 2gu`z쟼,I$I>[ajʙqp(HvjBGn ʪEXṢd;:! t,[w݃@~+TIJJ~㟖lq8bƋf]W&tsԵ.i|xC{l/h6H$Iy ^(3?.ߏZBcO݂Q<57r~dxtH UQn?C~dA_3<; DY53?eCv/dH.K~nÔ>P*'莍YtniX7=ಝU2UR0lDne$I$ifY?V29GkMͿ+8fs0D~7aѡu&G3?<@U Z{{~.__pzWN}WKc ٍ{EhUߦ%[w}0'7&* =jmۙ"3NTN;l.|tmOnAeZЧa̼$Zw/!I$Iڔ,J/aS6WWT8axB1cI1-$ǔ EE+V6a.WK%K_] 7U5Ub;d\.;ԟ)I$ZO}En*+d[ȋ+>.jĔÅ| /*cºs,k/-Ƿֺؒ$I$IB$I$%$I$IJ8I$Ip$I$) $I$IR@H$I3$I$I g!I$IB$I$%$I$IJ8I$Ip$I$) $I$IR@H$I3$I$I g!I$IB$I$%$I$IJ8I$Ip$I$) $I$IR@H$I3$I$I g!I$IB$I$%$I$IJ8I$Ip$I$) $I$IR%WH[ҨI3$I$$I$I mؕժ3eOۣfҬv%$I$ZvV-o-zsmQZz|$I$iqHԱw I$I[B$I$%+ K4{6C ciۯ633ݫ5l I$IҞB;U^^#FD6j;wscW٣nH$ILiK6}:@=΢ǙgqA~i6#FdQ+̙3gyB$I^B;̀gddd縣4 $''Ӥ_^L>{ ~I$IB;Og3| |V-[w)֪eK|~ Ogw$I$a S 6H$BΤe%jْcW +Y$I1NqPÆуh4?a!>@4=9_R$I{Jߍ70gMο$I}AR|Tzhz* -ȔՅ)Ad1~gaʧ2U<7`3ÅC˯w6sJa +u׺W?G/!uѪB$I0PbWᢿqx*Ф%t vJ!ǹ4@YІ{QA gO$qv[4a:¹!# kwcL%EO$I$6#?VVa u jV_̬HӞD0ٰ!Xji6j"K4w:v; #y눴[K>$I݀#NF,\Bu,XBj CtaS6R;pt)*I$Ix v\8ֱp[C5}/!?p'Ni?v 5) ?'[Nfw0$I$iw o['piGhm*MphWvB y>ߎywn{F5}[K$If3 KT>-oE0xB1cI1-HE-qQ{Q9}}nngɒ%dddW7=; *Wkfov,C$IҮY_ƪR @c0W}\^{))cºG7-Ƿֺx $I$IJ8I$Ip$I$) $I$IR@H$I3$I$I g!I$IB$I$%$I$IJ8I$Ip$I$) $I$IR@H$I3$I$I g!I$IB$I$%$I$IJ8I$Ip$I$) $I$IR@H$I3$I$I _!L .d֬hܸjՊ!I$I@hXr% 7ǎݨ[׮rs?*UQ$I$i)VfgKo˩&I$IB; `4kڔfM`BpoS$I$I{8T .,^ЬiS<<EmT~utԉ%I$I{%[.6Ԯ]:աrJX/@%;wx[s̞3s寇FzzzqI$IB ҥgׅB!ڶiC]9][*W VXǟLͱc駄a/^̕W_M<hۦu($I݉J7~K+b@Apq嗓 J IDAT׻ʕ+zI,YAO>ɫN8É7ꛓ]wͻoۨ^$I{1P1cb֭[_~6lsc7|35jԠVZdjEzuoOs5kV3$I$IٳgsWtƝ'555gI1zr9{w݋6lqkys؍s%I$I`|gZ_z)+8gm 69sCt9$?T={U/ ˒$IݓJ*{EΝ[z9 .\"[ҹH }$I$i7d6c FzjKg㣪>f&IA)Dp-kA]\ " . *Rd]^.R,P @3y)L2 sUEt͜5 ?@}Xn,%"""""8J?a"e+=K/Q|U_~h٢QX|9@llWd.@Pmذ[nxp\"v{ '36n(ˈ(Np*lw'%2𳅁_)Ͻ;6 """""x-[۷-t a?E۶mt޲5QUΝ; LRSSqbsuѶ=]G+///h@d*nطoJfddbw􉈈(~p*,~jgϞJ?=z@=t8@?55Md(^#Ta8Du.Ν%^.@P5i$7_Y|MDDDDDD?A֦u@~?k""""""c=ii\OU|iii8[7%"""""x0ǃf~]nެ*b͛v:@ """"""\J9e@^""""""'\J)EW^} 6mRi&k͛o*(^p*%117xS*bg0*(^p*m9G>2g{~1Sǎ8U.@Pnwd$%%|a|h- |t)]ݏ;۷GVf&۶mö۱~z<v<[.'"""""6mZӱrJL}x.[%K- C9gO2ftU\׮]a˖-XgtB,[=04kLQ 2͚5]/ea؞m۶t\.7d\jr ѡNQ-_IDr]tʬy n>k|VI 7)""""*vaP$(U?DDDDD?ADDDDDDD1"""""""9.@Qqb DDDDDDDs\ """"""\QU\\?{Utiii:UEζm(**)ۍԐ* DDDDDȪիѪe de5)f999Xzth:u6MFzz9p P#DDDDDȾ}4i!N)*.BRRZrr"KB>ADDDDTX,Qa7/*Ƌk\ """""3 Smď`"ƷOXEu1' Q &^Q-,Nz#DDDDD Q<}CG)xc DDDDD~#sgP=xc """":Kx5sxBɃqsp;j5Y(Ye_~U[ mjⳙRp"Rc%Zy~>\N,<^.}&6{U,1jOS.(څKZW`Q[΍8mh4wK m;N|!>hŢMSECإw\y)nl$u8J>̿V>{znA_$QP`ThͲ2@߲`kfl }:rǂ7j*7:P$4u}q*W] .W;7CNȪgBq.ց .0'j7pEExpQ#ĽόkмCc@w+؜c/&.P/хt$14ӛh,S ~WVO"""nU.{ǾۏO[\#Vڊ:-A'Եv]+T!geոЙH{ܞ/bvaxaL4x4Fݏ«1vU(?߇0||u,Kه?8z]x3nzR]EG͗4iEΦWdNj3?='cBK~w#UKxs6b+`SڵR wbkXd:GJG~^m+@ZlW^cQ&_;{NJGѦa\V~[h7op%5@#:㰌OT5?qP`iga˛sxP.m>枂3}<,}_6o5ܵE;[ScYܾ]pǏ'GO@&|$̜vXhwոb!8X%hS? MK&LƵ2|+H@ʧps| ;.c.%ۖ`[Q]4W!>i7wOucԐq3.h.+d=^arhwX|WwF~yljxn h!ff|}T/<vpu` 6; ]{uF2 y  ;6DvGu޷m~Nn_qc" U? S;{v#9k[)Щym'X .p0y][?pz7IFε5H:+% t=7J,?~k7mQ?GT9A5tf1|UV}8\tvUsGWÓ΃K1}Nlhbcpp/Ǐ⌿aԣ?`Wo%7|'_7xspßz,g3Ko 7o~_0 c1=eg#{&׿!>`&(:࿿ }_˓a߆Q;ʵ`P=sgws9R C[ir/?l8bX1?盏ŅÎCHhp .zbxom  @0(¢/Vq82sUЬl\-׾X^Εf!md6 ,߬lݛV5D˂;9;׿ՠhDnwn8,+n͑ ̤ō <) *65>q\p栣0{GzP4;-1=/-F U^8|jlrqw䣘=1|4IWbނ\06h ?f.įca%^Geͳ۟z)z뱹Ch\:74? 8y|O-A_g7trhmpɝ0?g1?@"""ߵ_zxm?y׷eY(޵eqR.(݆W`Eg|E=E,gĥÆ됭PǁXh+fD$q^/|ײL bރQX]LIJ t^ E [џ, žc"uZpsإ`9 .@2ht`8|\fw1=E>| 7z)eO1d=wOL myzn!]?nサ5L1#޷N݆?-:ovE:0^12=nLDDDDp%!a#4/LK J6)bߐqّo/c<6ct,oiMIn[i 7:ڽP`~d4BF=/~$}GEQ U]WJLDhBd4c:p@n- ػh!ĕ?)?BϡѨyz,XOg20tϲT8Pwpиa ]L詿Bwg4FpSqzoQ#?( ^'DDDDfO۫%\YK727Gc垿Ob$"v7]UX`.ϯDg F]o>^ :r>^LB<MI2qkqƠ.Fc W$tİ7";1B$7@C'MDѬq+rnp.}`[UXdb m |=euШUklu#}wty eΰ~?~ @Brq')W漮Ħԥ K$ov]#E#;eΣQTpS@e=ݓe18et 4) qg΋Ϧ`uJD#b-]7]7 {_x26"! Nb2Gy(:rvP1T=î?}N=89N.@Q Woo@>w߃W )HQo1Y")p-2a1㓁"B1D ?Kmga\|0)+ݍc' "^USvtq@k3'1nVǷg pt__A=$fՑ*Pch) yZnJYHC{~u8u<>dnW3qٗclmw[47|2}7Fv=0 \x d(mۆ,m}t(7ő?:LbӪm+^8/7Ɨ6h[h:vfi g0Xnvԫ[7轩J{$]eb\÷b%blctrhn >ADDDDTX@?pH( b~/ੇV=W\ """"CP 1/>G,I &^ qO@&}$tEW>xC Qn)4E㓖ȇj~D-[HgDnʯ?c#""|ulU|Xluj$;L(ڸAtJp{k!"",%%99[DlۆT.qHJN)"1)Q)ʸADDDDTt>Hf ֭[STRSѶ][ԩ|ٸ1rw{ub$)1 B.@"ҹ3rIDj rxX8* DDDDDLjj*'R5!F-DDDDDDDs\ """""" (ADDDDDDD1"""""""9.@Qqb DDDDDDDs :@TUdž عs'aÆ8MԩSGUQMR^ {s+PXXX&ݻcA83v!"""""ڀ Te[{XnNb_c_'„;ƣ2""""""aAU≧3z$t͚5lٲ?3<Xnnjƕ#G#""""" sӦ' [n뮹g~:RRE%|cƍzxiؓ7]j~bjނe,xg.:$cs O>y J""""""IK5|L|o`ٰo>.>ĉ&M =1ƨIO@X\:X&ըVS)))"S1DDDD¹| DVFs͛DXDzݻDb1䱉(>m _3wb"^? W#nBmԺu@5LccQ<y'T|?ih'u2"ؑRzɧzT̲,|ɧ<6 9b! ImO0 *Ge˖?dž OqکeaOdž -[G """"N++?Q\ w^nU p/hu. W_yE`|S/*“_sՕp*FEDDDD1c~fX KtG­kQы U*O0Юg\w (((PU p7௿ڵkVUDDDDTLjP7:TIE\ w:wSx<L{\b.bv,׵kqEc|sJ""""ry *`bΜ9>b뇾a3g^oz 6}gvu:S\ N\UD,N9EI1HLL[X<|rmXxI'" xrmDD\,<Ӧ lٲ2y˅k%^/3vp*EZ_iU7t,77)NUA[ɇ`؛ѧ̄AVf&>ތO>v+4hCDDDDqǂeہqMNǓPFJpvhm»q?\x9T-X[o.¬k>7 aLMBƯ?#.={ɓ1~,_L%]y痉ۏe?E`X'`Oc%pia1wD|jxqهz@ ox3NFWWcy^z 76^S߹#SO=Cn|_l5B0q`~8\{)^Y=/v N859-B6/~2ex8$t8R݀;q߹_73ymߌmz)Hظ킡{!3te[Xj~%.XqI?a< =?mz,xw]~Ő3 q"\}R- .'NǮXaU , mqp_tVAxO(@QI>v.Fc?w|We|,V ޾kÕg쁒B:u6H rrA.Q-ߋ >t>T,WbǼYEɂ}:/ɾS؝ŋc ݱ۷o/ƍڠ7(Y1 !CvpŕWa6c:2pI=n8rl8$)/-[}F6ѠI y* w;*Vhq0s_F'-rѽ< wL'݃g}(,p||Pp4F0v>86``P7;{"Py<Q/FyHO`Ƕ\XIҎ 6@1řXo~1l^3$n]MU@ez?=ؿ?{y "݂w7Lƍ9s1[qbv_\0B<3(((G&"""b~~r`pu$3 N\]nv69σ7/}y(߄eMonZM=Ԟ7bD:av -Tqz~~G<y,S00Du6g!+ךy2ʃX1u]x7a67/}y[`}N1p 5%b3'n4>=w@ؼ?ԾUpo}.D׆Im  #9ՙ *svcyͥ(ڷo^zxk.[.23o-zr*\ O>4.2\zŨW^:""""> ֭Z۱vW|9q<1~p$q 3Ц:q S7iH݋qcnx34A?6¿&Nĵ߀K.':uۍ_~>,}4/Dzv}w7iN>;{]9/x< cնH9n4G'X:X NYWBfGq] Ô0sOA$4fc勹2ODŽ)ႇv yę5=x/,ЗؐncS\ .bv;vuN17}u 3q=vj}:"f dڝ7a>HIx9xpT+OOKC޽7;ݻ&YYaٶ +V|-’%K_Az:n 9op8m6deep$0,Y~'/~85kS9u˲0o<_ .ڶ=}63.T"h"t1=2@j^EJT4M}3 ,08lo nX<aNΟj bƆP/cQۇ}7/xLqᚫB޽C~CqJJ ki! FII /Y$Oou """ :^\.;\;\eɹ%c p"ʰ``b"*_xǤ X미ihlذ1~q3jz!*#xpR߾8o_,[gĊ[?ZGf@՞DDDDTuVW?6AUwU*&sb`6n"^`uv7@,Tk׭e/,>x<h={K/<1Fذa#.~9֮[X?ln o[(d:Ŵ`9)ܺp -/Zۗ"?#Gyfx套pUW?vqWᕗ^BZ#G T5U ~˱!rkN:'D{1=6.EP8雼)n݊G^|/9c銗^x!G֭[U%U6[-,E|(A-Iٗ[ݗt\NMآ݋1=zkflY e@VVh\UN~Ö-[0~UEDDDDgVOH_ Ne1`^Eyy5pEͷ%_RRSOu֪*ڴigzɾ_ xxTŞ-ZxUTU*p?Mwj釳1CU-@ر`NO˧!( ۶oN njۋվ}{=*0T """"%*ᚭ~zjɾKNŕ\Gu( 7fv *‡!eG)]rz]z)zƍ={`̙*"٣K.؜92g lAjj*BIIIANr`5'ia3I>a2n[IC*l®.]o -ȾY&f%vψEۅgP?AgPס@( 맢uVS'1BD^^~YUTm6=2_ @1|_FiUqkfE zqC/t8-j]\ʈ [dX&goF%-x_СػwNQ™ȦKμq"{yaWjN*A(crkv7Eǽ(}"""""H'cT5Z(}jA>Ns\>oʩ/9]Ps yCL1y`%"""""" sPsX9g5I&4Du,@b Lӗv!""""""&9UU996}.bM˼xN[7cݜ:g """"""%􃞛攓XlvB+, Z7lwaX_t9q sMŒʹGq9^YǒS(D2,~웱}SM3_@s.QCDDDDDD+N9..:7bp낍M?XLooQUsQr=PpNk,@ ]] "']N81Q,yQͼԌCee$Ǧk ]LB*-.|sb7-rljbeG\3L39&ժ‚{V w&X%>B(VP:'O?'"6y&vBcBO򝄪˘Yqcd'5<*Vt-c$P5DN%M_nAm61ǀ}L '"""""P^ '9frrkr͋& A+V5oΣϥ*nLR}9qC *_O@h':nȾ{ᛸ\ |^Q"(@[ (b5[}~׌5]DDDDDD5Dirk~Nb^V$.EEp`jV̱1"y^dN%=6U* ,E93}%]@_,t؜ǼL܌˘|v[QMfKrcrk](;759^|[x0 bu]ܮ_r‚d)nE35I2g2cI T<'3 zBمyNcv['EO 7oML_OuO L\/BEY'+s<:fVebS)^i\yfB,v9K( onyZ(3<.>uf vI/J]L1<Q _O7'$q̢\|qIty}&'߫mu&3:'&'foL\/8Ⱦ:$y-o:&ɭ!kXUp ^l&یal LN /˿ot?s\p}M^D2n};vyQ,dd^f13\Ћ? c[( aݹhб]Ŝ\Ohe[k~[(ƚ' .7-AEPvAӜǜ[.8؝ӌf93b@9zPM.ȾY4q݂*f^0y]gȾ똡 gJDX(?Q6oE\˧E `:BiN1}Mň$n9˱]-8T+…?D0qtNU\P:)6eӗgydfk2onY|O: ϛ\0O]@[1[ca#"""""rNgt_fvzlz'z15]'q Oő h&& Ƞt0 Lލ0f@99|fc.7cODDDDDT9_}3/9YDyh s f?Xfup"TXU-@XK&gwŖyJ //,yANb?r!°ysPvB̢Zwi s|^ua.eߌmbDDDDDD@'zk24fN IDATV?yj, 4KlMp~"Bfȱ꾮b1W Ÿ Zyq&hs1c}bAͱM{4[ׂTd"""""ʰlɶ+f8M lu,f9^5:L$QQ NxXe ".rM\\rr/"(dY9S"t0cjV }N­#"""""p'Nu(;[ӗ)jA,8Z̙¿;D81 Mjb@1?. r!bn,tɛf1ŤPq1QMNPq!- }]#t\d8Dnlb].LAE{" c|N9/k-뼹z`d<3c&/bXaFM_nzHjR$]=cݗ[5Nݾ}s$^0,ͅɿǖ،\Qף>n!&l)'"""""nNaaN[͌uzlHU $ ':*.. ES#03O@nylPc:urNv1"""""xt}Ly[$f7ֱ` 2oN5zChv`1\ cٷc}`qs](]dDߜC> ajXyy LL$Z7B縝HjAׂqq2&kt"A8 N1$7`U.ZP8 z-X\]]$Pqy#>Sp4Mj&z=wW4fPq7dNnuߎS)z" 8DeNub~ 36o%2خ d_?-5}9}``9""""" .X(7}:Z97} 1c5t)_m=Q v`9ym79cu/ҜΛ~SNV  5B剈] ·'v[P9}ɸ˱Ϯo'X>X."ў;^a71˸q$93[v9]ǡDZODDDDD"zItN9yy=vE$ړPNj4ik:,s::.r/bFCDDDDDT.g'zk%Nq1c [#>k͇-pi]_C.}Ct>m%cݸu"""""h$WnaޚWd`[.w×PVj3vښjydLjʟ׮ps@s3N98P5v19vu"&1+Rd^!Ѫ[7V#Q}Ae&z_`7zkxjRg豝hՄ-pN Pn®k9Xjm%S_V<8Q$1u:Fev}tNo Kt_o%c'ԅSXL@=fE&^+RlɮN>DDDDDD5YE&z OuzF8uz$ua6cSs:~q.fJi`q x6 6)vb.&:rv1îNN© &b{9MulnPuvc;Ѫ!"""""M™Wir]L VgWI" l(_[I~v1MC 8iƆ]Lr/ݾN`­ ."FrpkjTԷwTf_"""""X̄7ԾNy4wKN5N}ɩƮ.f': ڈzR#Tԗt>ұXׂՅI}$j ` r]NpQ8Mu\I:8píFzG:t.ұ*濫śNCgi߮8 {T!Bx&4alC'MsZҽͮV[Ϛ9iNLm~mϵyi~:'9[Gc%\=ԶךIc:"K9:"8Wi,]rXδִwKh[#krب?sl+r\^m,8^ZӚ?䮁x.v[V@Y]+rXD{Lk]k;g8/`LːݒqT3+^f؝}yOͷRQ<}fڥ~G{G^)v{[ԣ1Ά^uS2$cY\ikrrkb!x>#^ym#:`sjskjjau^#%}[t>F.p;z#god85zh0Ϻ>>nm`>Λg_JguVv8ϺӬ>K꾫@ĺGU}{WV? ?s-W=\uOw w;ݓm;َwm ؐc p<63q~Cw0|-7^<*)|ͺ'+%IENDB`kraft-1.1/manual/images/de/unity.png000066400000000000000000002034501450127457600174710ustar00rootroot00000000000000PNG  IHDR 6l= pHYs+ IDATx^wxU{vHHHA ( >QP X (Х"{vc$gOf$!!֙g&,@DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD (o"""""EW!QbEpy 781 """""Q em]^/le(q9OKk+ω,+r_sKDDDDDDR.~r8k(QR\EO@Iuw'"""""[JD;P7P+j\+Mo=WO%9]NJD__Ti9ko<)iχH(i~>ڟ <)-s+(>-^Q&E[EGQ: .*ʶ:f5_o_5[E(DIe[cy[ŵ"""""@+I/68ྯ0=QY >oflr[}fl[e_rȜ/m_rmFa-6Ev&|l;_F13rɼ#""""""hsק25=u;_RLv}ݧ6FqocFb>s?D]QQ̈Q1<_$=uۨ1 Tjcy=QixFq51 _Frb2Of QIS؉b*5׶LI}V\Uomږ}j>QSۂYlr6`>5]L퉷Z'K.P0][퓙噭ԸmO| QITIۨٺ]'@OV}\"~u{9WPsԥhluݨ]XPm0g_1˗bݗ\ rD[]-uj̨*j=u7>hbnSқuA-*xۧ#r~obj_󉈈J*_'jnj&g> қuy),掻w}>dx|u]^}u]^-}"ƌjL^W꺠wR0q'z~uMxmu/0cݍ+ձBc3]Qin0|䶜RΓcQLcfr[^ jܬLQ=D8&Fr-/uq!@SǗ嘼̬SP'fm5K"QL~USWs`7[W<{o($l;urN凈W7嫅 ➮qOE y]m&pߧ%|ȺfbmA|yCAs>riRlmRewG? ^1 fjnI1u5B\|?:!0irʬ_mODDDDDtx/j\źFm Qxԧm/QǗc 1u݈YYk0MՉڧ`'rb"[ե/Fe'"""""\M=Mu./QysU GݨiJ|""""""BuI׮X<*#51_ ͹O.Bs`QbwESn@X@!/\0 rXW(wC"DDDDDDDEE oZr{v,C~@(Ž0 A=Fmr1A͑U Tk?DDDDDDTuP)8V~$RL\zu#n5bz`TFbj\P}b].8x*>XXiKwr2q n*XjBsƌj/1AˬPR_|aȅy).G,ĺ1O`g]w=gOE.JMpUFhw]k4nPqdܳބ;v v\h78Oe՝q1ܧ<Dq RŁv'ʑXb]1+zřVege!ٶ#a ѡY3uhgz5(zK_O?7vZxT=08qJ|Ʌ) ?!FVqQu8bjJINvkݨ Dk7PcQոA= y9D]4nP#ǟ=n<5*B~'& j[T ƍb Gnq9 jì_PB2jl{&[XMt[ׂ}_Pp,_u;`""""" FйC;TZpi\KWENNZ*^p y9އ8qJ1՝qu¨9cbn+ѯn 9vj;`!+ !m.>qɂŹ.r r,T *^ml:N BVF6E1;µU^ t]gwOtΜUSCs]^tPL<;vQر=oX*WgGʕv_"R!$$o L8^-=wEk[cV [KY [cG![Bqhn :h>-/u5Gf ũq-3:f1WqBZu=bqo>VArZRVVZ(M\*]nn7~uo.Ya#"B axs@{,Xfzj|e=ĤdbŐw###Cl߁CjgL^-oKWVJ#|:6*vT FNQNmiJDT8u ~ ]BHpw֩`r_4jP98pM^ز}Y6׸4l^>4-r9azuDZcA [/ĜUA-OW=}j[0Uq `yCu[іpOJ nt>:ϩ/v;-_ՠic@89HN5?6y5ԮU}{߁ q:o ~:b菱b_hڤ!bcѻon>+N _쇪U&Om;~ IuҩZ\hZ_w?]ѥS4jPGwĺ ͘ݏزm@߻q}6/?t6wn1ݏFx\"1{j⁾wSvZ-X&0ys@q]wnZxOՀö;ѼYos }#֮?4jP?qcO@bR2^,j׬'ލݽ͚`/\ODTB7)f[V4w09,$8<>bi1yxy/ yxQ֡CGcϠ\E3_n 8/",, UkFhܷ vQ $e8F~GSfYs0bDR㳱{='Lа=?+j'Æb Xo=8n5o0  **oa2֬\<~qΧB\rq}0O &: E¶X&q]a 3/l8ߧ77ĤdTTv:6jBLt>nMO>ty鵼~ohX&rss+p]=o=>Wn醶׶›Y.3~B͆\[.Vۀ&LBnn.^~)}g|D 5>PJeDEFbwqJժDzF3]xe瞽<Q|عgK/q>ם q1j@~b'[2,>14_ :5}"&LWl>@#ȌvWhp>DX(Nݮ#iT+JW#HJF\#siؾBGhE4+X eR*(aN|ٗxAvl8Sf@Dt);4hغso[k=v2o#HNIAp\bσ RgŵWęXoK$&'E&Xvc;o.1 KL{PZռ~ozԾ-0 'O;x-b%ΏX$%ilu7vo&NFڅt@>0@zuqe:̄ݮGׁbloK v^JH {U5^ >_ h޴1p8f-*]41tA1"e2D: E)2<'nGHLXCs 'z/B@HWA@d󸢢0ߝ\M1"KE޴N>|=wEK]R8>߱}tà@tAХFKbQz5XHHJ9m]Ʌj͋:}\{8ƈ™ ۱ .6z4aX_s{K̝)3`ʌjIxxxG0r8~<=Q4 H\kWDD5--۱d*жlR _p~05vyGx/ HLJFjUp=zu("K_ BZM铉0Nfۚ}mB}QK>h]4iݢct:숮K):τRiެ ^O^qDDo:85y Ǿ F'kG?~=ƙα;YS>9%{Pt_ o]//SPB\s܍mw%?}_='1g>f̙p137wE⊇f3\b"|Cd7S6y9qF#pq%lێc°7_=|a99>jۏo$lێ ;'ǫ״}מ`tcJafPcD-6WD-O'^D(-b!B߂Ht 3YCh.`)Q*8~A-51~Yx ?R""*^:Ắc뎝2s6^}Y z}(38'(\Ǡ:Zlؘh#~\uj\bboSZ&<t|= Pfu8yYYW98w< ;#yaͺ v8t)QFu<|p[yԴT :* SS:XƉSq9DFG\l 9q%{ܳQLґw(g8rty|Zj߀EDTY?57 [>v ؽG Znwޱ{aA1ۯMkms ol6_xPo]rYsqӱxo:ߍsIضc6m'OMs?w\9q鼾S1OCfБ1j 23Ix?sKiү0a ;ƚu0nML !oi=Fxx9a8|˶A:N;wůfaȠ0赡`/#n7"5Z.:|~UkVXv=O588%Pٵ IDATYرk4rB W5ۯ}wvF煃uMy]rL>yr;"g/4uxJ'n>rŃ|]Cez4- \B~9z:i)B}+iЬurKL~O^I#4k鲦zwvu!=zq_!g(@]ZKK'/> -UfqS_aF.>mw}r[} 9&?qc`ˍų5u"tٲpgbH9dC[uDׁQ'"""""*a5iog]e'0.B\F~O]2y^* :~PŬR^ɥ]R,@SpY\0'A>Cpp~stjEDHD̋UF-GN#R4Nm܍CPS`|"""""i봲[|܅x~M7T]l߹cozDcxR.@8ELߊW@b;3ff" dB%@Xuv8"gkbiPrt:=XDDDDDDTR;~C~W5۠YㆨP!m;wc_yvo,Vuy#puQ|wl7Z7.aDDW.3jB-HXcxEnnrx;Rۀb9DDDDDDG-[ߖjWaHsмzI ̋r37ŋE x"Fc_~'ӨRxS5Txj 1U8-ejl݌؏B+00q/ #V䘻1śÌY Fܽp`'6ZmJ1 """""˛QA!~u/LQQ 0>8jzɕKr(|mi)m(nSgіm5l_h%ym!VF'(91.~5Gf+.EB>f2wqu{cԧFDDDDDDDf ( j[MlXรnct2RއQ\}UEP"O,RPސ@ a.ef'ŨO^WsA-8`]0S}Re/6UP_ٺVjAEŜ\SF7(;8@,/几1 """""uij45[1dj\mtuTnMh4y*XR&SOs<I=R j Rf՘zեX7"Ӧ]B& EdCDDDDD^0VuKm_mfw›bԶĸ[" Ooŋ#ѽ&gaT9s+WVÅ6*! ´Ρjy\Wh]^uWf179^y^ԃ 0ZuuߣLX|2ipHdCDDDDT֨sPu>a=vt wy 0Q*O]jL^Tdե*@1:F\m(5&ǍATSL0CfdQP;FyԶ`vsONDDDDDDHfQ-bF25cF(@\ O( u.N=K@ =@fy1@7;DDDDDDDnwsX*o|,,_^ y:jȵX6'ZVM5Bd? """"1sVu>kFz5uL ,W= sw>XVk[kňoK9}Ϩ`Wq-@~0`ݵ q, FDDDDD~?*S]_ oNQmWCH5mvdGj  pVGNz*C編4=w9 )]HMG8h|TOw]^PYpw`TYQ\mcj8}46'$a(ګa*#8) !b%DKIn䤝Ź aE?tL] 7I?͊rqѬ qw,οoz2;o ke3{d"heb|9DM ڋa) ջ1z_ Qj1y.7*03KnFR0pЋj'{?2kJyB oyǨ'Ꮱ`ڌwǐ1ϏѽX9G0V߂u.&? `f`gE'=i~ vHَ_~^DƿrIX}2:c'bRDDDDtCY CC1Ks_|~Ǩ}1nHMK ɋ<=q5{19[nOb̚ {>+RSX.7,U~5X ~dF{Q """*3~+|S"+M~rwpD\'T}alB Rb8ebu:έ^36/(;'`l^x};4FH 2a:V.;"uBbnC.7#55y3R%z?}G4Թ XcDZS0evZ*m:>NDDDpfsQJmJTщb䅖-ZհX 35ΊgrfdnNyBG+=k]&R<.ۀLIE5}>Тo#ٰYC|Ϳjnl $DyqXn/lQ"""ˍofT}_t) =nc'fTX YoNT2Wi?K܋z!zHyDsL Z*>f;[N$ "9g!-%Z9DG:Η>(*GD}aE9_[&RSaDTDᾥÞ4BQ Бq)6D *D9/a(b!ܹS+b{ώspdʨn4vT"*M'YA*rAN(QyU6j!0]~k]~BOZ/oy;hVj?kaê;Py=(~z{z 4Uidž}Y,Ūe 1gСH߸N\ xX|,Cozv.2~ 3;ՠoy+~Z,9϶,ؑLX.66| 6gf  q1|͙|GWD1X|Ξwz7DxX?ADDD~ӗR u8YZZ}I!.g!W[G-X_G|.8q17{·C]WYh|5{VTz#8p4WԀ쬬+*4 7ĢX>@ >__QA hc!5QY% Lh:? \b$|4vj0ǼvZZy L;4o :tށ.hj^YP]4o ˾';fQ󈈈G8`K d<1Xܸ{w5 .q ivl]Fߪ*˰76#ZDn".mq25v`E jr?^gBYGl3ض1#FvrLӽ&cH!)1vD0vŕi0n"Wԯc $4 :BG谧a}Lldž$`ݧ^5P H5I""""QEqW͟'JQHH1.;MW,9۰liǤ~KC.|tk |{;Yϻ)>xKE_cQA)Qř bSñT\o?d_)7c4DDR0YP|OOm-*pQSF+ ā.U… x'wߡE ^ qF.Qmʯ8f+p~o) m74a݇I!A A+z( `ӆ}ΛDR=5] >-Vs\}x>{4XBY[l"C}/%XozU/ @ 7?(-]:\~]b~;.-X(#X<7OGٱ+NޅVK aKކ_m\5LnhR-:6ƦlБc xxEC""""*G0 IOOWCT*QQ+T 9洘ꭨjVH xOm?iD7#CE޿ M,JrT5#"B1R=f=@퟈ ڠ n5Ktz"aA||YX.MLʵM}m4/!T%kC' {pyTQ-ߊ>}oChjt{[9hͿy$srX W4n6IE5ǃNA 1srlزGϞEc_>j.tGz+CQ}m$Z(fW]Ge7~"*ruLyIn~""""""" 8 (X """"""c""""""" 8 (X """"""c"""݆ 9jُGn~ ^Bgg]̔TX LOA7_An'Ǩndz?FK;K`qM>jgډѹM[j/e"*5m||_CS C++bdq)9o^Y ""l"){?V4~ lH @Z ljض{_Mo c1/©o̤qt'X*;',ZI.cN#'z z:W%w9p8>c66KR+ym<:Ct_; x|`*? ttsa3)\IԭS1߰h&+5G6 dlW'/[+oֱr eby _oq=? 4,xv̾7|7 FK0rzv㮘Sz&7ke|wlyNL<lN!#?&]>CD{Dو~4tv6.qA=RC ܀ySrm"{4/[Lo,^VƟCG`,Vqy4-o_ܓvw\7|:O,>ċ%""JDTpjS22 1csP`*"z ֎뚿]*K-֢CCj\"BpU\E P1C+X+}@PlK߷="J.6 9nxq#殨]s H^=c]k D"^X1ݙk{E+^q(N9#1Mx(T@6P9X+m9wi5F~mQ9@HutPGwC.b뷃1m97p+ZxGyw!㽸Q$, eg\}GOځX2Ƒ 2?tZDDDW^uz7c#ozDf8ڪ#i-ޜ1a"y~Y"U’&T_HXa۠$"%*А r\4O b;j2w ndz˱#\"oa˶qsk@\\X`G~|F|}w|Z;b6 SrOrV#J{b0-bGX-]?c̞\d5BdګPƳBu`L c[GOaAL8}Zu:`OARj V?9ZTT. opDDTVB0ժ*;ث`Bxi9h3yxUonP҅"Ble}TDEETEEe"((,((HP$6%Zhei>5ss&Lrh93$;sN~;O~;Dk=}m1Y/ky=ޛU^LPʟ$YΔӤ29XʴWL[冾qP- Ƨm=.ՅWEq .+/Q-mlh S p&ӥ֋x"ć:'!81_̭GpۊPƒR4uּa6o2s{3cJ}xԽ\?^;޸Vo6<'j}<Bhxʹ a޼qđO~>VROsCߝEO25ޕ/0rzxrwOO_X#/{""4CDs}SKYlTmv'/3!"FuSMZ}4з=T$$-N|=NUQߤOV2llЮ|s &ˣMxE"R|Xis5lD4h)ŁkbgE]2,]9TDDDDDD<‹ƣ{/~5M-/pٛnn[ĥG> rp귘쫫 """""%D0n΋ty+2/jE1KkFDҦ#L_w\o8Ɗ=wx~8[ӴYK:ͷû53䓣 >92⶛iAdޞy\GX=QlM-Ǝ$|53Oѩc'zG HdGߣ#Z6'`&=uq<`$1hќ{{Hv _7u#MKYI|2>6U _%7?s/RGwNp)JBXv]H3V/z*"""""RlcdwCBs&A˹]#C8u8!{jLk' /|ș u͆TcذZp$bOpt#]znAMPQ.\.jӁ3OXhsl5y,xg&Lv3u]ݤd;sYy?6lqiϹ <S<BsKp|Zt.s~O 6YAG܋VFdNrPY:ncna =:#gOY\ s*Z^'1,z?DD $sT.7% <-K7YhtCw,ZdpIBʅf[V̷|㌙ߐC y.pR ]eõ;vג]<^KޏݍO|я1bvunpw(܎_I ǁw=ԅDpDN; k/$32?} yo3nVOL>d,dCو?:I̞xWgh~b@؊Y k'kW7DDDDD_49ǦyzD~#;ł-n˹,w'v7w6ѽ{쬑lBA8e1r`8@*.Yhq$:>0NMS>~7ÄGkz I Z@@I,1:<AB.tya62Uh16X @6CxtiI/v6挸v-#1O}qbFYŽ_$_Aӿ-"[Ӷfm9H`C6SzӮcwƭJλ=du9/ hOfAMXIy:A <|aadž -{fpz\Vo=g]Fn/KCԷسouk3S@gd9~)+l4)!Jgө++"ȗa6Zl{2i(^xQugKaH[ӒUwg0nU[uKT6uFh~t+kvnuN>Ժc5HR~o{1P>cN}@DD2DD ՟`Պ5 Wfņ8tڡ-n_->>l6St9&ov}Qtis""0|j8t)))氈"% Hq8MB8N:DZZJDDDDDD R at:q:M\)#!"""""Am*|%?pZdmDDDDDDp"R 'ʻw]`` UV͵J*Ęj2W֕—JBx% ܓyX,Pϫ7 #{=$ąKDDDDDD R`9oР9Åꃂ!ܴ  s"?'""""""WR sUn:S5l9]#<< }ڵ)W\#$\I}m?E> ""%!fN6[IIIR\Xzz:'N.dl6lVgSI=p9maUPG""5Q<;Nc&?ð>iI/v6挸v-#1O}q)pڴX êӸ]sjf֧ wwYDK̥opOIתѻƱk]cS`nDiIV=:k; IDAT @:럎bۈlҌ_&)uiMD(y1}x>wpkVс~㗲{}GgZD4#u \ĝ0'ZDmr'N~53Oѩc'zG pna[iӲ%&\uʥP(> ""Rsnײ{|-G`{sC9r 5-ov$R82 yfFoYDzY }7|eckرa!ly0՛7|luFaӃz0[(:YO丹7"4~olf{Cb!?d 僕4#lH\0O%ߘn|j2$ofX}ɔ?2~[lbGyNӿdUl?3f,'<;#,c,Ί1qc/^nYfKG7qGeulf67!m߀Q@8yri Mq?I~TT9tAkoOOuWO~u_ؽTj@<ഹƁwҾMmoqX-aSS|-ۢ d͎培nVd4=p/R'EM5;GEw9~F} """E )Nͱ_5G٬AĐR 1111WTҥK(k]p3As&RCы՟`V+ր \"ԥ磯<`N_8k(_g'e-9~# RH淥s{bXY:f+U$bOpt#]$Vg ( XC :6*V+6a8;G޹ n3匋%.u;{UW,# gy%||NW@.@DDD R`# rnwp[b.YVs$,EݍO|я1bvu?Yǣ -cyhc8ѥ,g .lbOL$(ϼ=1$gQ %fZ}tkdX5RԾ]>{ys7|g;wPmݹFH<2ΥY}%kًL{rY\> ""RXeDC^ .\sMX`` 絽P{%W%-{)&swHMUǞ EvV~bwpE,ɗzF[o?G^>;]mk%Vc1df8Uo?u5hX=+ⶭ`?άsSL#$w$J^ӖIpbR BPp )~'&=jvw}}=1g3~㙿^.W~),!ۉ91qFS [.6~\u6mژCx6#~;>~7ÄG.s!7>!eXï!t0oT:ZPʗ ^ۮܰ3 5T[ (EӣgB`'3rSegpR]Zr8k^L~=_AqGx[xzT)mCne_oݯLFt0S+_π3[2˽/r\R}@DDw_nejeʮJ MW+kq_wջʡ OMe]PsHLLСCԪU 9III啙ӊsm- Œ:y 3%>>kТE UfjQrng=aRD9ݲxw]Xx >UP&)_RȗkѡJDD93.lX ˫ɜa*3ŝ[Ym íld\F{\X-bNgg}y\'""""""C )0W}y Fa))!bN:xO?KuS]mʥq-:^]J@H~Ϟ=EU\Gj2+WL`+եXn'Nә]~;̂ضզ'L)!)u5b^>'""""""WR`9ߴi9D:uZݻ\zھEl6sXDDDDDD<R` \weʔbZ DzX,y&B򊋈HQB R8>}:G9 N8+U˗wk9r)'""""""WR`؛cM0W9z{^"""""""O )0 U#v) >gPB O  J@HyHId5D.5 Dt{"Ōgg sMvbviAҒa4#qExo"""C# @{ruVsԩ}L5ТE G|||vN:!}"ɩ]'a?P| n4ߘRaAOQ\sٿ#8b1Q)  +P@VX1GB%E}7Ht8ޜI ;'?k37C@ WoG>nE+c)WHI)R at:q:3Ǯ=w@2e(SLv999d u񤧧g!6ǥh#omč\ю>S6qo7LD@s֧=""8eƜҮe7F/TY"?n^ex]KZ’qzqn]G_5wƷso9|ٕϘSܕDDD F@H˹M0Д͛sS.ԩCHHHy?rǞbMxvTtA'8fy4?îw!Ϣ4|U[އxo]a9%~Ǽr7f///§ eS4fྷZNv~cߧ3lv_DkAWG37w5׾_tDDD R`ă_6[[0Uj2W`N6(Q9eT6qk?X3."ߝɷuD~' @5F^k lPug|ѓN`FINYB)z)s㒓Œa^15ݦ[uBq75JYzD5G1pRmVa>~u_ؽ,{13^}upGveϺJgө\> ""RX aQbEoSM*VcF~'Eq&đ_ ̙&یp9u9{?!z Vk@ANlXh$pByas&ŎLk' M: 6[AN -V+NÉL"D G?Bۥ *擯/ تPJ>%(i1O>pHaQB ,?'<vKu}Z63{ogH!Y DKP MtV}!\b<ٶ'&t%'k~|9ˇ<Θ ?@ka}|pm;eʼ¹ċw`_tf),et s0 j֬yy MTȱT#$Ēy-T/Z8l CW"v#.d1)JTcq*G`R6r!Myt 29MΗRf?wi'ٿ S`c# øH}իԩu5(9bcc 7۞d0)"nY<ڻͳ HF%OgK<k\La*neGVNL?WV6b!׍<%4B ,?# 0ÑK )`x""""""%.B)NEDDDDDB+NS0_KHH -- ȼ࡟6[5Jau>D%zsrk ժǪXhSv㈈Ux /l1 V#S',~9a?Xs'L&r7z(k(<}WI{@ܳ\#wx{-LoGGqdy4BDD7&lֺ;ڇgOL\GOXn@HY'No!t_^'1,@0˯?6zDDD "$\'^6 $RaeJY *])vlɯ4Ήe{VoĥWGܳ\H}ĥ9ZkI%t"""ś`:7+M<ǬGWC7[XPѷGC`!3DzIwF5jzo`|lZ^1c땼{+~_:Ir_` ƌwx 8vy\quyq°nlnZ^neb^YUM88|m*z"'66ps8۸I"͡lų}dTnt0W)i{""/%5.w]we=kqVvdVv&]u#Žlso,MbC chڨiP^'1,z?DDDMbH/fSd|m 1-.z=g!""Rt(!"Ŋjo&.J:EHѡ)"""""""r)QB˛2Jr#T9w%t▌pݐ 1[X%VDDDDDD#h FI8{cm`$8U1+N~[T۰ ߍ(lH^IgלLՄmdYt96vyd1S>plaj67Teپefg=,55߱)4c&ӿZNysj,x܊լ[oxNePW*Y/O""""""r(Qbœ0w@ECNJ$ +u_5;aWqo07a5ĺo= G9zzjŻT9˶i+UQ-%.Mok&jK?F_H`/醧y0,'|t  e>c1$~3K\v&j˫XFV)y& GF'>F%8{تPʹMjÛYL͙H1fD/ sRZ-$IMsaf*j !.|!"""""R)!o'^C?qa\a #L{^MgjpK:=ũT#B^yͲd8`B`n'g1:_=7oAϪvpL;.e@VEIDDDDDD./M(RiNO$ՑArV>za#j!(8LZ;zb:gsǝ9RsROz.FO#󖟹qO18ԫ=#l iXRH;g߄kPY y/^x^q'$""""""F@P$`C|_e,Gބ/pM_7Q 2ƷW_&#z:t˩ gԭ S>Ã(w}$]k-z6_{QuډW`5yjV6#~;>~7ÄGVC7[XPѷGCemgߏa`ڭm^?3L㭍'9(-jsM?f{$""""""s[b{ټFaXsY9խVv-Vۭ앵]ЄSSɧ^ߦW9,qbcc 7۞d0)"nY<×dTn֧?1^ %{zz_+T IDAT""r5%5.w]we=kq>sřp+;FV5ۼn䱸u.)""H~ylx艁4 dS`|s"J}@DDX_b"%lt:Ub#E?5;Ng^H㸯iEʔGbE}@DD"I܉8宨Y1{gd|YV-Tf)DDD% DDo]w7o,yʙٵ,H> ""RG`8IKKZpnl 8_{ 0 +zbL['IJ{I-EiI/v6挸v-#1O}q߿t"""ś"p ͛c" $9 t{koّٝZ=?2u &7{KcAšWwWĚq)OޏWkٺ TԷ6q6k gR>/o}K8w:M[Wj̘X#kn>ưװcB=38=`.7oflBzKgө{!Wv&5N:B1rs23Z1ǾRqیiMf?^h_]:x^3NcHr/l]ҽүv@MCx"^r^6}jTz/}]nb)ݎ᣻R ?-òӲe]2ƒl@(W hFP5mq᝴pS(5/I+P'mGO:jKgө\> ""r)!WvG "եv:dI$oF"_Ϙmej99\yeGZ.k189,y>~(S]^?hg2ռ)_>Sp:?iMnPʅ ""Rj+ٻ(M T)"4T*YQSN99l(z'"X*CFze~l6Y& %|<̷|gBŵ9ߵwBd*pR{Z>mH5%jа̴rrjA{۪b\fTS&rآC>PRR6 J=VRn(+r >%¥zwz֮:v8K];uɱwK?dݬ㼢檳X6=1WL՚}C #N=~M]p2N9L}rBnF頠l kPu ݿ:=P-Z~{c\g8ҸFϘ;Hb/y@s cj*>7XYTNWOK+"4bZXꕗ]M[( [$OO:']l}AEﺷܛM8*hrT5VLkV֬Z%99Y)2-vPqiWQ)I|fQRY囶yU4܂R*56&PJfZ2Y]?\epl뒤B\@no]#U9Vp X{ 7GԯoSws@YNSFxS,MW搬M?ڝ!i(4.;nbc Jq@wԄ |rf-mp*\(@)&$R?ĚuJF^z5 PC@)K*D5@b)P٥*Y۰.dA6e6oڠ_|G Hտ~Lo@a-wXw+b9ij (ŬEe2*&0\}\= ׎nIn@^;\zP Fjdjm1^Aݪgװ. 4]ZJ^RSߡc77(ӻf,}XF\nWᓴhK Sh5oo[> t i-(bU 4nuklk?Z{g*(eɕL^/v+sN7T]zSC~\}O1+ Sx藳4i^&]]"Vvԃw.nfi}3te.}k9JQJp@)xDUl*© όҹs E6RϗTH~hu>$5iHI3ZE2w:5ZhfVy+|:_?>ղmg*>HRa3iݽW9_(l[ڴd*eUzX Rh1x^+FEюVyǼc50 B?m~*kZn{R@Ms޾>1SeğƖ/mnп^׿?_zTgv7y:Dքuy{,wJR5k@=s?WNwR]o (r$E{EwQ)g]]rrd ; tDZq hWN(lej٦mPe9#n1=C.9#?{{ϭ5l1qjXotGXKsS߮)2'PLlCeǪ}X5@pzQf/*#x۪EQD650\v-V[re΃yr'm/ܰ:6ᐔoM6hvF[WJܒ\9Eۓ"pqe~zT.{hfj4h^S.I|%oߦ}\ s,(]@U#RrjѺZn[Lc4Qf :Қࡺ}vqmӣ˻\)uoB9S@0Yf}8h`;o$:Ksn tck:3]_ϾM~CGhڪ,kZfnn7dȐa *Jd'nӥgǵ< 4guW4;!A}GNҋEB36H2jW @65`;ZdӞl[vThT'\i:r4FMդQRS"^-H6!*y ܠvZlxNg}9\T'3Q; X7HסdGI&*.^12d)*} p&Yϗ=hV ňRL}C{P$jX}=%%m+uF *y }YrI nVE fӎbDk7WwiPa"~OsGo+gKuMu =k]αr׀ywPB7x^oF\(^yy|uߴuAle>?m> wI I-ro:6=Q_Ql $''+>>ޚ]lZb5K43!ښUlT-roO]+KS5M+AR%9$%-w]Ei蝧Ն "@F05lW}IwY[JJq>nzCRf|@;ߩ /LkRڻ:2˳lR/]e*s$@K^.݋~Ֆh%Գg? m֥{;즎7L}^OּG$yM"NHPߑbbL3]_ϾM~CGhڪS^ѧqP3nBC_^{jssf.A~uM֥}S O{{7i5⻴䀻hKl5txwNsJeo)ϯךw*fMYG L}Oݹ}~ ib*s ;][gߤ|Ik|CKGzwd+wJ>oO*;74叵nzuQ6sc4stsprJu+q[\{ 8WF>y\=wWTK;_۷i_nFbڳmr%fg+=?V4S!_?x,WHńvdʔ)ouZ|`]ykg.iif[z2ݢ!}zk_Бg:Sw/S5l_p߭W. СO5Y_'uq^g&Sz;u/zjvU~Эܥ1lj~e}gߦo~7;ɑK*D2I4a2̽GdK$3{毘}Zzuz~ࡾ ǩIkX?դcn}ڨ&Gm6Qz_}ַK꛺F_dWթa ENO˔$e kҏsRUf *$(\qmZ*;4(O%6אoV٭75i+yJM:uAMjJ|}w BKn)>~2v)O RcyQcڣ]TP-yK$Wֿo4XCH;ЖtV]rgjG_hgoaj"F{U).IeBfk$$ūY,CJ2?xQoo=*\=S{뚔pLsZ뚲|:]Mit pq c?CC/OrnNu u^V:uaƢts4něj__Kڭ;3x{0E6K^vvCBl=Kԑ7([fN.QM]ZZA5fuq?O RcycƴG-oGYwuC'.6I>頢w[MǦg}B4|}9*֚ d[MK̴fIf&D[ ^C¬ٕpWsM97h軕Opڪo  ^ژmo]_1 O*Y$9,iuo'*J;țv͢Zrյ qjԺ{k6֗QuȮ6+O̽_U$ɝTHFkոqCeM?v";։lM[E@ k?zގ~[//Sk7ݣ)tSLҝ.  G4T\\\IgĕHo,[B|(Ye:be!!|S޴$Ogzյ sj͚9زDrf7DS.=r~-J5_#:+Haj"F{U).IeBvjܭ+!SvoQg6paPw^=vϥzC!i􌹺K$ts4něj__KڭlkqMeoZF C#Q @mPѸe+/ϛ.Q2 Iv6tOڻ$uo7q UШ/Xk6pcLK̴fIf&D[ ^C¬ٕpW5ToSiPTI΢%aI{>iWQ)tG޴%?EX7Y|28):uf[XՀ9 1;!..V߭YSx H^ICӧ[Cӧ+.y P0'%G>x]4t.:Y# 1bΝZh_N$5kT}zYY^@r8Zdnh=٫={jiر >f"p&j]b иc41:,h;vjɻKdzwk.eP 0N?u ^3fS`ut1Co,x]ZYO̶nPicN-^Da9ЫJ^'dYX;vV0 pZ,\Hn[c\^={ZKIKcJn[ -j8-_N413VRk5Gmz'o]k5w pZ4kTQ}-"ӢOޒ%.o%J^ @ulZ]%_o-.%qz-}=l6:k1!v4nX7A4M]3njW+)Ț˴Lծ].1Q7x\}ƍ[;vj%Z{2MS}zSlPiYO;kwdjlk4S) ;V?u͸Zh_NyE޽5jgkg̰fj)&~G'߀ljkvlj0 & pRRRR#XCeZ$INTEB{c5Z&oB}͍$qhJګ.ǧZ]?⃤4fV*WQF%yx5iTٞQ H6 ).`T\lc]2%SYꩢb@rJyW@ *A%;vO&*.^QPQ](K嶘857Dw|:G#@-~Gw ~Gw ~G]58mj9 wf: P-ClK]<M9rj6nilѥtQP: k#Dq]=å6 9ڞ$5/]"}_@ഊ|؞_={bO İڂN+bOnS+}j6zx8BJv}&WtQ^f)S% ߺ.nfe4,9=@x5 ?6tI0ؓ5 UPS_],Tu /lù.s+X 1tFxJI:76Hmyn=9G*$eWH;^.L  l~^΍-9ܦ>_,,;pbS`]K?qX$ P:4ң=Ԩ)nSZ7_onSJ~A_n}@/P\M:kD0 oc uN&|qL> @9bKs<^"AS+O )ץɖ>k\p߽$Ϩ'~\<[KC&@Fvc NSrCCu}IRS=, I7uTJhK~Hv#Kucpuv}qj0 P@n]2{|JÐ4SdqK6*w I.^]c#3b}CIEsA${NYH{N8䟙6'aJ9Y$a@ "Svϓ'~Iq_&!ŏy&8e% Ȫ\Oi )6s,ypF@@ "S M)8L=W++6sgƫEt3+xo"*Dp< @@@"S,G(|bcSSU'gT=n)K/džVN )KwMYQJґkDw )M pʶ9]4B3B-Wq S2BIRhD-5I]%>, P)*TRgޅQgi4ҮQgzI.}{3x@RnSޞ'I K )BAEgyrTg +3 b`]6RigH~tiK @ !Js_TX4"+>RN.Ss~ @؞ 9$!=3JzF(TBH( Oz9ڞ}\ Pe>_E;roL8" kvh' 6PYObSEŕ'4O0Å룺 , [\eJ#ӥS)9jjhi;-}}PnՁ|@K`7n5աWj[Z!@e8uwooA >61թo 6Pynk@ CMr[vk|0P\a,)yn*t3Djn-vg1v Cis8# T[jپ\}/ZA6C5fP‚qev܂;@#;$9Nm޲E"TpuV;EGG[vu89YZj`E *ʴifhLEfwvg)**Z\,))Ya_ ?@Y2 v 0mT`L999Tƍw)CLXBth\*6F@l)4jӿBHnՃo Z.UD6 P`PTNIEq@-eJUKEZvq#r1DMgҩ 8iڭzp[0P6P0-Lwu=CArˑ[jzݮNܝ=Iz^l#Ϫ)9{[cT^JTs"S%mO F>Siɢ\ IDAT{vpl#YywD(6*X Op;|D]`J{-fCŃ RR[!c<JqK\_hl8\yɳGFF [FC@p2oqf=ʞ_K˵ٝjy>ޒf{4M"4}4c^XQ饇?&jϗ'/U$)K}\y'Y K~zV<\o^6W z[m&Iqj1OnԔWBT==eޙ&4ڳLݼxzID-xra9Ú)a=wlEGΗV9~lzzVz3lk;wJBCCu^=o}m l&a:/.qtvث6oګ|iI7Sng*0M{~۩2i^[W$ JLQMR;Hmձ}Egdɶ[0 ÝWlUnޗ3v s*u~PuZ˦>WBeVT׮-^q,]}=~"Ny(#)#3c?z:D]`H{*eڢazZ/C4ܧrAjb(Ԫz)-1 u{c ?*Ǜmk@H"H1rkϡ<=@]RT(-nЍkliHB:L" )[o<8<&\w 9TвM9z+s-,XωX\.{T @eߤk{ӥbt۩giE~ 6m袶jbhF^%WkOSTD/]g#s޹<=.}]]*I}6o8F%ˀc^tוi8CrV;kޚz\;OQYS,IZ }!{Eo5HTmqzR.Uzz>[J={Rm$I}SvV225lp4xLRTLIھigPar_OPCjީb"ڭ_ީWIr騞"dإt+M]{wQ;G-;"ԫS{?o|VsWFo٢#Qt^X$?outֱ?+RFaMĪKut+&'fi f3tQׄN SlIU ۶ZMTF:vmf:qv='jW3Sƨ}%ĥ?~կS\6wa8'>uSU9Ѻ{:g dkGoTRjuhgfgFi^p}% mL-"W?cz;P|..\mk7w؂4C֥CGo㬪?0 ˰"X.RhfYbf-?24̲\ҴRT@sI\M!\ؗfǽssfz<{!s|?Ӏw Ł5Iscw 0sR_LǷhAmy9~8޶WU爷E px/7@&V8?|"1|qr?{ >DADDw^NOG/Dԭe꫎%O&T" jC0Y|&OX񫕇MBH+$7 @HW^V4VI(6"6j zE=X_P[[_mDKp(^Xm6<N(no#s ë7ⵦDhl C#H,@ë+9M >W`y2ٿ[ԂqMxdMoxX bkZ׹ 6hތx } /Aek+m Zm@mhj0(y<(荨8 %%WZҶ:yhJsNGojBssX޾oֱoYJվ@?'΂r"t)68/[Ru} 'ފ~В4ھKQ^pb'eM^ٳَG&!e!*Ś*ģQ8&6B6NM/moG߾U_EmµyHwz67<-ݱ(8j|3D#C :86/D/&""߀ Fo>mz_b֞_+F@@>h5mu[P%9Bm˱ 7 UbQg:f)Mij#AJ<2e?,_/سo "^-}yZA~+Ei( 8<-fd'?]%~Bv@aIb&!:&2>fxHA%\v^K YKڊN ߯i_f ڷ7Ǥ O-CcIݭ-97:H|S~ěڌǿ:nG)?z`=?878NMR>j׷~1O݊^vbC1f#1Z>1 kPHC޻ =<]ǜ;TR4Y#0c wo6| h>w>؅&u猷ch zGACQr%[jmhֈxE_47*{A͛bsVpj@ ?X ~Q ph더qTG]!}^Ūףm鋾Rt~nA98yy3\H 4nGېė!ufA sdkG_~)W>3K1yx&Zpa+y[+o`.e_f)"Ck}+6yEXu=\:~e;^!Vø^jf<N_wj6wE /Q~D< e SGхD^Kӝ.Ob8+p @p!(yk1眄ל>Wa\ژ)/6\u1N.-7ތf^ږzt0&>R.F+1zhlX[lGPƷٷh)T Ş{HFW/-kFb(;cꋊ0fxk"P^55՛mM^}?;#Wco5^FbA(|>oV;-v'>=#&N=h%a@߲Xkkr"15WT`>c7Yӯ'-xaM&abk>c&8o$ک籂raLq$zl7稣SmTKX(ɸ$eSKՕ[ zC]m~j^ A{إhki+mm g*wfr}<哏^bM @cC+|}+ V!E{b׊ S)omsW?hƬcCPSSc.zΆ?ۿ ;tF= gil8Sⅅi~kN奫p3111l0j|{8h wq лwE/̽EuU؈'xZ!9,=}ո-9nEbDmj%c򯫶/K1vzls"l,kU좃ƒ\ DDl vN` 6BiE_a ] aF6G޽yߊP{ .@$&DDDDDx@)bK5sƺ8냑~{T* qWR1} rR}g_?Ͷ"ARE=x N>@DDDDDDDT0|O-I|$}u0}a D;ʲ(6w$+CQDD-xh>K)""Oq uuu޷^pmQxmc+Ĉ D;h e3DDD Xv jju֡_e wEѴzuƦ&p'o]/콡p&'|-λ6Eݬ_e%vJK'L †ަ[ {o(7\ """"cQIPQ*--Ce H${XDxߊW{C=aF;".@d3QYn u  ADDDDDDD"""""""*8.@Qq DDDDDDDTp\ """"""+҂+WbӦM`ѣQZZj*ux<>|//^|YY&O3Q_Q>CDDDDD#u^|WX;6ծ  r+"~z.@Po@<oc1l0ի7@SS`;٧矇O;}?""""""yAwuw>5jַ#DEE/U 46nc?|3VZx-[jU&;DDDDT6QV?;xQׅ7aG4jo2&"""b--@++~iQwźL.v&)'rzT<OX7 dr31#r7(l`{bĈbJW̳FCCЀ3:0vX;s""""gܲhFjd_tD.>~uSb1\kˋ+'~ o/[f*;{{2|įŋ$~ uXTQ1hnoax 8|A2{6rrN=> xznYn'/n2#wݹQA/QL?^s5$f%|? Shhh 3RBEYYjcZ""""*?uC~lذgu7>=71Sc̳† nk]_}(IHϣC'mn)p H%]xm^ϝ C]w܁97l@[[Οlջn{)""""b[477 .Dyy9Isc|#sn_x}f4Ucg;0/m:f\77+pQ 4~sQO@dzqջ cgo̟0N5iCYYN5 >""""܌s.b~qm:WEמ.k!>r~xH=相z:~{ޥXzȕ,>d _{-~4g-ZD"g-C?iּt.mR?DA}uyԖ'e;M2YW/@ ũTUU~}pASDbb<M=^]?>ax_?І/]v9N>p TWh_mۂ] n>džStsSgcʔ)9s/DQ|įay)qF,q>N.=!)6\c#o\џȷ.ō_6Z8>}9[Gq7~x2sGcf,Vy^=z*|ᐃ]LH=|)fw?s8;³kz[r/.9m&?8[^ty^rs\qx6yr"7/19fT`C 駝o~uugpNÐ!CnDDDDT8sѧOo\_$֩n нLex2̻|e:r| IDAT{ɓ'.B)1o˿Q8spQc㣏`Y*7~7<rGi-x9d]}zKC?} =wo>=sp{9ƓO?\{>;"1}t8g>|61Η k{u`<+ȺEx`v|ēsqu{-:h;:ŁK&9|PNs]p=v剈( /~[bEJlι硲ʐ)-:@cFW-f.ůmFCS+ qu EHq:c?a3ٚ(> IPi9e%8z֗쉣?(ö?BasGvAY$fے2L>k {r F>Ov>j ubJ߶WAcǰuQSӿ[;3q9`#1Kqh܀cظn< I$%U(XuL Ea_GK9aŭuY MW]X󍒱ώqǝwOi =^yUZ}AjWZW^}{!\iq _ݎud""""*.u㎝:'͚!kpe"vKEo?wͭh?`DTVN< ̹ j;"򽥗jƌEwC<ɓ&.߽zU`FD^J?;Sנ& 8j՗Q6aCaɖ6 ^/ s򩢻Ϗyw9|GÚV|x:!Ƶb/`Oq2|Ԙn`Ymor~lm:L!nɯN.ιfظͥ<ڶmӟ;͛m]޽1x :-2qd ^_vN5 '}kӧOJu+s F}h4Eb7W~4zf4Uc>n'S;1i(KO%?^ ?}?c~zOK.:_?0a"(|M>I?<`;D3_:v:PNǝgĒuQ!e^+S+ ]oY3/AmK}_g[Cաʍ7↋o64dT|0,9CLzLH#1xq5ф^p0\fu8^^%_Y{_cmklc/n˘kuAǓ2q;bR~٢oR{=Bvs@&偿=_\}5֦뇩Sbi4RS{v:,^ sXp!jRj=w̔8Znjjjl8'݈a"""-\| S׿0f 6̦=36m wyΛyv/uf|q"T2saLZe;Dܛ,Dx,08] ac) 4̟jbAca/ GbXm۶'?)$%>ӟƷ&:57WTT`ѣ8ؙhkk ۛW^}@$.3/.ɏ4QQ"GGu/L%s5c |%l]F ً`oZyoʕc>i2eL,ӧӱh˸WskK^ǯƏ7{QIW|?6A]/;!sո\cܱn."չnyX]}²wSNm_|by?ޙ5ed;q?Ir*:T,{SMDDDD]œpz@;}mC'#trZغ0m~оW}Ç_g|_/h:wcgNÊ+M5u O-Mc㺕߾~):!ycẨqK^״%5kӾ 6H,>?b?e*o?E 6٧a͚5a[[(Eq~?$5cԄt\/8 {#l+}>kCh^PSS;o n gqmիW9sL6JjHnŰeA\ǥfcǀ;V0]}b ~2t TTnF2U7z([ЫWWC.X<SEDDDDgٖ^**Y{6!0 ;VŶ`~HOھ!(u_\>>0n8Uѵƍ;}|/ڵkUup-!14;2ag:W GTX }Y%X,qK;h!f7a{[3n+ѷfhgWWWw} 6E![QF,p!om)b*+36hE(Ǔˢd,.h.n؅E +(bu㚮KrھJ2Cmhկ_?) )DkD^"zj:lkŻL t<#cJuSl<(Q*++3Qx{4=Ԃ~S~0'#M5 *7H"qc&&JDDDDDDT(:>Vz*i]. a.o/fJ_/^CDDDDDDOzUٜKrŊB! ҽiϯ}/nsQ!n~9M>Ag V70zl/8~Anlv""""""By?9:;@j̕/B e. se 3&9ݪC{~S!8ǒ%H>QcNj~'"6 rMr^D@yQb4\Ǟ˞?&.uL_u\pŴt.۸ǑK ŁG(x H]V/: X!ژb-[oDDDDDD=k"7s?XAs^2'1#ٶ%[H\iu=q> y@#M2F2cuZQO&%=1~I\v~v T뗳uw+B.@xpO•Mjŏ qtN:nc~*B`Ő$u`R"9eO;ؾZ?扈Mϧ\]tLvRo7,Mv.2:}\1#ٗfb_/B.@dBޠLؕ8ԧ M@yZ⃎hǔn@C$Y'Ǖ15(!+f+ODDDDDTM|~}б(`7 :bK_gcpu%Fغ?MˤYbz%Ǻ'[KA'kGC Ǖ' t>*cٜ}"""""L\?a6灒c˂킃'!$f~Z/yӛt+tۺnvb 5zlVpŕVn&9+7^/"б"*%/Q"^|qWk.+FDDDDDTH2\1M|+5zQ.xx2!uAB\ 1 ;Χv"9긧ZA-['1~:EDܠxr1}9nR@ꂄS#c9e l-W#"""""*z^'\1Pƶ^r:n /:Wq$>01Om}ۘ/'Z'f%n/$[VdBdQ8^p@2\O.$q۷>+FDDDDDT \\ϒ9뱫\~}8 }p!1$Ǟ ,WtI\'Z{ᥕV~A/H Y'm<^ؐs.j#tL⺵}; W9plߎ2ѷs;;\y1͞;hu۾EW/@x|"/^@K< `t1G](!Hre$cjX2Dv/Bs='z@dOZ{|٤Ƅ_`7yj] ]#ZODZ =֭+X~2,}MHز,:/ٗe $՗czA6[A9?CDDDDD -}\m;WԛNZ cۅ ]nldR]!u+c1fkEK^\Ћzr"H}2A+dNjB ˦ >~c?a눈%s@J_o~t `k:'}"ٺ՗ZWůs & 2Ժ]1E#cY 'zq*k$㘲 :&Ҵ.7&"""""io.l7עĐ`:l\_P}Xb+ɴ>P "ɾ:yvBn<٠!uR?!y=PbĥƎ[Wߎʤ+e2ѵ?;}ھw;x }re4W DW/@b\htLX{* @7/ԯ}BjDDDDDDo"k6xP.Lȼ*7Y`@9W=^r۱._;ֶ6f9F `~Fo@"/cyJ'""""".&6oBO]s}ɿ݄,&kavlL霎mm%ڴ ( ιt1o<?I^`H$TlP}u$ 89fDDDDDD=19&&N"u,(o|6&1Z! 2!u#}/ڐX,5Aba31y 8 }߇ =9~PM:u%\Ώjt՛\9WtgcUw^ZZwո똮q"AE^h{Be5;_\&Զvn[P\.Xmu^cʼnv~fU뚬}/m̵D ӭuA<$&8TN:麠>:&խ 5ODDDDD]<4/c 561W+z9;1N$ۢ R'vu6'y=9]kcpmL5iv?A9+Z"""""|s A:WgkXe쪳yŅ+Gt1Wk8Ayk6.xǶcaA}ułZ/nLDDDDDisA+_.nvl[>Vw?$ބL ET\}$/cW?}ZlAs+ǺU+qyXپVظ_{t?vMX~eyro[6nltfO7:O]|v9y=.A\F=Q :^PN&殘U6缾Lru^:;N'z"""""bֻ&Hٜ=v9yy;vz\F=YMwLLZxPlm\ض⮘f"""""\d3 Ǖsܶ=ۼFƶM׭Gرk>|O@/WmET_͇?\Ƕ}8[:Qkk㚠۾x Ol+}fV~}? ;zIDAT2R'2kƒ_=霫pm-? """"")3~98Б5moٜ5MZԄ: Wnm_mg"}A.l]p+o[qZv쒯 1Q s05@:ׄs]5A|3ce"Zcw]ٜmgbv,1۷:;.LMh=fuɼl}6Ah:wf""""",IooIq>vl[aOB)6̱&p/bl;kw8#"""""Mr+'flrpپk'L]rMmZ p퓮.>䫆hGfrM+չw~]BN`;lй6I~~+fxQ8~hO7WL˻lܵ8Hڰu)D7㇭u-jWwE|\%"""""*\&Ņߤ߯5W+Ȭ6#frLjAcg:N'z }Q6Lb_ K7N'Lj3Uհ ['l}c-h!(r6f/NDDDDDDT۸h`se:N'l}غuդ7ZXL.WLK~DDDDDD&Iq\yW̲55tN3֕LϕzK7v5 [hgvNL.&pǂ>+]=|}l̎w̲5v c<[>QO \qcW1>g-f] Ӊs>xXBhgn.w\1W]>礻&7z_&qWOPmPN [GDDDDDDNr2~;LG훯xl!"""""d2ΤV퓯x>9 y6hA@pO'AŁ\>yQ l_CiA版8ʅ1//ee_-qp5"Z""""""ʟL&ajդˇqr7/me_+梫CDDDDDTh]5i~z]u""""""Yj1S;ڤOwFwMy#Ok""""""ڙ_Sv ~퐋 .Qi\8N׈ة:wDDDDDD;.0䀓MDDDDDT\@DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD; rAgIENDB`kraft-1.1/manual/images/de/wages.png000066400000000000000000002037521450127457600174340ustar00rootroot00000000000000PNG  IHDRT pHYs+ IDATx^y|e?3gݴRJE(  KEQLJ)-mҜdwgwlfjJ~Bvgg7eg?<3#mzPz`0"""""""|0 r""""""!PNDDDDDD4D ̙3O툈hp5Bn}m'Z8}=zmGDDDDDDۧӧBzVi-744l+QvB< J8ͽ9s7 xܷOX7da}J kn#uuu zN$jkkDDDDDD[t) m75Js` 6ʏ?xw{{9KJJBҥKF7?Sd F_}U &JXխ|ˉhCp8ܭ>zj!"k|POWbҤIHR²,l7h+ F T8VFn0Ns[(B!Ӳ,h4jd2ש/l-'"""""mi9H$$P(,˲|0FGZm{׭[gb1px*2e\F{'"""""!He7a4M٩LTn@/++?~=X##%tm{>BjA3ehTXeRa>WH_fFa٭OR} d"PPHR)Y\\lg2;J`%##%t &i&eYif:6ᰐRD"]ᛈhow2at:-MTmۑHmу@Ġ{m_o@2hiN`0(l6PJpw ݧ t@W BdBVJe HO0Ȉp#9a NC`0dB`0NômPJ 7ae#"""""P(m;ǶmK4m22t:t:mA }aȽ#a- !"BaaNJi!L)aPJ )t@ K_&"""""Id2ʅJJ)R)e!RʔR*JB2s@83]ޫSmP2Bgi8S#DcV_ח6B!D"QL+s ˲H$S09^0D@nu=) 0Rd_) )@gg'V~ O0t*6}  """""w-PxP9_,l7)B}}!\aH) " "N 4aYHR"ylP> @%e ˲D,t:m)d2B)ex(_RFFX:0 (( UŰ~sUooJJ"""""Pbo}2 n|zT 77fTsPJ 9?nw$܏{uo wGSw\R! )a֮] Q¨2(ny# 4s$cvсSKDD4$)J4Vhε#"z mo .[]O/ù-@ !Maן+ tR)47fTu^Ⱦͤm[lXw|+4`x7lFYY)4rW,V⢢>GDD%%mfwkZZ JYH&(++C(@[[i;(  AK[hؼD @gg™ֆXw􀈈F6=NjniFEy9씲,-(r=d--465[8Γ+T*/@eE9[LOYܲ}- y[2grZDCyCC'[%D(BGGdD45R);}s8SJaڵh،ckN;-%Z[x"lnhBӦMCUU5}w>>dv}bEy}4fn #""(Rhjnab%mmqf"!(% TaS}*++`εTShQrˈ=v7xeeBy!ղ,4P0ü}cRHYQYQyEy9pFvqw9cP[ UrBwWƶ<1DQ)W[sr7O0A$ ЀT*%WZUUraF~XLd2 Y7M)sp@u@eehnn;?VRh#DD4RhϞ. kF#} Piɤ!eRJHۓs*sJ ~arxCn(DYii. 9eYhimEEy9O_m#D*@pvݩ} c= /׷Yꯁ-qG4ihhh0ZZZD,s)yۛe2XL V!:::DQQiaf*2i m` ! =4+؀)!E6'C PR79FB@^MXq1/FDD[s_Iq 676]+cqYN/PvƆiF=-}W?wDD7rC М1 䡠3BrCft:L@(z!"pnļs(M@&m)uso.=\)PJ ,1P!4iXn 㢣CxG uC{k3t_B#TB,2 gzuRťt" !+@ @AfR{ಲGPMDDD%^M4Csk LD0/8틔rb1f wbgI/=(9gDD#7l74ˀJK@<;*?+/ ~C!T;登uP {8N(W >o8]͝w7w;.lP.b1ՌFȞ Vfsq^-Ƕ6HDض-iF86-28PJR7dLNQ^Vbmii)ZZ0JkMDD48E҂ʊzN ض-a&rfR)FJ9a\eC~">_Rhx)B(/m/oB/ԧ{٭W{worsH)y$A{g©W *Jy1-eYP{P7B 0 ۶͢"ömaYRp8w;t:-s^uF:6L4#۶Ca&P$vYVR!?mw=,H9_`zҊ@}0@UeE'""\ow_SJҊ2H Dv;MM0 ifՏ̆sw'FG"@II Hxh۠b N. 2/)iBaAX4,w37onl? ޗ} y[Qhܲ@8a&I3 8Gd2)"yGDUz6p80 `FPBl R7nRܸ 6`eU%IJ:eu4R"s#N#"Si, J{#0">m3P]or,o;"":G.oP^rCнm1 eؼy3t=O:ƻnXS\<sz!Hӡp8Rm`P(D&Jan} nmۦRPΔ" "I)?ynq0mm$VY`8# C i5;4ry %l2]sݰnu2R @~pF̓*++@(U0 !`*3CB!)e0m#N@ vo i2{^t2 }޼uhi`ɻ"{ @sI"|Ǩ1VqD ~a[a܏myY[zBtp:ۧN0BFKKkn*{` QQ\pNm7z 9suuu !@uP)RL̍r ކnsdF!mۦBm *BBR({C:F<y4~"T7m@Ii-ODDDDD4R%T+˽ec ^:cEEE0 #:w=7D+ 0 T dv\@4F ss yQ__opna`0 ٶ9s/\ع|2fkI/ne}y">ODDDDDD=Rٟ-0 :1EεR y]$F$\K{P( D}}D 0EEEd2TJ /X7|wCDDDDDD4`錍4H$!Z)݅y_#x\֢ATUU ˲LeYPcc`!""""""&-:::ŠT׹@W@ۣsq֤xބhDB܂~{߰0nqWuseYښ&!:{@jǰiLmQb%B &OEE8ǹJuryㅮrv6^$ ޞ5m )D"R i C4OlDf$+>%V \Qkշw>'sTnct""7-JJ0烈oiwcnjƷ:~|յ8K}i/DQi7׋O ]ۡ G ssB\x g{| fDDޗ:I̻|L$ЙHÏ>Ƽ{@JϷ0v^g3kan断tx.^iXx)6Xv3{x~)e^0w{^멭`r/s, uLTchWTKJ889*/{ ?""(8H8+.9o%e0  0 l\::tvvj{j}^TPϸcp̑?^5{-Om .\x۝s1k3p\>ߗr5 IDAToq>۾Qqﺃ_=< 3}]uM]:rNԸ c*RJJ@)TGYX!Ȟ'mYhnl@G`>͕[o-o 3>V0M\zX#?j3f2nve 80a}̷PUY?EP]Y~ڛ*+q~ )%~z m]pƌFcS3Xp ?Gz5/|]cPJЃ)vpQx?̻w0-C0IÁ탢h׬?P =_9h}?vejԌ^sLI4o؞uP ~ &kni8Sd2}:gouxwq?S~gԌ\#LqNމ^@ YO[{2 5M_ڗ1eθGiB.z=i3qmw9\3ks~]?pgL5J56/ҽ6(lk*Kz uuubΜ9k&oBuiBMPVfC*DG;65D"vqJbexrGV`:wσ A4'yx9"(E省\;3³O<WTB8¼{ǧ7` ;kkoߞt&?_z:O>\:8pŏo-^{>s.yhmk_rZ %ࣸP^V^KAAK{ 3Y^ey^9v_s=Q3RI((N& P^V[Yy g8r~1Ga]'_L&+|N8(!\7w~y5x/]X w_"ipgxz>YC̽n\rY{y70?\/̯v(\ |9_B9:ȷ_+s4Pn۶0MVfJ)!@ @mT 0vvffXM*[ 3@8[!<&ݏ ]u￀K~~rAg} O<@ND4aXl9翽EK?]Y5k҂QUܘ e} x͘tzZsc^͍Xb%Ə!W/¯}?Eѭ?x}q್urvzzSs+<}{_+<[;{8;Gǟu[v< Ld2 )U(,[! E/\Cܯk={DD#Mi,k ~gW_ǖK;Ə; gN% D~ =R (mP/-U[[իW 5jϫp 8))I +@@+ {+v쵻ߓt&Ay?1 oYv58Cd>|(R#Po}EUev7}{, :3|mjn'4\M3~P;}aطzTV;`sK>nofW֓'yO<'M͸lu3~o+^;Vc¤'@"Mۜڵe"j=f`xUhI]^@d ){͝ԌqcwЋs_ <}]0׃W/o-[eh@Al'3W#$u*o!3wws>/<KWDD4o M--{ݸҋÏjZ|NOu2>gO{^wqs~K8թY҂W?^nt=RݭRPhm2V=-_,-]bϗz?W_ H&1{p?~ޜw֩؈+~~t+8}rmHT\R%KqƵWpu7i\7w^S.Y΃N5-][(^ ~s-]ܠ n7}4[׻z[IUUm87P `l3vYOOnwW ݁N>μKDD/ex?'\~5:::\JىO>]c&*ˀlwoභ4$&M 9k{wW9&`ŽMHRݕ :w_ClI5;GbOҊƏǟ]w[ (+-Ek[Rx߯P߰X *+u7<ڊn鏱l*B}twCʲp8rm}5njک0  p_ _<@8+^v!+}÷oW]vQ_k~?x}15rz 6}i?[AKBG{qT\|vuq].Ù3 ϿiSvy?< 7zS q~_}w&,[,oi)}qig7Z[p/n'g|`k~C2riszl#?SﻘwBXǸ|g^_O[ஹף \z8x_(xO'4~Գzvc pե9w7oЫrQmw$;-.ͭs{yGrn j(|6a(.$+NN6ݨ5W"""""'Onܵdr\98P;m7:e+p=!w´Nϕz.ְB^_֝Іā)iM+r&5!"""""anpտ3jq`i؄%V7Kf?nC rWo ={PJUf2 P,,ydH-@DDDDDD4(`b߼a[OC/zy C:}ݖK6Rz1^z/! DDDDDDD[Jσ^+WUU m[DQ!hSmtܯ\Ưl0+ zPCw^ʽfʉh*42-r""""""q2 )˟!%ѶBJ+?ĺuǏnSvaP(X^ChX!>ܲxreDDDDD482J/[ˠ )Rba!Z~^DDDDDD[ߨyoz)'TJ/B2ԋ vg#[-8IaDѠ#""""|} ~!i&,XP/pz1m'T@zbAQo2hMP !cwDI,3Fb }q Ë_} z}t CZp!λB_=lsb$^^*,0w)=M5f%>. >h-”ٿ]5ކxU򯢦{2'""""r~S2}[_Nu{~">6ca~ƚ>Pxh"HvWa|{̚G.9rb#DYU Uy4-p5g(&5 v^g ?&;$+٧ Ap}CxqM{w *#""""z~AܯSPc(߆0SDwg V PJpڕ8Xo'Vm JJc<]!ѼI0P\9ea*$DJcEɶYJQ>G?h*4=ø|`N}X<;<װ`uR@tG~a8gkzDzӻx'? R r4@?܎^x\8pN/방SBA P2S9'rkx+cus R ` v 㻇LDQh*āi]}i1o̩7֚?܄֦TRV'x?Nj?8%>2Kq-.=(Hk|x[q{C;֧[i K0oq!o܁~uq)WP8~"^ ^:*~0vDDDDۼ ů#…qF; sqw첋֊G5txi}&?kTz^"\YnxFqB⇮>gZ@?Q5x_/!Okøߣ*C((צXq٘""""|^a/_ #=G=0>bx{1s̼6In n d{bp=ŪNfyhyFrt(@ٟ/~fS0N8spWga:݄-h y1><;]ó?@.B;k'ESظ̻v^^RI,{7۷oQ[!LDDDDC`lqrXh^Eۓ7>3[ p-?aGeI1JGg__]~(*M/k t1n|i(D(=߼J;.Ѳr%6w0f1}˘>%E1L*ιT~x$>\vv{ xfagBμ b̞Wqנ:ǙDDDDmO`8R>q/"_ .ă=[iv*]7gӱ ݺ _>t6~+x|T= 'Mh0(~2 @vƌ1#ݭh= (?ߘȨ3v0'6֖O~fN!_ ϺVZ^f`]V}1 6a `~ -浟8qVU஘15 C9 @ \sݖFQ=}B w'OcGF͕msllBR;m3<f_}Ŧ.TM{k QʲB8ATTCe(!֟O"ՉVS3id2""""" ({q|;ގSN?wf4WB#{1`^ c 3p}Kh4A܋|;`(,!(v#%_Mbxn4ZU̯PE(+ B-Ga/^4#"""^ 4D``B9%`ڈ +kK^]:'c▎ &N1wt=Ӊ2*ގS8|;`N>\GVƚg?ݫQQ1l(iԼce"EX9m=C> @W0{jTּ/s}lq{8n^xvP8pݥ X'pއaʯ`7#xoc oCA"]+0{a{R Bi>^+n2.z.L,6Gh -sT Nez w K/1Pb?9[nDWWW 18[ %c|?߄כ$_m  i5 8;pїxnQ4 skѸWz2{kEDDDDH9vHOo>'^64uBc^cBJq/ -,X[Ȉ k0~tߗqamuKb_]p^?bƊ~ ^;]\rw;^5[/%/`%z9뷼^7ݘ&Nuq3""""ao8J%"""""".0 r""""""!PNDDDDDD4DʉC9-шhDiiiA2a00 籾},i0a8cՆa  Br""""""QQ\\ 4sa}l=ur7M44lFM(N_'""""""PRR+m[C9a('""""""" DDDDDDDCz&x! EDDDDDD41 .BiNDDDDDD4D8R>?0[: Ƒr""""""!‘西]/b7mҋh+c(λBF N_'""""""")!N)8ԋ4%38 ^CDDDDF,אb֬z1Q3)!'l/-_iSDDDDCwSߪ*oDې r""""R{u i+ w"""""".5 IDAT!PNDDDDDD4DʉC9a('""""""" DDDDDDDCh0 r"oMIyñ8:z H@/ mDpѐ0Pv^Jp1̋֬!ޮFn5phiϿmT޸к\F~"S 絧0v[:`ޙ&{SPV+B'4p4oj[EذbFWjOr.),B"˗4 Z65tknq-<2I( 9`Fr \KpH\tm7\~!ѶnZe[w>mn0'df&IkW1ƓsdqB/Φ-H{$]^MWTIZŢbʱ7߰c:0ڋv}ۅ !B'P.BZjس"]z¤]ciTpH ކᄿƐP' &Ϧ6O봝׀My|NXT 9ȹnxgP_.#t?f6B!xT'Bm1jdSDsux}8wo0w<M_k5jL0$ƙ>P%@cC%O2rs!BDFʅxchp7E˙l:|/1fظi+T&?}6="[uˑ SGL+s@O˻?aV[Qzl0y"_cL`Q6_PM~Լ.4M;5s{$ål3> g@ \>;DgWEFɅB! KY7kZLR-i=UY҂1jߦoYIGYEYh wf~Ӫ} F/ 2m,9v5Ӷ[JaY:!BHBB!BJdd$ t?x"  #\!B!kE-=,/^I*R5&i7C9 &娄B!zr?FJUP ?Cri Kr*}HMo݁Z!B!ċzr̨:dwV8@r䖺?aZzѡ]_3ku^B!uBy&EjfIԻ5_mOʬ>̚qti\ Oo?jY%t[lHa۸~^_z#3&Ț-yF$To^{{ؗc4GutCq\0.k@^_F/C_5jOÞ{GH]y]Q@~אHi;1E j7~1ԯKMvNMx"=ͭcqnr1(-DQw>s'u$I1<-}׆Α` 7>mPϚ=(RyDoGdM}k?0Ɇ{:?|وcr-v*`hF] Fn !B!^1yr7އ~ oZ gXVZ 0h 3yOnj]zf3 p"18z/[áݓƫB~S?Я|۠sh}gYV{rJxb4E?]OП!~=Yϊet+W 4߯l|!]?[I> cʃ|vуOWHO4N0SѸp?u*h8<慷gTȬ0*X-Ly$]Hn3X{zHw>=y͆2k6'j>Ye*IL&σkߡf a\R(u!B!kEQ=[mi[4v/>Ʀ->(q1`m)ie9Pp hϻ%Q[*mk_{ XEܼ$h}@26h4vTiۂrVXY%(4(7~SK|:3(_wsS<Ϳq"(jIZ VI's,)MagL!x7{$Qg'*inAT7:bQܓ%0C?oND?ZKaM(he'šy/-a(T+-Kn=Epq:v^Jny B!o|ɉNN8;;??.θ8;ꊫ nQ QiwGAC|ܽs^j?!g;>hhEՠ SgSD*Xg\g+h5`c.?i5fh zT@[ tY0ҁ<em;IŽŋXs-BS*g:"ЉR)\犳EZo5hqn*hxnS_Gkˠ!}""MK"sq/s!BR\-ښ( 'CMFULcaPqK̝;qrɟ1U@ޖ'/^eDA2x|$ *+ipvtoYQGzGqKϰO_4ClSLkGY4l0c۰JX%Cu.OŴkw6sW9G(!(ոhbSt+}yKaFY;4)00ӧ(Fܖ|Zb6:sa^N0ox;ȼxb%!B!^Vc.ZŨ9QcχVHٲ5b {'g5qVB猋'>ap: ;rSDݸUݭmՀ}R5>N_ytpѨp܈A;\ARG{.Í$PU=,RҎZ0D>i敩WKVs )9b-ףCT*f=mP7/".eT}h%ϧ]p D$@cK%qVIzB!B$pjz3*nūPtv @ >ɤO23< }+Y`:ݲ|1w:?L#yio7W\ImYk`|̺2?gZؚv7eI~o<+wB?Pe> WZ5U {~gt Ɵ`ꍞ{ʉ4_| jOWƷsKv/w 76rqLXIdi8?.mgۮDg_tB!B׋bܸqٳgp%&&F)Qj yrrh46کiM{N@Ze!^9aaafh!۶lԴa/Qi؛MB!BTu7c;:sӵKglllh4hյlW[O@F*XUEaǎHxNl0RIIIz˗U;;;EP 0~xa5OM_B䂔?֬>㏦] B!xjʅȫ(٬3d\No=Srnd\o~ WמsMѦQ-<|-#L$snԨڝwC9VlO﷩ߔSws3>j$'Em/z&|DTR ^{!낎B!o BU~u8e%5~d,CGC4QVlǎ͉n8_[™Ōe$?9aY'N_^q=*11d#k汋a![6'pjG ݕnsA{ yD!B7r!, .޾x**ߙo]de?-O,ehS,>vߖ o &u.S#S+n_Zi=yGImI@5zD~ս%&8xѵ(CA]|<֝e-`N܁I9Ǯف v͇[wpY]k>-Pݨݻ#oaOx6<֦2地ŭޥ]D! #\feVB!$ ieΐ;v¸ _8DK +{sX;6,NkeNoܑqb]~ÚP +HA>|.(߷CAmXKEK~߶4u9c3 Z;c*bmN2?IMuh;~SPo*S.4cRX>ψG<:ucي !؄xYUSam@\|֘-Օy! qh͌[yV~<.%Z !B)B<%U(⨝k((}$eA1p1.l a {*6 jj6j#Al ":|ޑ$-bcQ܊F0?_u(=#7jfp:O +kT&$VgU )EuXe=׫='!V mb IqB!ʅljR4Ԯќ+0W4hprq#k";wuszpVlk&ij|?z;aY='yAg\yj1q  ϑ?0[)rIdWKmtź5CX#S1~6Mc9Ѐ>K@Zv`=~˖k a{TnHl~Xӵ5&LfpSscMB!"yog4ԩ9J-@-4O3qmʤٝQV_juKx蘹WgH3Z0eN'kϋ \92Dg]HjP/ $Tfv+ggg9Nqi_^AVl 3f5!;Wߛq0_-`5wO+&1yR[ e[łeF8j^tgb% !'ׅT近M˕Oe)*Wg+;dRo5[bض7ض܁I˲۟`ZĦzOiZΞUSk{4AdmYV!+i%bGNSYɴ1> B!ol4Bi9{AMp B!/ !ӲB!x$ |ϴ$}-򛖄B!kBBy4!B!^rB!BK$ !B!D"UU"99ٴbnn6 !B!xsQBBQQQW%VVVe!B!@"UUMKX?F͙y:Ŵ{>F*4v BMo7m/sMѦQ-<|-~aCo,Dmoo<ZwA<w#Sm7LX<Y~9a,w9pA|\ :IB!02R@Z֤c0s.\ix(֔,Mӷu-oxFVB!ěNBL?1 ^JbbixEѲa@w<6n-Ŗo1v8xk4u@ox7#<{Q(p<Ʃvɦa^h÷3f(ݖ~qe{86Il'k~7K?9ikɤX O[vMK_JxaJ+Y ƕk/U,ct]q,I|Wp5kׇ.wvGexk7 qYq,B!ěIBy.RU`xb8~Qzc_JJTŝ*Ɲ1Gi3Z@-פ9 0Tn IDAT q/Ncj/Rٍs߷CAmXKEK~߶4u9c3^Mѝ1ApF's j:q A_@b/i͟DAu 6qՠEk@#ֺﱢBg#6!x3tVFW@):-L[+Bњy.]JȅB!KJJ"11D<3>y#666cllKprMy..gW{ҧ+1b5/Xˠ!mׂhs~Kbsc"DA69ДhKtcW[<. &R:C DGx~K$iV6ez,0yQ&{n'Gvo*w,N)c4 qF~ 俿be@\ iՄ4VꬰJ!!>H}@\^{OC0+߃&Bdmm ZFF\բ(J6F1=oGEGڋ%<_םۧOx1{{{)m{…qIK*ggg13K} SI %6ED̪w(S<j0^BmS}0~6Mc9Ѐ>K@Zv`=~˖k a{TnHG^kfÄl8N|J"w.rzL'B!Dc#%{[bER9;88nMG̟üb b[Hq+owL3y8X9Vs Q épKKU[3~PuP(7}Fk[Ƕ`ʜ8~9#H@kV|:{/!<>ahhɊ:nѢro'uҮ_^Aviq QTLKs|aL{,Zk ӻMd\B5V}ɓR(LTp.3̦2k`sƄc\f_NV`B!MBy.2 Ħ}xTJSRbl_ti\\\Kǐq׀{_{R]w̩9;72ae`F+}؝[d8a: 7YTe*,|Ӳx.ldΚ4 [PKz] %k YI,R)vT4LC/c BfP˲ a==p"u잯yfƶN˸<]JJJ'ȋ9{A!g;-B!^ yh,,,pqq!<<HM@Gբh3773Gɺ[R鍋y9>7cZB!/\f<=VWώ+]{RRIII-[{[)BRrs;i B!QsiRߴ=))9Qq33:>!B!?sYva״v̙,ۦ*Vȍ76}N)ϮY~jB!BGBy.3nyvv+ˮ_vtٵi4ͳpEQ$ !B! $</_޴B UM=qP. !B!x~$®H/bʖ-VٳM]iv:=:C!BI(eOz+T`ZEQm{+J-;ei {2fǷt.7ֺʔr@J5 n7%_toaSca|yK7~ĝc,J+U[~OS P#9$ ˏp=^G!!~ΏyOr蛩Z{ѹUnqLjS ӾB!o)&^UU1 ׍9;;g6S~|5ȠM0 OW54DŽaӪxŨqW8yɁi-1~À>̭5̈=þ#\!r>1',ovwlʟ?%Yѣq1du(~!B avK\yk%pjG =XQSNsUSsӮB!oGt/TW!^oVVh2c6#`v~[25w3 F`Q6\N]Ryd[<@Gk&؊:~޼]'OV!6œn4wt 8.l@ƵI/q#9Q<m>ݟ&e0Ccϵ(XX:Ss2/s N9Ǯف v͇[wpY]k>-Pݨݻ#oaOx6'blm A!#h^ +K[]ʚ !B$W='ʃәw bH-ܨoï7\_|},EGVmǩr9®\95I` Ϳۮy45NJ̡iF?-|^w_ΥlfڋgF7S `^b:W Sxftו,͋\J ʵD*6Mq,I|Wp57QAƖi,->fEvU!Bdz.{{9,Xפ%i{]iOք2g*_ᆿY7B.:ӱ=Z;8-ݝj@Iy1竽3,w7Dl>mؠmApVJsM5ևFI|^2=>?5>xtXȠBg#6!x3tVFB֖ ܎3C[+BP/Dnjé!uB!?rYv`0`02ڲzss홌}6Ür-Xɞh"^]1C1dP!%8iC~Iς$ 6͉K&,<LM?Z%G6gd8M2{SvoZ=UР`Z,A -bGNSYɴ1> B!o6 ,kZnʹreuKKGBez,B*{B!EPLӷ29qrrhѢYjMI3z#>e!BBI(Ez5=I B!P^B!B$2 +1*B!Besӆ_մDeʔ… &-%p˨)S摕ٍiS!B!#<=MME}\ww,!>>ܹs'tuSeʔ)K8,_۞:,)OKѳ .nКe? (>罿J9E Y$W$m1:c8)@9VOς=DR'L>mS_5KBujsf*Dtn{ڔ´B!$?Kd?boo>O]_UU)UJ2m4K(Cben{*ú#9AUSYg罿<MUmF,,x*?*lg?cNXJٔ? +JGqkR}CVkZ◩2, f\91`5FND_;UM!2!B$碧 /^4-۷MZez2>Q ^W*vPɶ,!"% @7|E{փ]3Ky\Ʉ)+9r=j~[ഥ]g< 79s_m;KDk9FNUT~uIFX7,|3OsCm2s+$jB)R6uX=u,ol(^t땱mW:"sNvxm7ӭb0s,eu$߿̕x, X|\0K BZ3uoxS7/@P䳣x&_`A Fy'H۩h\g88j;_/goE~I~)[f?$j}m]|++ԕ,LPS0n_KxbcIJʅz0 |k~45@[NK B!_ڏD԰8az*:+t8bT09'. ѯEe㳾G2/ Bt<[G!" (=.֎;e;;׋<+sjdw@N9n3<`;CԤX:#|q7o; C6 C"vkMp+>ˠ!eXĕϦ˂-(k[+X5/iТM 4Q .~(H2Ģe>v2{dWFbqsk2jB +l7bS_+RHOeuXe='!V mb I͍ԅB!Xsӄ'-Dr<.9];LK@PźzS6˾YnK=)f^N0oxϥ~P/۔ӚQq ̀6`s~FˢEy1ڝ<1{?ZV)$+A)^M%rۣ$EM Ρ+%Yz =je.=(;E&mm]q#B!ȓd"=nܘXXXku{Həw:Wʖv<%d5_ "[ /Lɽ wǍSI!%9Ppp'?HUy? "(C4oKSt|#8{3vޡLXhѴq>.s #Ota 4z=!LrkہH-[%&q9S!u]zΚ &t8)D߹1&D!Byd<Nu9Nap-?bSi)؂nDN"Q,tϨ${X>vX%:Bў{G7U,-uVmA1CC޴îgl:zg^qr6r%Ά!<>ahhɊ:n<+k*C_9WQ0_-j26˱@wȸDkp.'P6,\fMe ¹,͂g3ݓ&H!Bi_As)BGaZ4;hԍ?3(k3 Fh*X6*vg4uÍjVmbA5aVOwnQ6{2gMOr& YI=U ,N}Qi*;6<>_ǴA!͖혆B7M2gO]; A!⥑WăHLL ,, NV}iIg3z#>e!BBI(E:u(rUB!EPj$&&Rד'$$(B!B(stkkk (;wz:4T!B!7 ٙ%KQsqqɲgU/ϵݴ,B!I(ErʙB!B!dN%T-gEo@4ݹ.B!ěKByTlۛ~h?G>rsٞ:oSͿ)=fEAEUϑCgˡCC*lЉȝB!īE,x(֔,Mh\7bxvŮTuJ>Xn9މq~6N'y| Nc˅dӆMUmF,űcwAsW&̃4#=ʱ{u&fCƜ,}['S ZKǑ Ű-e85#Gy9v [j07*BP.D^)Ѱ7rafYi #Ѵя5c>>5}nԝl)0{`x-ﺴ}ZPπ6| U7e4jRçmJƐi6LKZxФח츑]M%'[^CfS|k</eMHgF}I񯩿gw,z4;1_'fޒ1rg ` m_|LjH{l_єT/}t(h+Oܺq^} @T΄{4cx@; Zjխ;O䮃صxt(nݑș IDATrǷ'©1}Z RпdV5t daKZMo}j4R]*=_-YoVH ߧhuG#lޛn+w嫺//)4gQ4{ğLZ-^*Q*`SU CoIGZ޼TvR=ݺݏ}T;wIiwSf?*EE?3pf/kaGaKMr7X4|ϫoi+i\̖=x$CZVm(·Q;-e!{@JԷq#^cGw߼r7hCW3-jfڰn C:*۲h:stkcm0[OmӠ.M(;KOUytQٖ w3dتו>jK/kh[{V\pzOOJe/֙$X+bm*٬e7JxY%*\y}d0;NӛOӛSI]whoCƨ]1_w ;2qXׇi)_$/96'$V~ 8-Wen6"-5^iy8%i>j[k7ʨy \_~)UnUj5ZI[jҶr~Y5FI;"sn5W7F7k՗o+N9EqX596PNB]Y/~Z&|F*Qq))QHMq l]`JT\F]O]x;Zs.9fHT=pHrߦVEϱ&cIG'nP|G%cIf 6)`^MS۹jH^:{-WoS=;s :JƯy_36~v]SFi){FI%;%o䍖`yG+ʕ:^߆+ A8=jHmqCӉs?WٸjTر}suaj8qWuoP.˒$~X+wSjܵ^^TQN$nR9i;]ӥMV^޽NfdϘTպoA:nպEC;^MWN!i~.12ekݒj6!w!תB)]>^EU:OgkoUŪج¯֝n½}co,fcyɫ5ojbm{J[>U~_~bIXj1h\Tr39T]¿AҦ #)ԳoԮ{N쏾QIFekЋ/QY#ݤ+TL>*nC=dvq{N{L--)/Ї0 LHq|lcrݍzBm(jѲ OU4T{v17W^>B N=z9MkLD~3^ݩ%~_ϙzԷO2NWHIoNctSWOO#huiW; 7c}y`_? uF6VOVS ij?k j=\7sgO}ЁSᡷqj+tI߾g߾v3*~rkKuԠw>{䥚sH蒧uK4NMڿs}XtXI)Ѻnq?xXuU2ǟGO4+7_\s5֢EBkÆ V׮]B;33ٴinFƍ33%e۶c5OڔjtЁf uiO7IF1<3k۫WyzDjn6 j_mh$6^o8O` FSR5zrrr8lۖm۱cqdYVv۶+}vLt:v;^dYf̘1F:uh٥VEʢZr,YbrssMVL=$M81.a]~ 5-+עKW;ް@RUn@"h,5$EP@HB9IB(%eKgֳF}G4p4k\If|M\E w&L_aWYsUxzm~'/JszܬNfH˖o]w}q$)nCvj%zjwE+ѵG֕.*-ϫiK eQރջMgVM\Æӑ\R#=0hԿ =V}Zo$i^=w?r uŀ#u~lf~_x]uE=qcлݥS_{K&# Ԡgye$EH ;P9Q>/> ?E??z-<[C׀֞'=-MkC64WoOgbt0bn<Yo|KS.Oŗv?O,.Q>{p&~K7N߾_|߿PǗusųwUSgkGi=4rY얻г֔s񛷨Ϸ7xu!|f>qz4:HL[|[rjN:\M嵢^>!O2N?]_55,"0C~{tV?Hi Y3"<8:mvz6sdew1Oォ3V9< TnguZ7O/OXK7jywuijIԯO'8ݬ앥5ī1ۮ=ԕ+&@U)-NsGvV#L^:Xw'\zC[czm(FP߭,RI\[ϿZnw-7U񒯵 NCudyzYZٕզ++$eC|-[PTůN'e{EҨ9TFFoǯU]|2wrTQ^.RBA,Ƿ'kkWQgrd-5QTkէOߤX5F-v־]V#qݤ=nҴ'ߦIwC.պrK9 [VSQOqG<6j~:eisյަ]Evߠ;wieŘ5sugiaQVVZ3FK-3? ֌&je~sz9C;>Hwu8Nw_V^u&hTLDZ3kxQkEYֆ ]Zvffi&u݌ƍggJʶm;kɟ2) 4@)((P5?}MG 7̚=Gn!-{Zz5xM=8;\kN;qٶ-۶cǎȲJ}mW8&XKc%Ieiƌc$s](Kڜ]Z\\\nE^^^,ڪU+wɒ%&77״jHĉe@HB9IB( I$ $!$rP@HB9IB( I$ $!$rP@HHu3Mꊃ;)Jy0yef@#71wK0tB(o ~^_?[I04š5FK٬׿,_ԔS 7~Byr]K@HB9IB( I- MխvmpWRpnl6z r#3Z<;U7?8S_*8]w9: ߒdTxӚl2؋Zɮ&M:e?-_/uox :{?ist;#5,y4o|Y߿n|\~W#jOgcQ[vzS=򡊆?=QIꉬwLP-[*''Gxp8ۃP|v/?ڴnzǺC6zhOmܕ򿼤SӬ[9GOЄ*x׮94\Zo^~j꭛zjmz躗׼Yk'uۿ(*-?'돏jև֚~5zeݮs:o?(ң7=/| $iFw7u4,w-wաgݭ)37oQo]o79藙uu4t=o=t3ޛw$MyyyN~A|eoڨh5ocuΰʶ̶鼓_TnKkgߤYOakdw9LㆴW5oiL=R]Yrvנjh{9:)rԢX o5_3mp8Ti&}uYL?VA`g~}:)Ǒf4`,YF~xνpH~jFWVI]oZzVm*k KMڶQ/H;I?}Hejd+gv~ 51X'WyߡX-׸2rpJzX=U9s&vZhت;"ۍҷsf z7pUl҆y|0XwQ9Vm%)"&\ӦG8E:ַj)}B\-IFVԦVzVd]W=G#ٶ%%]EA7ߢzW9V—UHx;+;v?-]r.}LOFV޽tNdY@/_@ $[a*6jŢw g뮟(KZ ?g,f#L=FU`F\mZѐo?ޡKFռSGe-$i*vj5h~x}G%%*K-/1U~_~bI_KI g5ULY?olmA נl:{iރuE곶#ݤ9QֳqtǸ^%mх7cuŀu#uԉg4th˰ێ tXԫ0|ZRY 45^ӄikdև3[sG먱Ow#>:ܽh{z:(6Ur5X- 6X]v LgӦM7(//ϔmv1&?ekSɧ hASPP[x,´ק$I#n5{+ܼCF[F7j5zpv֜v)uH.UbK,Ҍ3HZnQ4-9;;u݊hYYYUV%KLnniժѣ'& 6[;P@lq/olc\c{S-˛r?{SJ9 Į*AOr@Z1n>NnJ E(--䆻*mS}0TSXSH+nT&jyk+''U AV ,$VS44? Gu>'cΪ_cɫܳ@(<}ci H93-(ܘaܫ@lTi$F*:A(KJ j IDATW63a'k ;k,z׷gG)9}%}uK3wTmg[Q)a:9z+a {؝>ќPH_uiPH[k88r@ ژdIRu/T'![o7B9 X$˟.P<e\2^!PH_\"Z8Ϸ.f\ya|y YPHO~6ؽoi {$܀ӯcV)}ci ˒TdLZrJ9 x<6<6}]gG&R e wLe:Vb _u;*IT5Z"ܜrPY4M~3ZX)~iyPWnjyժMQIk ]U'~6 m)~'cM9< e{mA5Vn@:j!:pU̷!' - =ۖGck }yS׃CO|ʺ1KڶJy2i[7nTD(OC%Qo[6m @: 6uϪK ԗ\4TTMίߴ--UPf[+>e=>OE4lֶeٱ\ i+K%\ =5l=!WXޥydcd#JFdɏ* AgihvoWRܯdžt]! W+_8Y4$Iu_bſ49oPU<Q17 "M%jF^0f*%c\tQ>$M3ˡqۥ? L76H{jyh*>ӿΞ,U0e}bjyjdIr[G>[hvG10ʩ3 eŘ*FT=0}=-ۧ&zԿ^|Yg\.}Qjh'Fn_zCAo35*7J4)7uzzRsUZ4qr_Tې":^<$1CyXzw`'5o{9.#NW_-}ߍ8^9XUeZR'ids~j]\]]>S.SC?@"RP /RKc<ͫ ܵ*Z-Vj޼\KYմY0]vi~/lGz7@>gӋ~)/]!xm~8 }]_[nfM5RWkh͚L?>VGoPnꝐ }xڄ֟RZTVL•"{ OkqQT2lڣ8:DaٝQ.UXJrUK-/MpTSLż4~u>[jo)Oݦ'_J56TGO=KCI߫NRme:G@:32*5uPHMr@z2+o1[;q%7Oq7M VNUOTcduR^Q}!IVćqhF%PhPu<[qe&./?r@ u xmd`_$hp׊+W_Kv}7k.4:.gQH D%9&qhAXWToYS_{R#uՕW(iJ1eȒ(^dn\o ȉ^ihz9*\Fu֯w@9@;y<-noM,vPƂM$ر(###vc;O i/!g$y21F2_2r ֚6zKcEb7tHMA[ȍeY$2F V&!SgsϿ@V?};n:4f͚i#4r*((}c)އ5^_T&{pE#I'vM?t!UWFl+Vhir]֡$G{<H ;Uw$A]F POB2'_/$Iоn&v5=c%yoQ۷$=ȏqUHrJyɓ0s]<}} IOƍFԎӦ.I'J~kt=&RiyWb_sz,o=!Z>D4/4v}'}x*7&]) bBO{wcHK|O ; ^<;Uz,,b\rI޽[B϶?c]pyھzHvIx+_ c x ¸}aݘhu [cFQAa)%VEk< mc݊x%= "$GQQQ8Yw1ڴiSZQϏ[.v (3yYlth\gwEMrc6lj$[{7ocǹMz U+HU9kcd#KlѮ[!Sh)UV`*y2&w넯 R1OStp-andrHmڴ%C/&HHװ.<zǯpD(O]:w/\߄ cǝ&HIA:!W{Uq ^efo^d\RȯOѳgO5m;3sM6U} @yS%Sн0nxwOU[y:&>~S8:F?ShDͷJt [ױc^SȐ?S ='prU^)d!о$_C#/H:oCF@NWӽJ?o}d+V)$33S$\&Qw&M I WfffhXNA 7ۍJ׍dXS#ۮJfV)u'Ќޖ$n9bDh ?RMp ry4z֔'#Smۺ%IɚQg*YYYeXHa~%\vč Ust{c۸drW s=tKѨ?^ofhԎ:FnA{Gh, B P?5r:3$I7/M[+?(u=p_URR"I:34ᡑz_N ?˯xHϱ+<]hEƦ?C}Fzs>@|p._B# may05=XPOuJ֚HO.wф/֦MW_OgOG+ie+*ҬY+jyM4I L ).48V,Y^ d$˫[%k$KFnAK/iwj[oIΛq۫w֭Zu֒jtغÆ]Ν;Wjta$/X[FFpnpozdYdIdYm9v XiKκ;O&ߡy|"n'ηf>}t񄋴^{ -[12ƍ1reImrI򢸬d9H2"r"rlG <^z'b {zwOUVV*ITjծ]H+xlו-[ey!Ȗk9GF9vD!'bq"rlۑe;~H4r,X={HKqU-ےOC,Km{Ut/vcE砽#2ryoNwnϦpP/mK 7*/{'-+ޞʹ$?4xz(lejk0h@fJXf۶lˑmٲJn[lȭXxe;l{9vGGve۲##vA#w\DGyǎQ$⍩okN@l?';p؎x4k؊H$H$C(xr/{//t;Bx$c {o ˲1&ܼMPFF*ݖH0m~B?=6 ڼm[i%TfFlJADmgqd4D"m.i%(U8 =^^ǡc$TjW uJ9FU*//wٶjwlzU"M5c7FƮIXcGcboX IDATآ G p[f>?ww~>|>Sv7LNMHگxc)X&q\׷~ؾĻIxcs0B=Gk. !QWb))M0jhP]Si0Wo Wн[WsVTTĦ͛׷_~ؾĻIxcs(?\Tk^ _BtJ, ~ţ[amm$TNNuu-PU$np naNr\!Z*)ځx!jR"(ځb#aO@$nGy_UJ74UիVYYY1g,IBb~BvG%đ'a$q _B|Ci?E<}đG|"W'qXxw}z²f=MsYf5Y)B8<">DAվId?DCvd$BqRn W_tq~ۑ![=R~~j(9u!BCM#8BHBkőO$^후 aO8$nGlIR.G)~WOhv,~XQQ7|ͤIIHHn plāțaGWR !QrEٚ/ؔp c{iŻ37; ;GTv/K1[;C1ҥm_/k9[ېOb_/#Êr>C9i.1?Se7= x"rq;EY:K'8-ڭ^ZZJMm-kG?>4 CAЃCEp8ΎZڡ%I17~:|2Wθ3(wO47P}ۇ54<o\3%hZYTX@NnnTK,>|js6v"E,3B'נ"W[: ;DQ}K7Uh:En!׈Hv((P Փ|p@@X{ uoJ¬.L";93XTʲ9lKMM%)) ]1 #tFCIx>.TJH Li_f3$fn(L}%dv\D\ol?JZ"}zx\5d,6ݼ?g]e?V!v%pEqh@I WJJ\&85F09-~ ?}*#qjeQa!-dҤ;x+tzan1O|!>>*cKa>?&o>}Pʶ[SQ;qL405yحS3#|ʝlܴ:?Iڗ~=p3A=E뗳rҥzeߟMjldöjvw!˥wut(YFOawwd OZ׀AY`L!'0'ּ ;ed+b߷ ٰa;^3=6T%T54z F 4͢vPN¶mpN1=G2-وc8zek;( ƾ vKWU[*X5|UcgT44O97lbwepֽ?`Ê1?w3Kڞ!9w8;xyO6Ւ;i竸쵛it)/<oW?+ν[[~T=b9ۼI?eϛsX|XNLT1': s _@N>~\ =|U|ɇ칫)Sn f~:\9W3|X| ={4ϼߎK ׳QY}ﮂQ궻t4,^S>k 1tҼ,'<^+g2̋||ڵs N~9+,҆|#'BLCIIf߻5?iM>l$u$;~JoIVf?RaGJ9,C SԖTy(K6Wn7's$ݢ=հpl4yekQ ʮQLb ʼnYU[.Im߱rNF W':v,g O,be);:1Lȣۚeit=ذ;a]dFM+gKQû8n`/݇cX'\4)q8gw8XT,"}(s+6ʍ#ƌK^?xjk`'5U, 2?i=R_FI_V9v 瑖dǪw+6;g4y{l=1ix@YF0!8Zvky9kIܯ/796;x'G0_ײ$!9xbr_z1Y^tqtU3{RX'|ec=ٸXR\Uv1lx8L}wv97ɱ"`ߙJɜT|z:ߟLg {K|5]'^IG1uZ5{.⫏si4uYOt/֚vOxɧc ,B9xgO}ŖDZjHdxP,,܋n)vtMǑC N= @O 336X^u`FWw0Y#bx(qӽg:NM'd9J*{MJrʩʴYf2FG'udFЊcQxlIk":s/IGs8l`=3&(XX<}0q0cߴTTч0t0z߾}{V0䩤5il-|>cWk؛җ4='tgv:HB ?SIO0Iuzx[v7CG׃Z'rW#YhZZ^Hkx=͕CD M;3LzEnDOwcDzOJ`[4_Dg;6/uA 9+.x59F!ZΜzCgR$3TAב|qzF?h#< zϱ%s2yj}8<>S0&rr//aL HfM `Bl?F@"NO6˄;?dڡ\xm@bwk&b9)tqqҔ<Uu>̅qRIE 2idsre, u64Enޔ,_QtA 2(ٱ=,/J38|TEY |{p:ݙQ`ٱ慆5i(%*,-?(î[G-,+ZM 藝ˤSXY8>B4 Q Yƚ {Hx$OcLķ=׏pQmԌ4tHP:n3]rSY K'gRT`@o>V`Z2*t{tRzK),~ByçT\YBB/'rp_۶m_qԩ88nh.6(9$f+7ncGa%&hx<`+]ff?f>SiayO<q{i;_fb) .8Y-JKǨq=#0mo}+vTWvVE%&dd:="N">!Cف7 жi{ #r]XY6͆ݦ۾ |̨F}kv[&}LV\-ίќtJψx;9}Bb^p@qѠ}/euk/U1* )N ZT{AZD.}.Nj8=8^U}Ę1cټy3KFff&?'M!4tl-(FvS2zD}_AV 6m%^6-]54|x ׃װccy1g{#<ʡI<}ڋV'v&(E%ԩtZR&Jvn-R`ykN9斷3rIo:Lm?T+8ZCqER3S1IܳU-/uյZXn˥%cP)6-{ls@6u[Rng9H +4: ڋl>|y,: .{UE׊>q:݆YWA%fT%ԛ`a6TQ㱚LbZў_xq^߈/:i]-+ۡv<>Zg}#ne|;BF L])n 2ܮ0\v'K"\#s)kYR:?ljޏ!ylm0AwًE.?z]bmXm!]|rsZ9]slKEr(gʯ)0\温#?C<\-^͙Aa ĵ4:uGuvNN;Nid%7y(™gnt#AӘq0l茸q)lu_#mc‡\SH:_i6rS8pùuO9|zI.zJR.D{w>/H.Qtua]=O̡1D2s?h,z ͢W>p @Kϸ=btʀcBWGFPt -Q;$chNVՃc&k< `qK˘1i#8& Iʨp Pv1[d;@+3^ӈ( IDAT3Ǽw` ;2=">8>h#oq~`V o] oCskێ}Ma\;Vn nlɷ<ɍ.ôi<ɴ6N/^QrÄ?eS?eFmcQ\x3Dhug|tW,]NLjZ֍1I=B3:utM;,koՃ#sv׉c)ƾgcBWt2M ۯ>nz&'z ?#%c󂭠Љc;/-.7޸$12j~hwܡYF+))Ѫ޽{k%%%0jkku˲쉉vt]ORJRiΝݽW`ʤ`DhNJΎUS,Q#|B6o&33+Z%$%&ҹsHڷxb`&L]-sbGU;oՌgƾ/ČO<Ȉ'6 ')) ]1 M0 纮k֨.Tkd# iӁ MӪ,˪UJ5$$$x|Lm[VVVWfjw %Gʅgh$^>}TS <8s=It fvАC S'7ѦimG%IBZ/;W'H;&8"_$BnݺyFu]6:Ov ī}#8qtGP\' #C6z$) _]@BB!Bx)|۫ze:Q t]g 8 IvK7t< 8T#tDW7!j⍡墨&q펮nB%}Ov IB23)-+&IFN; =Wo  bulܸ)Ianzb e?l_$n_4MSi6a0 (˲Zu\r!8Ju MӨ/)GQ:WO SRR/1l≡ĭ'6iJ["IBnHI ;>a$qmI4p8 P.+]B!B!Dɸjhhnn5IʅB!B8Yeit]WGlGeB!B'0L4-lc.IB!B'˲,0, UJJ W&;;[eeeYfLeB!B?eY|>p8:eTYYY.r\!B!i>peY^r:{q>y:IʅB!B8i4gYip8ۣ _B!B!i7-˥V^n|fv9R.B!CQYYYoFeY>u]7Ri4MeYT6fx?4Mny뺥2ȸG)QJ58eY0񘩩UvvxbGmvHOOg^v=B!Btle^ k,˧kJ-M,@-ko+&G#IRށYwlr^ovQ> N;Tt]VB!Bt|a4Y {Lfh%J)Ep2 =^nYJMoi3M |>ΎM(.? 7F7y^|%Kgy`ر݄B!C,˧DzM5M~6 ð~l 'lJu*Xe%$$Xer3;;یǕ IR.}Ge틷dp~>;w`Ϟ=^˸ !B!D &^gfy Cܲ,f#VRJa&aF!'$$(ǣL uVv]y^N_B۟HGg ?ѣW]y%|2.WBDOo?O>Ɏ;,zjnF}B!!rRoYp8Lol6,]וnWa(F ]0 UWWNz- YoG\iUɹd܁̝?QB~/fs~Mr+gwp/?3̝??B!BtJ)fu])N0i7 ç0 7 WWW竫)Ӆ,-[#Q>kI;UU}Ͻ^r1wy'N3WN'wy'^rq{eoUվNB!BA[Аut~?OII1,cz&WYoysI;y`=fhn馨-妛3f4H8.B!*ôeYfifRRJ~b`644 %ᡒjeeeY~֪,<澾щxB!8B~?6l6ItҳgO:uԈ`lq\׷ŘEu,@~R6MaRr\pjv+˥%ҫW|LB~$)V\~*t:R*;NrTrr %ߡ;$2B<;Ы$޽{E>}zG[!By55Onvk׮&fW[[+ y; ZY44i @u2 JIIB yVVzj\.j)L2ަJW^M^^n ?v\-&rB! #T!lJ)ʔV.Kvhh$J\I8++FyD[!Bm_)MӔR*?.JJ-R.Km߾]E&ѣ5R-&n[kѣ{uk9FukÏ#-B!%YAkyCNGu@1Wuuuʲ,$!?rq8'oM;IR|#-B!ڋC_-0ZiŕB75kWcő?hݺu`|Tǟm۷Э[7 !B!$2۽{W]} uuuQݻЧO~>}zT/!BqEgR몾^)˥E5t=&waCoglr=W߰!gS7l~Ųˁ-yA È)B!ڃ@JJ<4B\,wy/'3qd.Ry,j_EtZ+p8@=̳߳xFGXx {yV8yw8< ?W!B*,>I}G)QZZUW_͜yKۼ֛\z%\uՔFOzik_tK@KmU.=|Tұ ;O8"\{-%;>))Tmz?Lxq$B! zp8NF*ckO䛋X#a91aw97^=pTb ]q(_4X6S;)y\GycƄ&N'??D|jw֬p1QxhĈ̟._tQyH޽Mr]JB.B!r 7bT <|W 7?:soxfscU\ AB MPG9s̙|75M+,;o\˷wh:MmZr"aW.HRA'~7#;+ 00 ,7t#|FF!B; gihp͵t:x0 [>5erpqHw9IHcܹ/4|vjĿo#;dη- q[-;o^r)cƌÌ3YlY>sybyW7Gp&}Vv5=)S20gco7Ә|•kUp!?=dN>RZաjX7S<y3olf]\zit)XXZ[Eժpe9S8ץ/_^s_ 'f[^nL.''/}.`ͪY.g.#'''z2!BѮZHJJf3.u+.m<' vD0yj+Xw2w cIӚγۼy 0z& d˖ꚣ*v@?meD%%}vggWܫx;X{/Ozm&.Fl!f?}?|=-,u}m>$|/- X? >x^I-omG䣏2{j<6MHR.B!D;8{h<u۶Fu q;_=5{RIm&RHUUTք^Wo*9ԧR6"f\ӛMX~2l8y[OD'Mg[M/flb>f[hW>zO_K+ێOy`ιxY6_,,O>w9Mas׍Pm8qdG&ߗvQ_Wsى]qhicsR , `bd $O>E?A.#S_uB!x(l"+;. >zǩ |=uR:-ZTh)&kc)Sn矗Ws14ғkjO{44P2r9-0:YEyc2!毥?<(2,)ǻE.?_)0kk뙞 W:ebl؍?nGt?r^/^mvJ())igeeAϞy?n<'/ !B{egy&GG!;+{C7ZaT:c;#Zl1%NgDIAjNWnk|O~Ix!1ǡG =j4s7ͼ{_xӧM)y|P3{b30d>3oǧeS8=Pu7Fx(Dה[jG#rAZD.}.NhHI1(+.EHrHMO1st2;K^ѲxZv_zs;&rͷ;sXر#ر~[o 9sy\!B7#\sU\pEdeswaz~-i\s7t;,^oNϝ&3覇=wwf>⽡sۺ^ӦMt|),ѣFswqÍ7bZ̤Mc|l%w8m yX>uVU`UQ7:}ƔޘD_쪷ul*.Fx,5}WabQ_§NƄS?-T[@ oinMwxᥗnKLL$++&eY\VsqEq"))Q?!Bq(u38ݻ3cu%3'y?x[>S8g3"3rށA悋SmC񎄎9uqk8_2p@4]gڵ :Yw^b.dG2r({Dp/]=U zNww_PBi@E 8;=$WO>C8?' qf8zwMQ*Pex?pexH \wO_ˈξh m͚5ZIIV\\iFBBiͲ,pX2 #Q),+ݹލa,W`ʤ"[o<):1~x&NQ#nry}}=E,_Ͽ%KQԔnFbʂE3jj!B,YIE+,\^zѹs覰 0a„&R̝7y燯޻w/~viL44-:/`1ci?;]rMӪMӬuzu]) fvvY\\ln5ydk֬YrY7FF+~ǷxeLEϼŊoϘ9;5B!hUpT4ӧNnMiRi{us׳}pݨ#3ftD1 I'2iDf̞+;>߯Zc>B!OaThD!ֆK axKG3f47\w];KذqcTo!Bq?R(8$)|Hٺm\vY.]:W^\6 mEu7W%pF޽\rel۾=B!8,T)\Gǔ{}'Haa!\kJKˀ@B/3|moaļ/¨B!ph&͔Ҋ޾8\r?t-~Z3fdϞ=dggӵK^N.]xW߳g3fΌ%B!=4˔ҺEtIi@|> ډN{YK\^xz >CBB|ɛoK!BzY֕K. _ PHyD?۷oDëo߾puEEE=B!ġTSJ+B57J;v4]),<ٳ \Ϗq]t{uu5̞C 6 !s(*,j&ӔO)*,vEQQaaR),*S1kΏpSp8n뺮p8J)!CXUu6D75N:N ?_G5 }ztZn}tuCDW !BЯ_6m mhGF bulܸ)Ifnzb"EVs5ε*)2^@CAR_ea88},{I}E$ハ\{ڶ9̽ZWb>B۶{zs+ Eo'''q:ƮB4i (R;|?RJ-zI}4iu]N]ϟ~1r3<0~|. srrbooom]NR!WƘ(I:J))RRa!g)%c9R/97<{mu^JcRaݶ1&BJ)H1%=}Rz(˲jmm8d2I?~S򽛎oz)~^ 3ssscr]b !X:%iW ^<'Qjy2ckm !Wi}UU[ :_9%?\ݧO͍51뺔Tt]犢![I)]#<8@uKus[kScUUAs^/Q^ <]]]IfY<;;K_~U]גVc>䬵F^F1>4zl%ϬZTERJ19 A42+91fȕes:[U !1A.!_=gyrm㪪buprrv'jE u:== I7;}ds hrv۲\.ʲ\G}:c>>C;91?>>6߾}4l[ߓ3H'EQluQi\FIj&T#?ml6f\ba$u]g$';4<)*I|>O$F#ȥ7ٓ3swwg˥m<:Vu$i4x.//LTg6/ \.͇$IwwwFrh4J4$]^^j4drFy\VH`KI|2$Iz"2Ƴ?0YtvM$I˄<ӑKRl<%Gx<[&ٟq>4u=4KDN;?XmOK׊\F|Wxf(-%b\:]IENDB`kraft-1.1/manual/images/en/000077500000000000000000000000001450127457600156215ustar00rootroot00000000000000kraft-1.1/manual/images/en/acceptance_o_o_context.png000066400000000000000000001422661450127457600230300ustar00rootroot00000000000000PNG  IHDR{! pHYs+ IDATxw\G^Ab5$jLcIOL7D5h쉽wػv?@DA_/۝;f73;k!BRե@늨B!$P!Bdp(B!I8B!$ !BlB!D6 B!"C!BͰs׮.z__*+_EcrIbccX,]! hݝt\Q)VUrKLL"T8&{{> ;~ Kwq(4cǎc3P-ZqGQRgg'p.%ZCQF[EB[pX 8;;jqY223B ;;;,] !% Đ c\q/p(JMNc\qp(J 9mNq!Ľ@¡(9UEvr !E!MQ1.H8B!$ g#Jr]nl3? %Ch,gvI&VB$6.nzvӼ]W4"KN(i3ݣzӼnJڥK R_Dq/pXFhKױjH tܪU%e; 8Qe &ߝ2݋20yHzz#-B{/n]ቢTWc/pp<+Qm̅V)O}. < h.nfw?3s\ lݏP˸OzY kF>2j|΢pB%r7scki^7?mjĬ]ތl! Ӻ;J-?6GOӇ[a1HFIa3#yn.lfY=8\26k>iLz?e׏y5O{2+ʿ/z7_&hό :φGy@ p"Q{.+gDƀQtο36s2ֆ[ =3yЧ,^0UٟfLE$b;>ރJ% ==7 bԭS'uرc㏘L~% !rj(#Py7|;3Y-+Sd~&Glw?b}י*VE h4Pۑ lwFvZ</$<%gWx;5~Ido_&/LǢ"GB\Yr+O6| d21p@F}nXw>Fo ! rz(+!wdؗø?TrӦ?,І9VY8۔A'^4ߓWnl=~?usUYt5,;U'^nG%=v\΁5^*z(#!B 假CpցKU4 KV 霨ի;Ocӕ@l'ZSSEڵ &r{uTȉY{8ٛW DԭS!C!C٪(Pq/C8/bS?M<ě;E~ԩ]3rH ?Sv1r('H8,wmƄB3ΫL{~.h%^E*=XCi3i WOxJz>c֗mc׭Ot b@ҕS^q\h8Ʉ#zW7\Aq)\{O'>M;;>R猇UohW[,\~}iMy3콯= :hSd[O?`y^!Pq/n2B cKjKy,c"8.=go۸h-5eqY7Z)FP;f.'i[ځ>%MPϯXy.WZٮQ^`_3|ӫ%:jKvesmP>I*%3˚\}-t`kE%pdo,k ]@[_6q6ME͈%%܉ڳhqr\yMז/ukZf#iŢi鱄NWOvBxh#'y{$T16Ch^; oo/S|HF0riR&LΕi0zIaa]vוh((VUʦT66l$AB*MXr%۷/bQd֬YCǎB2ե@ÔT>̩DG_"#م]qW' NZUDi'Ǹ^p¡ؾ3{vcZn%$&;'D$ǷpW.HIJJbμ +`ӴIII)2iSvr !Er 瑐PԻʷy ^88nCQ-(PUm b☷p 4rB{@nKrJ@Ē]F(B 0%5{v ,F].ݖa`4ԲBjÇyhG-ٌlۑup#T^;#DѣxxwQ▊,Y"7rz\!O=U[>BBgӪ$h g*4cKzV8u*@uk|IȊDxC H=u;@;Ͼ%뉩Ԕ1 wi}Sq| OF8a4EÊEגu!Z@78\̈'ْd}Nf1szێ12BB)X/fڄTmͿ?  \Bw11_>u/!^I={٭>:rj&_ )xf4 ZIX[$]|>-$ޔ޵&]^{mOeæKtocQ>*1FQQۿ&31yfL&957z̶,y)0ۉE1z. e8OP0Eѓ!ߤq/ ay*p>盹U&ngiuƾkl`&"lՉ{ojx؋FOl[Ec->=HRo',% V$@BxŇX= `i=0w3+Ϟ>ߤ/)4Oɻ|}ٟ1qKH9{$+-JڀRD_g_94ONY:i.gvpFY7_>~4`*=>ihf%۩j#fsG l_854y{6wo"cV'ldc/ JᨀS  Q>(^Tp҈pK!<9a?1Ϟȉ9XOs3 3BҪr<;Vȍk9܊V͠`n%?NŘti VҊ,9]//&VCR+{s;=#-p==r@u,89QSGcϿҨOk +*^:yDZJ U #f@G`t ş-:z*-z+ ܠǹIR!% 0;q)Tͬ~5eDDFak9(UeO_x/No j_b9zk`rD±,lcaxNF0TV]G]J)Jpm: r8g& D zoOHKS8oK#v8|4@_Hc!5DFrFFԖO$:ÜLfŒUu^Zi.Q. <2Zu)_t(%2=vˆ-8Ղdeu[7դzG.CzR6FjR2;`o6cHKICÜ:ŕ_#:j 9F)z;vE*))Bv0uqȱe|P J'҈ۼn4{HN"mGMN" {f&HON:~nv] }grM5#.%a21oRV_X7 j_U8ӼOL Yl05]mí+f zz~HKI\AK%5c]g˲?6v7|lx a? o䨾e~ͬѴ>5lH 4M+N89iطQ+Y= #yjq9'[.{аa0UUcԴ8.GȬWN.04"n̦bw.-36Zo(1J\8ܱ+KmeGC9Pvާձ|9mVZ\5GB?!f=b%4}%RILLz]:|V>㙏G:%޵+Ozu)w/EW !YTtg(- Sc/\!6e qKZ"M~3ξA~szNe_,p @΋2g⻬pbwiZ.ĄDn~\ѰSK6ĵm'k9Q,b(z?=15ǤСV~;cW`Fg()ޡsҥSm"nC|tύjѱ{6{joԏ<'3>\ޠ@aCSOx=vJ=;^Ioy*lI]&n< ƍQo֔CZ3kQ酺Əsk/s ?iwg$( |\>K#DqЮCx5(*r]PJU8]ٞQAA˰D2OZIeu[N|L:!%sī@uG)F: f 6UYU9z6s<\$[Xx 2n|}ynzˉև2%JR:xʔR@AU eGX^FEG0̫PS ׬wssns:5vstoۮBpsjGiT :T TՆ&P&7kٻ̱z~7:x#]3ϿsT\"I8,:Kvn=4s8^q}7N1) m"zuz*q =:R=:6[p633O%KBUO颍t:vU+a7L?OpT7Nb/ɣP2*T41 _|J#9J V4{=6Vjhd3zi`xMKaV(5׍KnբXd4Ֆlל4 fCSKN8T-E#*Y ! OTΞzOi\0yx1le +4kFDy8\=aT?jBZx5fœ!1ě(66 MU ͆MU¡BՊ<_HBzǒqQÊBPW$Ωm茼Ξ؝ L'7/蘒4]Je j h2?ͩ09|m{Z:)dYY}N%ݦeU@taT"/3H:Dz 3/鸞XUF0)J:3#(= =jަTG@kQކ+d_jMTL47tl ħ2󬉷*ceˑdSY,ّԴ4jׅ"5--evvvw$wbgqi-PaB :G=lDXM}Y=R.8>.˕ADů_SYwnה¯9 X gr׿uد52px!YI>Oz3K9`OMۨߋ,zyys\:Ijׅ"UѱJ)JJJ+23aTnfxE*V3nܜX% {t1kFjZNf17+R:=7pQK2o<L4^LXVXst`D}v&4qDj &6UA|TR9q]әx'|ٻEPIBHn fיt댼ޝ7d}5.'m[%5 X4:9I0B''GVH4?r۱Zo8X2Xn-k֭-HHHHqugF ob1dIE7ֆ%2;G-Tr֑d#՜y[Su]!M?'6rPiiV8Wk*&CfZ3*7|s jWݤP~``hY-N Bb}F 5tA='lgXQXԫWď7>蒒 dm7vyszLbQ +YU Kj]#V,NfwYP/ąw,|!Uha9x=DFU2ˡekY2p;18#i\2b='.YM`E qpl`oVNN wDQll,QgΒ"B£( ~`Y Vtԭ\mM6""4/]*5>4iXznPΞ>zpfzǭ1<)s\Dbg 3UrqMm1|sQeɔĔ:V['k` t#XXH\U9w}#! gf1͞烝_<$e5-aIj9}''\ubeD I3jndO|iWZs}iR)(1RRR9w h' >PZ9$^8"B{T$oo۰ n΃[2V]u+_FT45; ~Mg?w E*5%SVM ڶ#Q@CQtlXmϾ;fN|͘y9}4߸X<{ /`԰Xw/}XZ9'vD}- /c줁5o:l_yCq|@R2 մ˫rV+oLCHzݏcSdȔs8?`[aY~ #)c`o_ı'O͜?q#?1`;O@Ձų'.4 `RHNBʁTQl%~"~M|V<83!||{jWD`&п]g^Az'-9^\?/G ؎-b.? }qBynKαڗ&x>G8pV7'u9Cn]jmXg+ǨʙXudiRJUТ]]|2v1gq>/Fy/4˻/ n񟬊1.C')OocA$iYZ54 'g|۶+M *nNZ7JH{4ՆQ8eſfut^5cgQmQ8mïV ܔ<7z*V";(8wB Ō٬`d^Бz8g2=ҵ[O٘f%6&+)^U 8dX R> X؀*CEwژØ,*k_6N;êNr2ѝ5|ss@kR)CgY`5oӧ@>}9/[zI !v}Cq7i$;¤i7S#*gf~ (X4TUS^e-~F3;\)F; ze󷒔jᛞm&EzUjU9dZQ`Yd?MK?gOOG_>Q(P!n]ZnLߎ)?v9p5 .S5<:}*:tu5  ӣ8}N'5WpH9IN\t'Ǐ7n8t(h7)bpLcJ_R懥z+8ۏ'1:ti$<)}U.`ѝvxk|&#B%BQSJH,ZsNu1/-C=@y5fq9Lr +oS{PiۻN['M=s3ذ kl8%GIVE6 Iwԇ}lb߫u)E@d*ξ8Ha(ne_)b^* ~-ePiط*!DI0(m/^DEJ!4>iO ؾKʅq~Ë/jFǨaj>q~_I3xumYWWs' `vV'xͷ,נCݯkLNCKPÇص۱oʳxlG답OZzI|}Η__Ҩ؍Fژ0a8X N~*_AD&<g{Ѥg~ N=7*o&9D F?jz/66CBX+6G328$F٣{gy{ZW(=_t5 ;z  m<:M&"!/ sN}jfeO~:Mgosԭ[(!DiIF޾#*+eOWm):ΕahL=?7xXk̨$Οbd?5ƸTɬI}6?<[#q/#?ljW^-8pG/^j͙?Gv_)J>txh;O^ox:8*+F<첁%@V/kRl~:gXa~ê:c-g`jrB!IEaϴ?imMPb&}7']?tL0ʰP..b0?=_wDE #ޗ kW`1fLY 3t_& {~xa/ƶ /ra=4>0_ƌ?Bv[\8K0B!=|Mnإ&F9ׇa={ԊW5 }}0f;pDn} pҁ2uCWNz1޸%-Fdt 7|;Ҷލ{23|g:w- j@KO`Y.YK+%Bq*F.dTYQIOq(|0'\&QUŢx=?y9]t(.8^ٖNM5" ;ues4F)Pq%礝z]\U1oG_O!V(e!(phb85xdOOyX |KHskNs8 :t: -G8%ƑDAg#KanjzHZ?u= cN4Ju8B\\JnVNBqknw:B05kX2 >߆5Ĉk}o"C륍,J݇N{TkN +W4'Ge7y–mvUX2e=T@%!"/Y|7bkME8éHW7 x7L!D)[`OJJj1FQVbp㐶;rPZ>.ތwU5{!"=3{*]xDfa?&}/?T93Às+ !")ڽ,'Ƽ{+=pwqb : #Mo| ruwT4yŻy#s}WM33֜G3amB})E!ϟGBԔT.\ ;PPN92ayOED^3!@l\gΜ%%%0!D( W[W9 T1{Cm[f]B"{[!J:B!$ !BlB!D6 B!"C!BM¡B!&S!D10e//],p(%];ox~hCOP8ѺE[ η'(ޡC!D(X@qad;'I7_ /|m9srg3(<+RywЏ슣PEFŒ>tk/㶊PFJ~4q3jzMFܵ1EGX8ICs&Ag2*ǴBqoE^g.h[ս]X]ֲhPkKywk Փim$.Ji3OTe~]M+f[}i;>2gv7+!IZ(X{)zrw] IDAT,'r;ODNC! ! H{ٝ$@$~߯׼gyyy_B9VѼ i d/[f^Ф%8BTR楽Ԓ|N[0fBw&||4!͝jwb҄L -yR% `ڄ|=i)78ܸ9f ٍT5L'U郎3mϿ3ǻnھlgW0~㯻gOљV͡o_'3jXbg?ɲ,K{0%v64r?1 Rr&16Z~eS{f31vnyOjZOԉx=T*4;^ƣ2m8N~qjMWx}^<ܷh@t:K ma~:,Gg>%=k=!Kq{ry2˟IbxJ<%|l_1-y8ڪbγ?}^&y=/ *r)~d>ȣRPPС!LŶvrWi,}! g6lV|>WSd=Q$E,m|RvIL䚑qRQQDP/#fP V3˱k kla?T4ʶo>8E̋_mSL l)L=o mb˲gǫa& 䍨,>4@濿>ͬxgeS`bp}clʪWqxn m|z%_=90i#[}ɣE#˛L-~G?=@K{mZS(۴gsGkٶK^JU tV~_CC!‹\v9{˯t,~غ`Z(ٹ}A71o?F8r#j-?lfC9 k-qӷ f6wXyal?=c :g .$UP6@H< `;c4vlNTem.r'TK6^1݅=ousɔ\hw9hUK8{٢(N}ŧ`Ҕ)Lf%'v)S4ފod2bHFMwOɸ珣BqIMKWwߍ'wupC_f<:Z7Y<iLjz:Mm ,-O۟n:/oam+n.M+:t:G'ǟСbR|޺e*LaҔk*,uM0שXN&GƐ9OΗ T ~a|A؟9jf<[) wצw^ܽd 6l`Y]Ȫ شkjr?v51HI^= 2DC! 4|)|٧G_|fzgIYƾ$6_z7O\ ()Q 9ᦠ "%U1A63ٸ7a#y<֬NyHuy|N7hTS扛gEΉPME~ڮgCmsn<6mh\lζ's&`^7ȉOnRZ8.zJJjSZ5UQōk;;t\}$8BK/C[;qԔT}Q}8UVRCArV% w|]dfK㋏wsl~S##U}_F狵@5ey'r`.t\Mcd O7 # n1}j9ṃNS.>fL XgKԔ1TU`A&:@LH<\KbsEkp]h`;y*R}*#vlDMLIobר9ʏۓ,@U^Y{0tsr(,A-&OX)8Kt`˷!0&eo~7>,o-z^8ĊE_rv!Uk\2' ]E _wgƁwX3hd8&0pČ'ҶͬM;^"vK(C/C{cȪߪ`_3 T[F-6y!_ 7N`4<~?]pu&v(_pWzq_y(ka;[ Hyۛ?3짼ߏ`,:FSKHb+Q\aދ) xѡm̛;޽}2󽅷VrQp,e7Ɵ'Fa?[*j!+.T+#C~1;k:nfӦضcO7ױeeW?ߙ-mzbX0X,Y9DY{|^R>dz|k[N)w+{tm.iOWP ^O@@@C!.4d<"*Q:mSЅaLoa +]+NC!BdkKy:Us~KC!Bg'3t5J !Bf !Bf !Bf !Bf !Bf !Bf !Bf]rÊ HMM%//ڮ(EEEQN/[8zy=LYYٕ䒃իW_U=-I(讎dd༇ߥ9q\>3`NoM]R{ఢwV]BHFYX("kDs׿Q/7? ߫ص:664'ͬ:$ ~B>\A;r10/]M= Nzo5O$?uazm2ּX+ 5Lj_1/'ӹWNZj&??_ZJეQ}a&ݬ~P"ᝇͶZ'eR-'OG9tvI=mr-7''N / !vYfٜ͜SO=tz3]pݱUYĎԹO$Ùhs*o8Wv7`9O?)_̜/;Pgƻvg{jnLbɂ;6a<&_}/}EZES@JigĎŘ)7ǵ xa򍼓S3OTכ[%vf{;>qc;N )sL$vШX$߽Oq+4qBt K ma~֏Q}*o<]_1*Zu:˞?~ɷ,>:ڲB³zՓ`^~Gng5[_[`+݇嵙q)Yw W3=<43OCҋ/0|0Y Bw8<˷lfG`g:>syI{߯boO!'O$ <|8ʶqs};JWB= Gwܭ>Ekf|x/̇w5o_섮2s״RgTKe4fRRRos Wy=3O/`xװeAܹ"ö]p9Jq=SbJshc9ə8z2G4 j4hT 93MZaE*uU)i?f2*TY봻B׿gY,Q.iK?,VxSou=Vڈ⌫C9E47 `;d8Jf#2вvr:z"[]MF# ,J+++cw y/qqqam,3>$Ie*]5EJcQY@@@ʼnּO}aᦧnt!//>jYrNW=^c08ͦZKe.OՂޗ"R`g_k`aƥ! sE.#kdTPoi*o/߬_nv#L1dhVw$:ߙ<*qK|׏>qtkL>>L/uᡀ&^}c&u?{|^ ic̙+Y fCC!42ĒvzKij _yLcTt x,GbȎ^~D&~s& {S>j1 @ԓKxw#cG2ym 'w(f7o^iK.l|95kfŋwǧ[1o۱]g:vL5r\TU=kX,9LVN.#:TÚ_wUB^S3"s34 `0 P/\ !fIm[6K`(DҨ<UO1H »LJD#/HIKK;!CPYYy_}U.\[WVQ!Wf}Y2 Q+\`P.N...meffyQsswB!UG=v]p+rU}{)f׿vIB!Wn1mڴ x,o!BU fϞMPPЅWB!ҭC#84\!'\!'Q\s璗ɓ'?cܹWVB_,9oC?|j"NNN+7k#^9U>wCeFƞ%ozZFw?իml;|To_Kq?CpOtjvޢ`w#4b$`Imu>3J?؋)ʆ<dpZ WQcV0]Ș>S AI !iOۀ MO%eT5h F C(ÇՒU :JQ)N]Ϸ議up;( ^5uXyf$Yρ:;A#8O? iF{i1lݬKÂ[`D`.#k9̶15_\t4*͠7:0=ù omA#?k vxxaUO`\O̧Y7~)$dҿ_拎͛fҥK/6Ki|III]^VDD<b޶c'C##ϻul~j$Ok1\TU=kX,f,K묜\G\ 70}betÒ2228΍7tgR71H=$D4xLG_;.i{`@СqY,VB!Dg1ci m]x/B!U|Ccǎz\!l!BcCWW6rrrL;?~| vJ>B!WBMXX(wqwqG裏oBq)L&֮eĉ888\!~azLa[7dw֓Kڼѵ(筇B5A|TUU]88vJDS9tuu%44GfVX{XjZhhh=Eٳ;Ѓh"kW[|m$_5"rJl ?lv7.k*L$nN *&~Տ4G CA:AZr:EU4=FWg VCAn5΁tUWOei(8qbW^={f<EљA."@>x2hԞ8́>\'G]PkPő a /u/ Fcphde8`K=e(VÁ#"=5Tp> yI-UVVt)wٸq#_qϞ=۷&$$Çw8_!4gkAh0; * Slof(mʣܖX)-ԛY՘;h8!΍ 4j(8e޸YV q4(PBj2!-3po.g08ɅD/`BP'+ACIidբNx-UL!=k_cѸk8SY8gxD0z0eȆZsDUtml,͵hnqk̸>v4w{I:ZH8k,c{wJ8ӳiuqӶ18̠梷adL_%=dU>tvqܙ<2ٝ]Rp@FFFiIII7R0EQ[y7ZMWUs 7k+Vn=B%KMؼy3gϾ貌Z<vlu:l*J3 aP'ʩ{n!2r2O@\tVű tk%a^R'1WGI*cĄh<jjUlt`ⓔˤH{$nGI_FZ y8=l ՝ qkbSz{p1Hfq3U슯Ůnt.['m?.{ch/8&:5)FFOJ "ሕ΀D|sf7wI k"""pttlS޽>}:k׮ms8Kdd$C !((7771LCJJ osӧO'$$ࡇ:II8x'3Wu,OizgT=Ix2RC1agy ZױtNp wF±Mٜ iOsI9oNjm0C|iUdlq3q<\T';B|s[G^^z:]-@{6AzUZS@ Ơ_w8TUF: Kc)!/GNPخX5dcp(e'g@;} qm:fwJ2vp %R@14b"C9o.)8=z4+Wl $|g|gRt:BCC;w.̙3|l6-i+""9s\RBіd<9Cy~ۑuI ^Fcxjhk(UAFPTfK}E1M;4ܲП3E}Ny@1۽\Ab*kMX4+QrD:8mvwj0xGYhEEEQv #<·~{95}t̙#=B.a2e֬YcRoZu Hu*ՁJڜD ;|To_Kq?Cp t,ɩla/ XӗQCS]5Jf Ø+QLZu#\C铷Gq02ȑ>Q)ر6zލЈ84i)$n\EYv #c°=ڒHٴt[#Vv^ٶ{Π1 IɊ5޽rQ~(:BVif5~{I۴4ތ߯l{tLP~6m:b6;%---?sZll,wygiǏgٲem=BBB[ݻEU >>]WQj~F#G())Jqqq͍0"##xB!:쩬GEAgJ`Pzw;'w7riʒae!:N=Mg +!BLC!BLC!BLC!BLC!BLC!BLC!BLn.]d+]!/DgcUC!"rCl!Dw$B!B!B!5VI|N61|  L] B!1v>?)A='ȴqu7Gߵ5YڂB!.V^ǦEė|@/ӣS1ͧkkM]B!.VVtzEӵxQb>C*`NfѬ;Y̟3ѣ|lJÒ'nb˜h05o9ߟqc0zeRR]1hY~|b=ݱǯ?x]fVp7G(>c[%rG\ֽ3OSK|b 7YƏUhD8Ъ9=uX{E1\7nM)OyV~%ʆӱeM|nrLﮯዷ>#. k2w C|&1m#|I1Y|פ~|}x}߼ x;8>raZ6<;?gg[ik,&1Ioޞaa?_/8:YöA77_7.`[ia≛=A%~ߍt@A%_s_OX_r6M@@ zѽ{BE=`^;^BKGɆc=kiF|)'3KSbuMx*p7?:'v>5߽w|M9fDdسv$wCR_KҁڳZjM=B"dq9?H1Bx܇g}=~ЮBq|a T8ȷ_V D=2/ŢքnzO\~g.uNElk=K&|DO.oڕњl$d6=I)d_`򏫉"?Ȧ0o&OW0g`-.ͬǹDZ, 6Ƞq VH#rڤ1v[V dhW}=Go:N[Ö 0V^ys)_K>ÆO闾 IDATٓձI8BCJ>٧S}:KVVTpRQҶ[p nT<*<^$dߵ++7`hҍۢkׂg-,6X%'D} +,=knDz[Z {܊uwXK G³&Ji*u[DZ5 Xy%xF(Аkl2ΫeQQq\\ǟ%|A51z3n'P܉m_"-V)ٰfoҪ bOPgZyhnSѤ =-hFZ^m>^69#ޭ,"Sfsr=U||\oZ=`@kF3w|6Ƥhq0寉5Yzd a[2sijA丆E')*4ёy ^b]lѦcM..ꂫ+*p0g**fQ׈J˨W3>s2Ъ *n19+x 8l7M~̝>ί]֩HL */+n.7t^ʷڋGHp:/1p(/ճU NdӼY=>57WZOjY8hˋ cxX,MYnfXSOڣأ5O/z!:Sܠ _7Zu#ZWN*"k7]-| .p =O{າM)X mXmGR_s1sjȘ[狞D#V^mr͍/̟Ҭ,yP*~YcJ; ٨dӓ =Ʊ?XfM0u{c(4=8n gƣ4`ᄳU8'$6h@Y|4pEtSWOlO0)6}akV_ʴ I!=b;?;J)TĕXt"3WzP0OGŲM>Z42}V.hFRqNEd$ GGϟr:蚄ćpl^$!LzyB~Lx&s1W??gJ:`"r"VxHT|ʻ2f"9B<(9w)gQ4f1iHޚ| #v%hJnK*3/eԛ&1:u/F^80-^[4iEF ږzJs$:3j2+ǐ MJ[k5NŨT#?~ږn7/T`1h:4ƋvCz!TѧØp= p0||{/_*/;{TAձ=ma:i| *#)o~ ],3g&~sT;7](͹8D' #3\qķZ[*9}ל"'^;l=~2 B奡lPPp~ڮb|sϟ=lP!? B jYδ9{+fElroe`3UKG B޲4(b|z6 c?J !s 3 >Nq4.ԃ KCص} G+ERCn^7apjrOޞDi$bфvJI8B<}Yαpxe8zԣ5F ;NҎ(9b;S>~Ө5ݾ^đ`c:o2fT>|ukףɛ_T2z>n 6ǮpĔ}yP0\^,ݘ~c>S1mʳ)YK#3'ԩA`&6jI$ts-sƌ j*t S3W;խC0mI6OvMSn Hx 9|[QA0m{cÕi5^$T +7`hҍۢkׂg-X6]P+_)Aҕ$HKx )BGb4Yn{w"55kTqc!h$w[TO3q[\\n-dw5,govV/Oo 漦Az#vxv)Rɟ/I#6gqΜ!sQ mp̜n@UA4t-)mKmi-^ 44 $P!(Hp),Yʴ)EDٰ4o+] $!"YAH5ōZaRO&** @OG8ҼMi\ xn9CW'qļDk&(q3inI>7; N.8%zoCEU})ĥx6bXSOڣؿ {}[7'D^'BG]N̉'Yv2w7>Qɤ'zcQ4e#\="k-%Zsjd4+b`fߌ_ٝJFm8ѫ©٢VfƼ؋]6hU@c97sc97%pr/inHsk E{?sn'۳7ndz`f:W4`9YcD6ٞcX~Ye"u{Rш`!i!x4af̀}{hŴEymViBѮ/1—&KNx=p˗#999e2[[[@7 xf3DDD픔FcֶmmmqrrGG'm!x.wl'S.ip:Νȑ#\tK.P0,X+FŊqpx``8tgϞҥKc2O䄯/+WEx|!Bq: d2e۷( JϏʕ+f/>>~Ng"x19)PkWԕG"N8ɝR\9(Wy=qÞ={|ˇ?xyy=049rݻwsȑwG !^c$ !rcl\ŅƍYEQۛ6mp96l}ܔ5zq mmm  Dvźu눉yu !BU ğ( ŊXb̛7-[d;_ݺuر6= 6nݺ뉯_!Y˵s{]n?.M!Y#;M9eS,N¡B?iȊ$ E 7aɻw:UxE'P!I'Wj9Ol[!GW*d6c))j7iD,z|ۻF %,c3^P"ܼME:'Dzdv.]OFOJؿ=>ƧQ'wzh( (cL$ !s`i9 :'0\PLÄ酱|K-,}HGdWM|CUQ_tCy9)нc{8~ݫ`8'r"u8,!hB!y.^6fȅ2 D^L¾P~Z㞿c6댦YW@UY@p(yMx<Z;o]Ut%~̙i5y2HoE5 n旦ɫPI6LNO) NLd7:CbK9 h`Nqv.mJ9<-<vPnӮ. .ylk2*_b1| 7ɻQЍ]?_Γ;88e aש.hw?efwy)`_iW`7t 4]J[:}8=Rj).kC?CNy?_70fXdg Y:ɻZ˜VE7?O[Sr sDH;3&@$FsbV<ޝɈ;.|G-K6B8Ngg`يt ҽe~z"Ǔu0epGsC7zn_FYYe8K53Vdz x l ?a_hl 9QCűJC]ϼYqk=ˠc"+"㗵 yC2fފkZO{x֓u]GF!9sظf~^ tM{&אp(yf6P $)89߯!?"|~1kS_HQGŪ5Vō~pRNY5+6aוڅmQ{ 7kυ>4Mߡ);d˘/mbϥ4z#g#(־wl{e*'Bbհ+ ۡ`ı|"ٵq?sqt+'<r|Y4=3.QJ[M`_=5 ٢`K`7;ǡar:II`:ʞ Tx :@u[(y0 -t3{B+ԥ6%gJ kPWhQ[, ֠OQR14fZYbC_9;Ԃxo'ZO=0t4\v4 *{C8ۖcDŦH8; :4\ʹMߡ9#"l}A;6sLvm 3L4+ !Du>J9;z q:+ *xt*(bc9: G 73g6!U]lu!EcVUK=gn=vӍ[P PPkx3)lяGhm|8KB=ED2p*~[h% a1(U)egݵ{WXLvE8q0ezt NV-₳Jr|<:,QwvBNL.͆|6D[O{*j툭ŭ ?+NηtC'ҫ6M?M\0y/`;P=|qgXW>RWX#źfD7 cӺݬ|#ew>=ɓ_ P1>&f BG@P}GL&g.Hqؿ4;/y䢺Ny]l;5pIXۗ!V hQ,gS8a{[K>㍍hWŕ $ْk Db,M,??+WMJHλST[A/54[$1:37(#5J90qeiTqp%&Entupt]iRu6'e}8Zc̽{zBTғyUKߣ w[P :*7HKLzgs>.]7nBy?]M4+ !DNF_laCIwGŤ`H!!8SPߎfs**F\%Z4N@uN[]tttݚҍꓲ' 1HC\qUT/v vk={-#ʯ)wqtPC̛fB:&an7E+#jkP)_ ; 0XVG~3nߖNߋv> tbv`TZP##"֎eu8?{`|^4f]5VFKX?wQ:zF ᡑh9*xcsQq?1Grlh\ YbzrX':u"1WCו^M3f WNB~{451K͡B17!o^ͣǃrSòE5;d|%9_얱h瑼1o<4zR~IE՛ IDAT-gUNXÿv#<\1c+|<͇_u ג,ѓJ.KϾ#mD1TЁ4I{`כ# 珘 n{hS>1[nJV .d?ya4R5o/T-m(X<~ʀ3R`ޣE e]ZWT 6nxj_hX͛J,)q8f{MIS/֐6%[R4b S~`럑;P{j0ls 3sE_Iuxuj}9iROS:Gbi|f)i{a43gX^9aJRm*UVgeeTT FE@ٺ3x9t({Rш`%5Bf0\:!rv p-SGKXr"KaxOMZZ~-}%\=9}+  BGC!rϹeӐ0R:u ⍆n}qnKNNf :BNN\OqJ.D B!Ck(!$ &|4| 6 o.'fOSI!D.Q_ !8~Jz8`6A?\¡BNV\aӧO\D4BR(쒳(4+ !D.y|>^QW/o!/s4ΐ!CM4s)6(’x\'Z. BK{0H$cҞqiykfiɴ\6H6pkOh$ !D.mvc2HJɳÃ6Eb\FTp(B(|;-YYf񞕕 A¡B!3|ʉh$5RRRf4]G6m pG@4 ϓp(d=ϺB<#n=SӴ擧аaC9|0fbmm`# %P!rɓe-xqe>gM&RҸI֭i۶-W#" 6>IB!!EQ0 7FX4 (\@uJB! .3eE̼Yt`"W!H8B!s2F1Wnp(B= yB!"P!Bdp(B!H8B!Y$ !B,ne]IIId2accS~FF)))Flll]ABQ}ܿ)D_TaFFW\ҥKJ||<ɤd`aa-vvvxxxワ/>>>ycNԥL1ѓr6Ɩގw=Gr->`xG$ ![rڟᛗ^vhES9{UCKb_G.LWu8`9_V3#^Nۘk._Kàw5X{cngu[6_''̥]>T09b;FH18QvG> o\Xۙ6j2v#G }tF4˸|XFG&xHut nɂYy:fʼi/J=j%ehPl=?jEqE1A, V̵,ۓGЮ^oepj4Q5 l_2ǫ] YE-Lz]6bK0c3黰 G56{]?.gBa=FC5s Wf [:'dܞuL'avkCؼ/vfx2C\}^a򕬜z`x;#5d^\@;ǜOdWo̖h1C%\bml[5*|t^sXy5F3,r?C4 k1 H =Rc HBHѽ)KϟQ k*7M#iUĄgJXcI8O~3q_7:9wg39";#ܩlWV&/1`G԰˜N>Rkl/O0V :+a8& NJ:ڹM9WNonM!lGĚܫ>v, P8m\괧U[Ŏ2iYࠂOM%,<LGX:Z]:SIE.J۶~Dnis}q( ̬a1כFq8p#ԡG)le:{6ٛ*lԙV%n;smJà _EP ¨=7>{{fCX[[䄭-FIJJ"))\kUggg찳Dbb"zӴB#>(} %w24M{@E]' g]aڹnsk#'z Q1:Hb>>5F %Kdɒ4nܘ8]8~xQLUFJ( xzz@ eڵ{.k4>qŅϙ)CNF)론+ÓA|q/fڍ@ (EѲ~o{Wt5Ӗ^=j({!sn5ɯr!̄o=#~2 caʆۉ팱<͚Y4 ~/s-e>xy '9y&t%T<=cG/T.X\b /ԀրcJl@٬k=^* OyJ2jbzΎ֭[Sf'6p 5jԠF\r+VlR -[l[Q|}}u_,_QV'M!505CY3whĤ0vV/*}5]A+A5b\R~a4+p#Hx}PRFK$aOZ30| `,[#"mD:7@@Wcz華}@ەx8Pvc*{cIwFŴz3D3F_C˪ѳ<ް2_F!$ !DcooO5޳ LЖ;Ӂt nDO`~v%B< P剮[׮ھ{$,<< ,:3D~wOCQC29fTO4|m>zH>gҟu1[87['0 E0q>d5$$WONp(@Q;^oZ EdvAn_ g튓,枳_kףsNH>wn[/[{~0/TJ`qy*Dc73Öuf=wZVH?Ģ K9¡3$ݽ'zS^!OuM0͘fL&餥ʫJ-xC f4lLvOVD#m = iԠu[ddH0c_nʷg<>TnE6Ik$N,BAԮ[Ưe0֞vuzӾqmkԧ[?OFnp% Y[H`Ňy04tWѧsX:;-գV|F6AԮ]̮̫N?إ%7"[ܾM-W aht=Ƽ!Q M̠وGqdj4(늕 .^/Qf)21A, =Է[Ѵu?_ї&߬e~\Ifn{mQ~0m{e4lw}~U>9'P!~UR՟T ?jԤzZԬ]Zu0 㫯xO-|v|K`FWVLdU(k?/culʱ}a|c A,80oɇӢi2z[g'm?K80cS~׳#w jM)- Pw,ٰ_WwxK_5?ܱT ^_KT\֢35bW:v*ft.ggh䍕b5ش7'cIs3bG5%LyfTӯ] '6]L2Mz~Ԙ6X[D?Eѽn~,Q/і΍DʯGrB/aT-qsY35C "MPpzTUtP-o>PrvtT\\]ܞ?'  ;7&8Dծ zˮ5}Dp(mͣ .ёh_DRBC_g>Q1Yc@.ϯ`/Ө~mէGs9 g&/ u1Ր1j3թa1]}3ס1իUZW;uY1ڛ_ o Z܁t_N9{=իP+-4+BI|!qG7XSU0b-Z׸FlLV>e(l-kp1j)Qٱ@wU k[aZ=%g0}`3Gp2-Ѩ b_Thi\?{M 39:IG`G-[τgI-Or9'(8;)\:ydnV4̮WJJǜ?3e  gpNI@G1QW>eO/eߑ+X#?{C.v+La/ݳXWw36 ƭnʴv1 wcʲ)wµ<;Պ9vl o9Mg;v>ׁ F\ft%aP>ZK'ha,#17k 6B(HOz8D?ik,}=7^'wQw߷{Isy<hq@P" tZMgXbj+b"TEl-P1(cHuC(HHDDHvG^r]>w02~1wvf3&ÄGPD$qi0 ߄d,,4m&oq˷rlXQ?aˮe8)eylE̔ >D -ض椕p>䴡Vc0y2'37QHoc診lJU aâO_6đOH|elC ϺB֧-dJ7C&7.cI7iwLd]zzsrY<Ҧ~N=7maPӫI!6}~>` :UWPDjJYIɨz UՆ//Vy=8R&LZ(-@V04~ڇlON L)p<9Y?'9#ΕR__K狂ZkTYF?_<%r@utT[9ȂOstR֘Wx' CveĬX"~O,\|#Izr(G!!}ޙ&Leĥ utƤq\juyRc8_><~>;`JcʺQ ^`Au*6a~ND|ߋ<GREjTn0_1'HT- =K8B&i 喢|2$g[zzoE Rh?נXb,N18iv Eѣ)w f۵>ڙ6ZWZ@=9YNƎӻ&#lIB֙vɣ t( !6 oB`x2!6[H8Bx^n#;_:l& o BwL&~~lUPzĵ]tDbVUCC΀ z+ܝ9YhjcF t.C\y!5$8u]orz0|ͅA BxBqָ{$z/7W=PB4^Bcs]Cתfc@4\8(DڳR8t>hZ g Nw`T>IENDB`kraft-1.1/manual/images/en/catalog_material.png000066400000000000000000001776661450127457600216460ustar00rootroot00000000000000PNG  IHDRx pHYs+ IDATx^w|n BKP+6 ("gz׆z"^ł]{PQT좂"E@ eG$''3[_u|wf3&ggTI-H܂ 1D 1mBt :"""""":Dooq{{""""""a rh.~M"""""RŐZ*Bۖz<[~EDDDDDl[*nvBP[#"""""Rj+Ԉ5] j:k뭩lMj*~kT5HaOYu}յDS׾M] yTU~jD]NUڪ}"rUVDDDDD}U U6QUn_#jPUmcIvHP]0$۟*ֈTe[WJ뭊ں)Q[A/I7ѾDTe_UٶZՕ@U*'<$c$+"""""۟dc"z'*ʶբ.~ k""""""U/PVe>\*nW-tWf[{2{"""""RUw(:ĞKDe6bKwe1z,lLl ATW=ٶ2Tٖ doFvjAbƚ%'"""""ۆD`Xs.^$_'-Ȓd!xz5?~}~5#ğmS0koίǯ/cIvdCYl?o1\n;+'"""""ի]nqkk$MVA+~oIvOHݔhKpq{KMWJmd離Ɏm\c?~=~5[ NDDDDD*-v~~5ۓ%;V[*Ip9/֜oέc#."""""ۇ1 {5gsǓh}V,' c9[P_кͭ';'~6"""""Ry nn';6Bqк+V_q<'ӛT?^@ =A붠u?AAu#|,UVDDDDDm4T7Bkк-'hWh$כ N;>+cԃo>Ssxc#."""""ۖ m4oumƱ$ڛh_Rj2%Wwf~~ۄ7n/u#hu~GDDDDDj_"2=AAy{kXۺzuqKJMDHT nnȪ-m j\s""""" pAs~uQnT3uqDIZMDY>@>w- _sƉ6"""""R*m¦֯fݥYw~KwHDJd@>@9wdƦ2^]UW=ձmQu}T4Kݗ]s{mAsAu='"""""5/VX j{˳Ҭuwi[R]= Iu [ 7^9#lyw{p{ܥo߸k?"""""۫xA,߹ ~y v%!83gjb5s~@I;. wUH$&*7c)ܱ2h^Bb1b;]Ճ$FDDDDd{Pp6Avݬ' >+Ǧnjeкpϭ]UOXuX5gG;nMt.Dcsf~k$Rs$/"""""Ul@s1ĮTÞXG@k,Yubk.)b/T [wno\wݚҭ]7Z+޼Tx̝7.ݚ;7g_I@췍\u{iՃĚ5 S&77{CYvW_{ ö'$|9>Y9~5{l,>fܷcunփTu> Sk>(G{l/uwu {{pv;-h.XDDDDD7:T3ˠ Wo{5ٽnߜ4AXs>tRfjP*qP`l6=gݠmc?@9W2"""""ۓdVDŸ iզ7n>%fzS Y=f?A9£g5KWP={5"%+h?Au#(uwU[wkݰkdmfݿߍ1T +h:/""""" fΛ[7yt%ots>m1֜뷽ݿ]s {έ~ +ɕ+$aԝsnukc>W3uM]Fm\Au]A!-^(4pi/*݇5_\ 6bM1A8l~5܏u| fYg=ۏ_+us30u7p 4z̼݇{~sv6w[u#<$+""""=I&!4z͌,mk7*9@Qt05{ޯ}7WKʖH3bL7!gJ^{-ѨQe㬦-""""""<ϋ37/?:ݺULI27GD4O k)nn {άKÄ٠uf+ȽscNPf_DDDDDd;ʬCF-4YpGYWs~=Wv_5fK]I67=o^ǾWM867n}BDDDDDhմ7XIIvJۯjb~ڽl ,g\j"$7̙ۡu; )@ P o˝-/DKLF*yk5';oݠ\25W|T%$2pk/m&ܚutNmMݮs0?Z.W+nYDDDDD.*Iψ5v PM972YfPfl>;0粠f-[OՌH$BQf6n^Iff#vf|)EDDDDDK(bk}֥M姅̞7HtûѺ3y˽neϹx5C9@.9бuY7f3 us]7[3NaКm/;d쯠}TU֭8ҭK'w6;͎~ZqO>ë){X~o6\) Dmvsk\~'hlNn@.x^RXeK!Z`;êE=6}TU. p*֥#oΝc䧅i7s&`l;65WuZ,T!9cn~͛Z.,͝5{x*+],۽vPq_:i1DgFDDDDDGmvlp@6232 ;X"J^f& 5h/nyw[(s{۹S!pb,ׄ\s3Y=g.7ڵivjb_Jes~Urjw_:i1!<emCބ!V^㶈 B\pyѯ)(,{.Ngy F]:g )&'o-S`MYb͙uc;Xym]wlݚ=oa|̣yB oI1-Af1y#,z4]UrҐc8y豥㓇[EDvcqu䩇[Υdi݊U7yg5va5!ݺv^剱ws駐R'A""RޣGn垇 0k\ĬsPPXXZֵ3{g7EvYͰ]w{l~W[W[w6T3u +(畾> -\t":oN]ߔh߼=  ʽy"H+41)ӬMyoiĻzιc#^j+$J9!fl_)O]WC~D"^D9(e)#A;g! 0‚rװ!r--#ygֵo@~鵷xݲ8MxÏlќEIqq1^qÆY,"Ƥw98m 4o#ɴϾG4jnH$uQ]ՓCNn/xϽZ|8w۶e+DzDXڛr.=zt㊋{Hw{?{GϏyAun( ֽkbr ֆ Xs'Z5l]w_5C>H&̜b͙\!U8kWefhG#b"^bUBrm~4hؘŋW:,%bܓ0?_{^-H-hܨ!DmiãyӦ|`nc4yxx\=es{Fv#}5Ͽ¢"N=q4^~47B!g/3Vp߸Y?B!v҉~Ǘ|W~>{gNNn1Xn*"iό~aF?pj槅?Ks7fM%,(>^<2߀ %)!ʮ"&y+nϙyw i[2$1wq09GUfp-vOe.iim"E`=sykݎO3 xYs~冫/#-d{( /,"3HOO#==tσTyYV\]Z_GYˣEf^]}~Űs̀~9Af͙NsAl\i[Y| ;~0Vt; Z~cج9?1 uY`ݣG7|2tUyKVDYx-ʿ3v N]_tO}ndE"DJ=\Ba L7(%%'׸ CaQPruWT@?2y\e,X ,d"}ٲ~zqaddqϭ(>/K~_CxfL8f@:`_n1ςdfҧqae_qμr( q^e.bǾGosrifG\7_}9;$giϻ4b=g3c/o;ϪmTOZ!}P5ɽ/@KuCzY/WsfR/1z&<ءUs?uK.([\ ^DDjWżDXtJw܉ =kn%Y=eDjFLşőb-_Lu1s?Ng_fp9p}a]m8d>p?> nyyΉHE^ lQPXVYsr((,}.p͝BH?˄b2_t_&+'-78L+~KW-J4$4sM]9tRӢ=`SnzEQz֝/7wWv; 9/+&-|+oLdΝ_gs=|UƍW~>Kyd5i ` ٸqth Rmѯ#4iܘ-y|<{#FKAa!ꕼi&f͙˄_J""߬saĝ%U P;$&|t]:`o?k./ ןMMiNMp~X f }T4qvn5͕dJA(&-f 6sw[f͞* lq^<ƌ}1cg%WrhAX`;c{|`W+έO}ˏ}@Κl !v)HoYRwJ)Gq!SCة{Ml{bXDDDDDڶّGDff;_6pK jJB}XsҞs8sYtՍx~%9q9{@m+!?X֚6oAqQ״cƒ?+.̯.^sz3ذ#b: h܁&JZl9y7 <_q-[NdªGUdw${icmQ5h ~$޾avP&:67Ͼ{-٠! ZҾg]I_t-`oe_NTќsu7qУ[Ww?-q^A(Iu! DM`dl$h>^e5]ucm箛ojD(}k_UZ6ʥ,O.%sKDDDDD$9,[G=8ح[W5k @vvs~Z_NsxgrS P]sG+kd~Aո ~Atu`v05nh:7{ sfN/WKFQQ! Y*B/кVΥl<gVN* v v] KAZQ!x>wooYR*[LF2ov2P.جzzs?*B@ak>~̼}5Įڧ& w 4oj~sFvH=~7ό챺ԅc """""RaS6~7eoQU ůǯu=+ vMDDDDDDJ${Z8\א|An_Atk~K1)?""""""R”@n]~xDA쯥wUE֠ ~4Z~e5yHdJ>0+]2Ovꌚ>pA^v>f e}DDDDDD7|,_+j2${~8]cPlklMOAsflnO]or@{Λu*""""""sOvͬKw-nUw;1~s!xSCY;%RZ5cXmNYWwoAl|ڽ> K'鐜Hwi :)~s+"""""=sC1>_˝sz>Xu{.ݚ ٽ_^2Xn'20^7ÝkG; IDAT|V2Yk͖ ɉ;8 WBc """""R싉A䗹lv˯VԵ0$XKȭX7rKs""""""5JA7ì'tk;ޢRB {n'=Ҭ'r܉D#f@V4/}Y#DfVdMn$BQv3BV,yf,"""""WPfǦn Q91HoڕrO}2cՃNp=k|8g I[z_ϣO?O>%1;0Y͛.wO_)KbD6呷)~ ĔenԄ99mћh֞ݏ5y|i ߏ΋-yOAzKX7 ·^ʼnGʑ#?LƳapQ'qӔ5DH%x`їîx2A\hģ\ )?mChw^F>n}N!uz< ԬGy'/Loa_fԜ`G޴o])+&r(<7?{ſz5/9q5|?x?أ3aK,(Ri٭]B֗'""""""+#mW;u\cso("K>d ;ZBڎ}rfStfۑpQ&$C(Pι@k;GwQj*-;Ц7t=@(NHUKY^ oEDDDDDIP `$)0 Xq.&g ^p3^)"YĄ^pJ~!9ܺ=mKϊG^NhMK3™4mZDJ%""""""QH, #3~~hy>>[Sg _ ؉>iPȺqƐhuXDDDDD.';> +6RTYo0yV=ږԎG0h!PCN6 { 0mvīs~{׌>l؀#ԽKPn}^ȠRN f,׶p;kXLد8$ T3u{7s5;ReZcs i85zͼ7Nc3fu"""R˦}콷[5YM(tX踈_2bkEk r׽a9#Z9zHBHBHBHBHBHBHBʕܲԢ+WEDt܅ f…ԒLtED)$ p]wEDDDDD;zHBHBHBHBHBHBHBHBHBHBHBHBHT[r6q"63""""""[OGtwFl q?gG]tْ~?ne [t>EC̄K9ܻ;%%86,"""""[}26sPRHRHRHRHRHRHRHRHަl;矏Σ؝r1rz;#"Grc?I yeF9RJ~&|s '}hy),UUء'Ϣܯ}|0q!;9YE !]2OmI*_*_%NzkkܫR'ܓ>%`}C!QWxk'sH=q o4_Ǎ{ɫAՋ'y?b\Ѭc[ λH]NV(T{`ؿOOZD*^խvc)IsE%+C467#arNowO]Y'Qw*"^_{)wM18f _Ǻ/rYHzM_4O>g]͡e˿+ʾ"mPmcس7~]P ~:}1_a};Nӎ㒗a3'nu=Kテ9k;,)0sؿ^by[y<~9j^_dSxm|Q>aGMSDRɟ;9G+x|F.&GȋAGҧ N%x"7uAs-Wb<ne"X]܉Dt2gCC:@՟>ew<ϑ'qcߑZƶsLXEK8iP;A^̣3ֳ|\LVp3Cf)A)LcsU_00__9sF<MӧO?r\GJ4%GNÇ˧{?etq Jkؿ /ayx ۇǞu/,`s.ȶI!x`NәY^BL5d]5`ǽ3xwy| .n?ķ^> }_!tʃL~&\Ғnɤѧ⟙0f*8w?'q~P_U.Vy rg{)1ẛLMo=Sz{[\9}o'z֜TǺ_nÙ0Cp ;M?^WH߃G~sΣo0*#o36SǟCykśMg_RYç_yy=j=FĂof8;ya~ {0EV2>oMχ[gx|z'ԆiA )z}&ןuύ%tL3fɼpեmkK~7[o( wgP4>4h>elǁ+X+]{3|ȇoЂbx L|L*oWР)<ƛKGQ-x?;&;ޞ֌A;.^6={5+;`_v] ?im(٫W.C䴽[C}+l튘09082Yԝ+l^{!x֓?)7ܑ[gU-T /^w_u#AF3v8m@2PzXS>$K5Wܜ!;5d|9w: LT2ZvM#͑~CѳI 2t؁[&$7{## =գ٫s i>_>zis(߂.kAj"χ[]9g8q]8cϽg*ژ>ر| {euĽ:+#δs4ک &y)t8_L* ^.LIcM䷏y=9isԹChD>(^9؋aMS n ;@2RJE|vH0ϧͦp|Q@N{05gScOWD^@ hY,q '21uvۦ%|Sby) a6Os5G ٩}W:?]*]8ѮDl2[7FXXobS߯E|B߯r@(9YV!5%H5sO@J[ڷ5W=rEkZ,IӦq H$zN#z'&Lë́SB,[xgn81s/4|pP `$)0 Xqa;O,mdժbwI1;Nẽ-x~8]r\z:'@ L8I??nnLӲl2[z hE e]Vܡl>Ys ٫<1@n&k#EFrbe!Ը9lIA/=^eѴύb>{~}(s=m~W]|#Ƌ+ԘfYf"dUkDV+Y0KBMR)0a"V0X0sqƐhN#F],;Q?T7 biHk~']~'_͕AWFq@íYj]Y_ 1e"W>wj@htߴAAѰSu[Z;o᏷KUxG9}#oǗk*/4mAֆ9 ԑիXMSn"iBEl_@fNҤM2G Ҥ.N%/y׳()yjʩ^GAћ#xC8|?sבS7$"'j^ 5IK,"0_)>D6f')l7b/tǾdf ſA4rߊwnOs΅pЀ^ze /e}a10u#LkxGVgӤ .ZWJTZe;v,X K22 o}yô8/-~G_B~//+yܔNP??bv_6wgҶ.4>-_X|Vzɳe׶DrР#7 L1}׫ĶuL[aqq_iM;ҥME@FY,+C4>h^:[^.ѻ|%ܡ/Gw OMgu!xgo$DJ9 ^y_ȫ~IeT82e#@yU^)L{5n(^|_&T7 }Z̔^ǰgOIcarmc9'hX)׏YsJC 9y=)n0D}Zt#)ZAn^H#gc9kX5 E{XHrg3rD:>z1_ǘ 2sxbD2Zie痏}vnt +gSvIv0NjҊ&s,n;[o_2h˵-q_3Sa2v:cRo߹F~J=7!^ɀ!x>txquˌ} Ӥ]wz1oHiwp?NAhkJ;V^sL"f=Cƚq ]}b`v p{Nq;゚ 4A2% HY#.%R>ZSc!)8(!.8F dٍέ2ucA;?8mw/"ۄDߠT3u{7[Ng=X˰5N&ffތy'hoJDϧۮeBt>En) _!fjx8 Eo@3|GE=[c/Z3N{7sFr2HBHBHBHBHBHBHBHT[֮]DhLߋuGݢQ|-:"eZ4oݪбC$"""""1ۭCoRHRHRHRHRHRHRHRHy6_wYɧO˘#s'EDDDDD$-H<ƣ8B}Ov,JCda:١;zfZ~"CZZ !w.![xv1^bOt 9i_RBr,x)\6)33VL7<+u6vKeVn# H\eRw4\#f(rmZ~ɏW!5=<l ô{sY.e˿3!^땼]zK,p6;_.`f gK.tR-"""""PH6{7wߙE=$ (3ɿ^cւhc9XY@JH)Hïsńq|{^o|^[֣{gqlJGZfۓKx v]종*dHwƳ<6'Lex~""""""s++;GَS&f̜+ NV_ G]t+) 9' $Jxǡ<|ing{ӿE?YDX*:^(|%\W:o}""""""RBreytxLeⷛ6~[۠t,XaZܟ9Ϋ/1iA>B˾%4[ɩk(ĦyYXTҕv0w4QHDDDDDDĦ[WAj OoG#ےPYOsywg0u3hWbؘ,Iq:zD32fdqr'""""""6]I ؃>mBGӯ}H | _~´qCiKpDozv er-!z~-N3w""""""$WIvGdF᷍04-w7LF Bޟ>[/ƿȜ6/{aN*\fBR3' ࣡ 8SM:MP4.ai,s4xޭo0i|`$z9YO}""""""8)<ٚDr˥Tww.NDݜ̼ 84;ݜʎ ;Q>4Ͷ""""""wjͪ^ s);;mNeNeSٰH:o098]R[zEDDDDDD$)IS,""""""b$YDDDDDDNId;%"""""""vnTU]DakTHͅPB]utܵJDR\DDDDZ!.4ZDDDDDDNId;%"""""""vJEDDDDDD$)IS_Hd;%O8+kO)IX94m""""""Z!ku"O^ʝ#;aѬ {Nlj ߲_oP浺Ǎؽ*Q>B,mD?ʮ<+PXLJsr^ G% .4"""""""JȨ(:ۉݻTڵC3/:erʉ.?X`ك gX2 {( B4u`}hwwܭqmg㍒0wr% Y'uwO&\<ŕ%8S'x{ӣ{wN>}$ʇ~vرDmB|fyql"[ugꍚ Xߚn+FѲ<ίyHSSGT#U~} C/?lײdМsodɄT?A3g\edžp2U,"""""JIT}$Id]2Q)WeyWBobo]߳vTf݉{"ɽ}׉& 3{)Aq$'ynk_Xq`C |KiMW7ʌo| l\ﷲhcY)ZdD8Z-/zە=]3/-Ry޹:9>Bʜ̼ 84;ݜʎ ;Q>4ͶI %$8ص:YL.V+kC~{xd\vSj/ST6uN]&kCjg)IS,""""""b$YDDDDDDNId;%"""""""vJEDDDDDD$عV/Qܵ*}V]+ązEDDDDDD$)IS,""""""b$YDDDDDDNId;%O)}Gk]c׋8U6or]OUbhq]HDDDDD_CI:{bNz_V?ڸm#kH}Jg|a#ΰ """""Fga݄m9ktʸ{QJ Q5$?%"vN$5$~w-X:'H}SW1e,J)3?f+cXΕnB: +9a2_y@L֕s/*La?iV5rnqt&~<{ j+ONo8hy ujQ&ufצg@N?O~@dTD * CL2%gvvӄ Lm09| 6æf}܉a6̞UC v=改 NhT(sǭdA_ Qe(9{7}I~ aӞX۩cø9GTJwF'vJuLͲ>du3fb"!s3ʩEDDDDD ~ x{ӣ{wΡC]9t0CG;v}wX?v4᝹;8I3suXfWGx>~޷ozn/d蚙/h9S6l`QIS!ĆYI%,)aᖟػ7I qp N/d̒s2!N[s߻}˻S6&mlf&U|= H=OӇÇӷO=ʎٹ.ٷ)`M ǎV&%B ϛX>w0a<4\zޜY-=tSV|÷e")SG>)yg:ѿLTδ_hZ3?LDDDDD$$?E\e'HD"d^^c7_˅8O|+Ș>@ŃH+.c v9“8""M8<5f|3>~F uHJӶj~M&$G:чq^(![ ٷiX=QfrJx*Ct{Vo2̻rD""""""U8[.:Gsurt 7fS1w}rw;wG[0:}Vi퉈XuU5\K '+RvwۜV{90VauHarp.9.]S,""""""b$YDDDDDDNId;%"""""""vJEDDDDDD$)Iss}V'k+dqIS,""""""b$YDDDDDDNId;%"""""""vJEDDDDDD$)IS,Zzw צj/7mQ-""""",ssIĈ`2zɄ3-EKB7y?FNor]_ʅ?p|e>K)]L9]EdhY]'+\߶3c*v}SZrע Ƿ2{zCNO}9L} Vr;mxinΜp9ʃy૔͘pn;ɟ.dpȐ;йqN<]6lH>άv9ﲸG=} wfk_,P2E\e g ܥiܻ-Mˤń,}~j.Dern(JKz(OD\@>l&^HǣeW%b\J΄ z=u|=u+{CŏBеw zqMl/\ᓧ$/jϛHʒ_EPƷ͌5G`hdZӃZY([7 n1jfNL1_F߉ w\=wqm7#:,!ug&/~?~L&g1.|s +U/G^<8~`s> lǐfΛF7r(>̔0.,NɜE8=w˼yԳw;+x[&g1SDzm)\;&cgFWi6yD?-Gnr3ɓls66XEja][y}} Y\Z#e{4b4Nk`![VtnY^&L^<_qkb4 T7EѥWuftd!K!;nHRI~ uJV߀c\+Ky-peYmqLπ 2CQ)UV3igi͈V_2%(zVOt؏G& ]SQmDpа3_Ws'R$N'ݗ{[^jE]c!fl>pfS3o 9aL x}ܟ3gFeQ?K=!2J 2a㼣 LIƕ-캑4b+9ܺ=o?{1aG6Kt6".\䞟W14/cV\&{)_m7wEAr ǯS>iN\B͛ߒ-ǒJV-&sVl1\R,*{k/f+FFׄ_ HAئUl`XGs3Ӎ7g pDkVgR5rY} 5̝E~8 SPL vJ%Xu̇0l:OkFp&xPeCJXo "K\B?4W7 [^ 7ZLF2PrV征)ʼV"̀/%ۿs oPۋ96 ͫ(39xb|=.3 Q0E>hQ%z',/Bޘ"W]2ilR7xTC̟{_$&F,!sU{8. dɎ`˚ٰ(K=W4'}iqC2aM%>Xp wgQMc1:,x\nTlSݿg`+ayK!45br$i3Qhb<=w5 D?SgK}Bڐ{o?DP#D+$f\Foo:ҷ| 6Jpv_$'FT41x퉇-h팝KvTg}&mg#.s|( q#IG(@D\%sȋPQo䄛 7 IDATG˙-m6 vw3L7q*G{/*dS\<lz~-x# ق>7ɋt~N }pkO$q}BtfZ-M0F>ӺN,ٲl}3kG|co؈dTdxp jv݅$^wvaKY2á՘3;ߟz#2R1K\N_?H( `kɛg u %svLg3\6zboŁ[ފҎz7^T7}%u֍`xsq%9wsfɏh6 ^4'b;B3~.Put^+pA*^ɯG3l[~OoAYO#_z3iďH{O2HY4W F3̝q#0\,`D^b]>\$Cq3=G=έsJ_ 5N Kx%M~?yQv"iTK=#]!0P*e~_5ol1>qnLU+P| 6F\kgB$V-Cv&>.᷹S=4)|ܞ<_܉ŌrGы6N@~E_gm\*Әɔ;ss<`%gػ7z3 wJ6!v*sdg6aB͢'X>7­h=<_Yx{Cײ|6̣$]NaQL[1i+FЯYu`ҜW)sz_6̍X+a,iQ.27?E``֙x#0hb>?Ϸۗ)CTd4QQqXs;bNFFCL7DY;/?ɒ&c7r!=k^iԿ$\ص6F;囋*}2T|ʢ֝9v5xoL3yoO<ɝb{mLjށ+6,RN+8;bh:8oCe0[ w[Ȕu5 gzz?ˆoʹ/0b Xu:CdzEߙr֡ϘL=#B>lǘ{(0$ :?(qkG\h^XO)c>Ì_u5" i@)fos*ԥd2YG>2[^/b"nW|zc[wd=3A51}@f ykNmfbh;b)#'fˬx6GDݺ Hi,c7b}Et3 53 sPmR ֵQw,X"%JQd)JB70}M'cPT*[UALR)\e ;Fį|7}׬HܸuFg|@ê!WAIpђ1u=+Gp7D;lshNV/T\n5%=p<uf{VUx1aHJzj"WmN(K A/yst]ʞ|%*#b};NF%gyHI΃Y9%oa][6oحtfr~gi1QY3dTp#Z=m mtu]Xvm }:|Jdg(7筪SwYvuLYe2Ly?1WqZ|d?̬ }["\AQXdܝ[zeDVsX2!+3 \דGY6&sT?n`rp&wʶ0㇈xCm x?VZ5# KGbԋ 73y>B#hD73YSz Wn" %tEJF8EYJGۛ;k|ZA~X[ߛcIuO\Έ xByBezOjwѪ~?_ NwRظ?ƅr}ԭ]WF#.0^nÌ2荚=s.ڰIݚRTuz==돽Ȇ/:b)_>-?S4O>^?Ʉo*jL9uظs`6Z#lYVyko`QxzeWBFվa9ʐvɑoU.E ł1NSTnӈf*܂~Q:&/_E苜:& v۰=H-)-7mX/mcrվ,f~wEvahrj«ui,4lړla0B{I`y0yVݲ_5eCik۵ڵ588\;l9_O@ 8ؙ3Rk?ީ!ԯ+/c"͵BV%+$88q2k'!K2s:Nd;uf.fWnlJ7t(vݣxoMM 8:#zϥ83@:L}8yo]o] |Ӿ7g񿱖>o`xRݓc1h]&L9umCyg^<,dܘ,X9)c#9~f z^ +KmgSݺ]LX~yj ٸw4w_Ͷ_gě |Ge lrsWMv?83'3O l78{>h1'9Nb=˥qF [{۶`RuJ<≋Q9k_L> .(pu7sR)*zAAcf|iAvcYrp8_.E~dz$#RITZk5]5f46Q+Of"7g35Ӥ@@jiQkw]hwU4 %,[굆WڒaRF,^K,XkIZDf7 []^>_ٛUknQ_Y4{5 r{!sˆg-M&'SߣrW#4w V6*Lz3%/ikּ [U?Qr*B:ESx!;.dz I/Y4'oh2W[:<^x.q6FQnxy;h3QH=~Ԉ7DEL+p@HKYw4 sc4B{27k3AL`KHČHQDM^x"ym`i79yn+U._|F[&7 L2\dz$!/,KWq]\ 0bp?rӗO?m@`& av7# V:plX U,`NGlnp+z/Vc..[Hpv8>NNjbK26xyI/gAۜ.gV޾)s$U|233sfl.umH4)D>~h4 u~79B$v> ZI1yOtT<8Ch"cHml+6GODEEw|\Z͠qv H~!fԶqIx(x kQs4W'ǩeݓRe(AHNԥR۩gRO^K0hZ7*fH|#Udz$;?e2J, S rf?/ Xr>6bu NVլ';xSQ"M`ѱ;F~?vp\ycKX6a;lWsZ#{/xɺTlƜ d쟹kRfZJ%|3 l+{g$GCݦGr}: #F2H"x8I;H)6]/cz߆5g!K)ى6n9+MT챀oTze>aOw1J0D%0$2*+O>E$yQ/)]dCoN5hHYXs>yPv. *$֯u> `';HWcx&gkϨbyIۙ :|Pި>CY7'-xkHFuބřH4oG,^7&dXꜿo-]n*9_% 9_cp>ӞÉE3m/{wMOO/25feq3¹|d{LlYgD3zZL;OK6^\g̵x5ND'8g`טu򾳀cH|AփЦ:39 C>>Z ?xuF/YflYt͊{Th ߮B:@ԣx goZTac}?Mlche!-xwOӞyӠN67=ӹ~}ih# Oߌd-ʟʷuqiW3C_sTy#Rs;;]'GeNfD]OSͩ̀S>9;倻aGnf[$JӾGbI-ʮ X߰&J>TQmJfbclw Цz\šk"]nW 7g) S LJȳ<[.r-E_iIrupڮ# x!>E_bӏu'sj߂*96${ԭ? oB5 FY6M^ʲp9̆Oܫ=oV/'J "~ˇ%s T\m=}sF沥zd[3xj(I?嵳<" )O E{a|X#npd vI5=˱5nFtXB|L_;~+C=Z[FyMA~&0:tnԢǬw 00y Yhi}#2L_2d̙]y?K%w^wK1~}"{vcҸdbǀ ßP) OWO壏gs J)tj 9| Y/t[Gi #.wsw$'M|ǹ|ʾCDR:ZEX/rfhޝɗ7wo2-Mpkӥ+Qo'7gtM7y1#" ۆmն4ЁJ֠Ӗ}iҚ F0oo@AFUiG761xZƨkkwqnju^XMF㶅ۚ,l73G^=Mk}йpyViOE IDATmrU7 fޮ2HV){sWmA؁ kхFe.F vBji\m2s l[#%ӳ] u?b ld`qL6bvϻP&gBe2%эIJ#j䞁ɷo'?4]:hҾ(~>м~,Vµq#ꁕBw<(Xkt VD-zҘI{w]M+>)wy x&SBG/|$][y}} Y\Z#'=~1SuS'0QBܲ8Ly^/_ GŮi^-+>n%Vɏob<ԣKCB(uwԓ Zl!>LV ϟ|"K?te◥-逴L< |W)ޑʑvkM,&_0xe }o;-ΐi{Eq; $@hRJB/RP W"]PI*R"]@齄[ dAA?5Wͳ3쇡ދ7?OSs?umy-IKeEڳ/td|x.ʨa |k0˾ưsz5w"}y{A[js;;Ό>擡Vi|<*|#.o285,c_/"KW&<Iq }Nv|I~92yك3?nG$$al~G$oƁ{07#O3sP \>h tJ?ƉH\bH!UwLg_0 55m4#7&cMcө`ڽSٯ]8Kp!xd!G΄S~&AgBqɹcu Pk{Co^EdYvlHVEs|yuGE1ў:$ojqcwB\Ŀt=>=Ƙ)>ur-٥еFTl}.y}\LM#_nbJ#5unfvD3 {'g) gV'Ȁ_p~>v<ǰ>;'T'"7K^ [\I`B%Je0$.\0qO 10/=L|bnw+o !_LNf`csnx捖{~"\'י\H-_dU333pMH칋u쇸"fl|lǛ3'1^3Ze etz4Z>Fs ҉ J'ЇtFu{gb2rsk+7qLc_óޔGaAzǧt2|aᛞu `UXs<\gXS?F-Bh^B) a6=U.3܏ NvmiZ*װ9 ?f6Mu{:<}f 2k)No>oBrX0&O0a_}L.~cm =~,w'űf1VQ:#)P2#{OX yrڟ~^IQBKѪk3?-iup7|PQs.С\+@?qz8p8؋xd"ׇB ?()QN$bRFǝ&i۴ $=) Ī+AL.2>9L~iW1M쯙Q轼G=AU~e+SI}>VH܄?(c/#!qz}gHK>QǏ÷p6,Suj`/M;6t#Ľ$_U&v_p&2gMQ0"ʺ,+glrC-#)*^"wV?ɮ@?ެ/E!cEΦ]&} [m Ҳ#3: &opnJ4MMi#Z=̲䉙>Tދw[^dPEkZ,Ks |Fu {!:_LF_iÿP)Mܫ]yq k"Ǔ]s /^`m-(ܔ/2_O G@M>z nc|^8mKXTC: ^ENnz[e̒e#]&]F3q>$fUZ}Ta8oV{F4rGi_<WH1 mQxw5Ġ$aQgM8<s̠Bz?<s]x<³Z1<3$R1JMe#*M+ [-WɤJ@Íw _ G6;[N{5O!EE{A0{OvZmYHfn4\9o^g\fkW"""rS3{]+ t|߻9Wӳ| /_o\`nr #_MLҶ%KҏF[Š{ؕ^y c/2pC2v_t}ہaަv$}W&og:_ cR*?sN2rGjEDDDD.ӭ`qq75]$5)dž/c8}X5L_r WZ1lI,V\M?eؙ-<ۖ⤍sY͸/SKYDDDDD\8|/ZPHR仌P"6lbu݂4N6l1qR|OǞNuO75AxPpnxsXU}$q2|x>CZrUtw:qGdh|{<3tƓEDDDD 仌`sl4?vŖ4(Hx?_'}ﱼ)Z֌77%xes ̙EBdl_Nmuϳ,Dr> (veŇvmwH?߉}T%ܖp4Mpҳ#lnB !i]NQKd4K+GxEDDDDj w[~t]#VnF8i)F%OS*F@7#~b5-ۘ{3nnڋ[Q߄r+@Y4!d)X&Oǖ6OH̜-?.\zFS QޣX8a)INK}24SEDDDDu)!~׫e۞Svd0ov6[;{nm/kr^9jY[y?lKDDDDDtsnY,$8O7&'v^rk;[#enmӪ9o^g\fkW"""""""dBE!YDDDDDDĢ,""""""bQH($XEDDDDDD, """""""/ς=K""""""ςxHE!YDDDDDDĢ,""""""bQH($XEDDDDDD, """""""dB˳ X~&K*QT+oϮt0x{DDDDDD3՟~SIvW<:vF!1ټĊ7WwTxo;'{jgV<̓ٸ!{y&)j^N^*uk"bK ^m>CZ`4Ikrx;kV%!fseh`O;8i+Agbm`Y-W" "?M)doL=:tpjw3\'Ը#zԧx%~yk~Br=pLk?w$65ĸϫm&AU;B-YQ_7I77Џ"sQm3jDxءǍf}d V4浂«Kf_$cN'(BK(T1{qҌ lS0Ȉ]wu=cv*c?nԿJ>r""""""w,̖/^p .*e3-t w27 3-{͚0NHK'4ȓ?&4Ԋ4RLQtp:&+$߉BmfT 77,5yn= .l;E3\x_9O~cۯ/ NWV`""""""3 ɷ-<f2._|q$܎̤O;Qg.hq\UȚ4#mcх̶{+<;ۋӬ}fϞq*Jykv>ÿ>L@pyݨǮEDDDDDX w;!CbUjf/wJ Cv_w[/}m\[>mҾK y|9 )ۈ| }l},sF]B (lWiھdÄ)=n_DDDDDofLNWˮϻ=F[`wisk{'& sUgqq7.ʍDDDDDD*fE0g<݀sd 9'Ywuog/wVA֭Niղ73eso{.v|XBE!YDDDDDDĢ,""""""bQH($XEDDDDDD, """""""dgA|fyϒ_gAf&R4?+Ts qO" IDAT|R$+?e6xi;f1|1X N\Þ vσ J;̳l]_%]0&jP?kڙUWda)]%EDDDDD >a`BSƃr`Z,=tdq ƽM%t-朲o#=% e""""""< ɷPl\g)G1їED]ZYL屖u)m|gZ uckZ|0Ok ;v1rXoo2v$3{t3a,ֿQӿ`FoMcJ03}0S1rV\}l:DUdK($B 耩DNØ)k)㆔ރyggQ36[Ruv nH`aJ@eb1~q ٰv;Fr%`jpwNԥn,Im۵UL8wBDDDDDK_u''ţ^N&~0_<;a\9t^&dˇ@mLR\yhFȉk8/y)c]yR׌ZѢ\.JDDDDDM!vKK#](X 䃙ti`3 'v"uϐ]ھrQH-"scxGulm)V£y0.gsbxں?N2VO~'UȼdiVGtp({ `nZƨi'h]d9 |GR2ss؉ [pCL;w$ľnK 8M+°{vwgs"._7$CHTUauMSgC}G5>M$q ɄS={$"""""r[N?AOsʁfibLR\1|<s+γݏ=$x |wdtn]x0j """"""/ wÿ6u$]A/G :}5x"yK!0%ꮃ+<u;2"c;vqлV@v%!vFrP^4-Ggvqz~Np"_u(AT&j_"OTSR; wË\%ro'8 atBbiG>{;HMs|;[DDDDD/| yrT0=Z2td\̲ޔ|!gϾ7#$Odփ4 f[ڴj0/b}<2m`&K*Jlu/o,eW5mMWs61}ހ|Isfprpo,SSzly%EDDDD䎠| DG{rt%LQVs 01&h90w99:a]^ҋn¯=ж|4Їi:y53>HyA6oL^!WͅZۈw\ũ-8gy:Dy+ҬQ8sQNe LXĤ{VyԸGZȝo$.ÿ6nm'˞ci؟CL6M\9= %P*?,S3ޟt/G`vkegf 6'eXY j9[kՙw&z("""""WRH+AT\:ee\gd0Ϟd *6w=%ͳKZ:WCxf4 I9Ndaνo=мϮN qoq2-u{is8.'؀9CEmrv)%p6{˭tk;ڦU˾ےy){sY]E$XEDDDDDD, """""""dBE!YDDDDDDĢ,""""""bQH($X< 4{DDDDDD< A#"""""""dBE!YDDDDDDĢ,""""""bQH($XEDDDDDD, w:1V~KS=-YZfd6| -T jS:Ďs GRg]=.""""""Bf{XFnr91M{pU9Nӳo Q1 """"""2;wf3U<^;v&% VʞͩondyѰyJ>sҡ_iNdTf4*jtNlXʒxTqeGDDDDDDb w;R>S))d$e7p!!k:1$!Gz&_y{@\tav郇Sox${FvàL%Cn3La]."""""B-YQLtg 20g 6bךqиy-yMRy~T贷xמ2\xac羀|Y<āe;HhR?wZæFlӖv6\Nɦ|Ⱦ&uM +7k`gBimv^ 6\o* JNd߅)*ʰV5r_Bߐ>SDN`y> ^؇H Ãq]N J5{^o_1|;y6#ܕ\ l%G됻`:O6CbK$l<[- I{ub3'6Bߐ=yJgQpw{<<(GF/J;Q7#L?GFIŞ{n*($Xo7#Fl1Ϻ^Yly6 ޘw?OҭXG nK !xճ*""""""?"""""""dN;L[Y[B#"""""""dBE!YDDDDDDĢ,""""""bQH+nvϒ_ ³ 4,""""""bQH($XEDDDDDD, """""""dBE!,ߌB]/]?Lfusz.($N6nű?0z<~;c^z`-ObVlWξs>]ظ>v`DlLWl"}#BCJ@eu .yPN 1er_9v/eD̐HW\孚7?]\-EFEDDDDDJJj*^z7;w&*b6mL1eJc]!iF+Ρֳ>>zb6>U+Q?ޟäٽ6dD׺ӫS)S2|6/L/c:&w}0o""""""wn_Νէ6m\̦Mէov̶mۈjrg-OR6.[Wh{)YBmlOSNyfwGh&2m^quط̎wpl8&n20^^a~9.NļT%6LIqU$"""""rRH/EEUGܣ{w*}t{Uk8 qXA:UVRٴl (D՘Pfj?QB~FPqZ? ;pUNj`3-VG±l:tm gU ٯ'B3({cD Y7|)[Ҡ ~+Rk1i)VFzj~\}WIFz i~G 0 32HK|^n_.B(;(wу=zŻR%*^RR3ToX ٰEJ򲑯h8>sݞ`ɱmH&E Y4.d;\vO8s?.iqݹKDDDDDt["*2}z<ZVjU[*Gڥ|4YЇGb(gJEJmJYӘz_*X ㋽U-,7Լ00B%Fo]@0rUvË2+blfOIGd}?rP:O1m&f$A;>ޖ2UQ>ڞ:GXxs^O}8-^>@pg;SG0pa–?(C>⩗Z ~zs۶nfI|Tv9?\8cg8/O;4T )\ع}upF %7l޺[c˯|0I^ї7'8~%Lkth xK Xl"fm*RYJʬMֱںoWs=w;ƿ۪|O,ҜSb :o ;nbGu[.5 eqXWnKbY?3n'ؙkləHօ ֱqo=>I7_\I<7E7*lMp7|4g6_7L~K&{ޫU\OpY}GUmmg&$Hfł"U@D슢^˵bzE}(*bWD( (XDjlϔdR ys^k33gLb֨p駢Ek__C<?c9cĤ1ܞ8q"`q>- i.0랂/AapUSp9u/.O>8r o |\yy F\s6:z : O\Wx0{5gv;uǙCgZL&V~.tCGaN-L|H}d/]"yW1:]6'6kH_t< =:գ N9+z{-^ZեǪ)[էqx$iq s0}t===NHŶۊ28H߱uG5@.~5\ݮK?Wۙdԋ[!?+ ;nԯV^^1 0gIPE6ھYȇ^gX ]<sf}M/|u:+NŚiyt{i~@9w!'Q&T۸[a7=oyvo>5~ҰiF$u.K[G GeX-YT:|򁱯Em^Rs!!go57^BOƉ0Ux{1H|iH_7>\S;u6L 1 ~ `cQM?@.5!ǶyOw#ջUOq6L}jecؿGs y{o;~m&lcoנeT* BC '} w~H9 6!csya΀۱Ii/~og>{jg*dT7=J%N]1uA\dcIxu6p,^~ jqtq#` IDATmqTmX6ͻ4;NKLYkk jb~xR 7᡼pw>N[GDM8ػ9_yݟD4 g6OgVcCVhl*qhq5}vNtϙ)zך^ZۛTbV8l  `Kodž/ ?GE_aez! U2FQqD4?/_~:.f\qZZ% }k.iܕwv'~^Tk}=84sMq9dzQp^h}.nw6/܄Ͷ`ƬP&_4 ޻, {9g;k .h]pc/v?MWe~AGT:8E⪧E>ѥz[?G\Om^ :adTL{4:TѴ-jRq}a_0x}p_;ցx|ndz⺎C\~Ybv2D$'S$$2?ہT<<&Wzmˆp{h<40gr"}ěUx>.zz):6N,"?tls,>3 /]+Ht~ѓ/iR܃] @FTACw2##x 5N]xG[ |ؽk7:ﮃi[h;G6{m{&6N ݻvCeK/Y. n ? -8ؙOÊ\M~?\,\O=R6=_3=KQsdԭWqW9θJ;|&oHWޤd$fdeeIՑ,"]0+׷|$%#ɓ7F7 5݇&"1Hqp?3#08Rd7}n }*U!ؿk<~(yg}=DTsλt¿wg`1g?v<.mز{륡"oٌz_Q(_ HoYʁزՏ:)~J6o?W؊MZ?ޚH# `Xx6(zroEUV3qpŠe/mn|C#U7e ><7`j~".?.Ɗ.#_}j5L-b~8ÌZb]ѰZ/_|h,,HD"?m]Y+47Vի֡Vcp sqEdl5_^͍Z_ҍXڵ:w/R^#Fa׳cpcw}^''o5vbċ>?êMYl@-_~I χ惮D1ovoұakoX_ؑ 77|B?Gcؕg/;Gc+PO_KIgBδ |m6mX{>^_^S Z|6Z5ZYev!;&`y~՘7!>Ƹ/^}=iY?wvUQw6{ÜMgK7> o 荶܀LL_У=]|~l$y/1CZx̬,<_g m1xp\b6233?5F#xgf"33 YyžcIDۘt0;&?.X v4] OM\4|(~~|Z Rm(0W7g"U ?LpɨQzY\NCMv9^~Ly~؋g_=KzLD~OaC]"кw{Bt};rSƠǟ-||8OaKu/݁.E~ixP=x}H#{݌훣['R6<OqALy?tF]F݈>/摽1kqoL?&u 93rQƸ艇ȫ_7 u o`+>?罎'c_/upF8 CwHwRЮ]yM:C8j"f |[CMxُz?+Fcu0yx l/NXyquς_ H8#<F<030M_vttܕ :˱S굌=|b817@51 nrlf^/cifcހz\̒KK˶*1rmw,@&C[ qᗖ/lԯgP]t^:/؁›D^Gt5 IGC8^LDDDDDًEM;(N 5Rίo64\ y>&[|Y)A9W{ЬW2w܄#N }͈`H$-bƂL8pi\68:ngwYcK~|H=$EΙo,]k6'NX2qֶS|aۑ]0t{*nhbf>vm8&H.ΗA ',xkn$Ζ pb.N@o7!y' h&: nm ~t/R:ݻ7AM/a-V܆v͐r &c³+ж m'&/B yX5u2x\ Vǻs86b#.RvcżXj5j}aI~^%syOmV'Z@DDDDD~_)f\on,s/)Ԃ~lZ0.^/߻c@֯K0oU|>m>WGǠZ!i㧡F8~4sN\OV?PkБ{L?^TsO|/+Ǥq'' Y4>Nٟ:kOEc뛰x." NH>%~)LXj@N&q&xrt[zANf.Р7qNN*|DDDDDtcH%KUE auv :)ዏֳaʁ밧וxnh^ 1o֏[{RNނ ;v ߈p;!88p6 7t /܆~ݗ~ަWZ꾇Q' f߃O..!P3.r6؇1Wbpr2khgM< w~]_Og Û#NB58dv-XwOWOF:9^{>y7>4 &G[804vmp42!!9F:|.ڀߊ3 s78rz ]6sVe|18π:Zwl-_/ /?H(S= nz<{ƒ5AOd$zx_=ǭ=P3~%] _HySjvs!zO) ) r[8yxj7;>s0s:=~""""":40$W0g"&݆oi]ۙt#xsWᦖ>J x Bߒ1kTTЇo?˟ޠWZy!Ǧ?# 7lEbM?C\d q~2@U {aN.rrvlX,%DՁe0Ӈ1XFn1p&̼1<7{CZ2%J+L0Ѩy;ycK1㫋pVc x|ѻxkg]T??w]= HNwZo۸#z0/OFX:e9k\w;G$t ',K/T4L xuHN9kTϟX8m4 yfpprILlO݃;kagGa\~8- """"J*R |zEq~}Yoa 1㑶{|0aVwJ p=Wtz%0O]F?5gne=j`ݧWy}qR(C>0 `+?ߵyBkXcg`?Y8wiôUѫO{T;|<9f5؎oO;]qd?Ƹ?ǥFz1|DDDDDT)DUm[Xf2Wl^<.ɱy]Gŀ٘7.O_EDDDDDT.!>뙨I=N|~yj.Ǧsp*d~1w5sO͐s3";DDDDDDDA DDDDDDDA DDDDDDDA DDDDDDDA DDDDDDDA DDDDDDDA DDDDDDDA DDDDDDDA DDDDDDDAq@es.@ $1$1$1$1$1$1$1$1$1$1$1$1$1$`l]&""""":XDGI*j| .O/߯[DDDDDDD$2) aԊ&u$"""""&"""""" bH&"""""" bH&"""""" bH&"""""" bH&"""""" bH&"""""" bH&"""""" bH&"""""" bH&"""""" bH&"""""" bH汾?-@6`\6w~ysg6Cl ^9r1qN8GDDDDD ɡ8'PzxrEU`3G0n-u """""*_T+ΞQ/"99 3;K==Ӿ;:nĢJ׃*8] -'_y MWzOa jd,ώ߯hoƝګ?BBAx!߮x?bېw8N^m;O^ o?Õht,_ŧ\6>yq|L}D>sihu<,̝9&o,E.xhxӛ4L|o>I8#5ŝWs7_dxӿ?/>ޛ^=~-:|C&9cz1܇텃l,._>a&ΙWmm!c:H3OWcD1oy~6DDDDDD1Ðh4n\xfrd:H_4˚=Go iߧ} ]/VS`fb]qXWwkxxQAW}oGL{QIk4Ì;Kplm/<1pر`>RwokqU -vXO E~o3w_}5Ni_B 7MCBSYXr, O~1lg!"""""qkGm6¹wW?ÿ< dLR <^މؔ"^F>/^ySEjix@ P',?l9 *-][#};=}{d 'C ?2Un܆E1:Xsr蔅|&vIA˴hCx\c&>xkI7Ai8q 1/Rw)Ogh@Rԩ vG Ȩ; Þ}EWQй*&2 ZeFyq1, 7X=lt [oht4Z) 'E=nTd'lm >V Pnsn< [sǽr<IDAT;ۼ7j#&]Ydnm^=ķlg!#`!3 'v=3Ŭ9p}+$;ؽd<yf:/"""""(7q∽a7Bx&݌szBagMk;CgKUc)oxX, yG49HQBNwի/u%= ]qc==z%/.~qn zw$G֖Đ3й{\=r>81=o88k?&퇞}/Zuh[_'v}zDDDDDT/1x-lj.r7ԽO=PQq[WSjR3vCr)ny3?pl`sQ;c؄nr{F";n/j lo??KkgYqt6ApSr`{-&To~ xg?QSiЙI'%ԺP QBr d7mUe:#[ꕻnm9tM1>N:GE3$1Q!9RѼpEQfs""""""**7zm8Ѭ-3e#}nl6oDDDDDD:g*gfյHE-NRP[=ԛCDDT][mG^^nQV- f2In W?EH6ƄP_V 57 73;n"""t֮Y 72Uyynޢ4L> SfK@5HE}{"C]|oGDDTmݶ]ٶ}.Lf 셫r{Va**$GzBx(6uۘ*sJ&S;rVBHTEH -/뵶:RkP?MKtf9K܎u;OIvP5]sC_T7 'pLDDtP8Y3)$" i>Q=2S>n_‡ۛq$JnaƑu UB킹]\Y˾mmDDDDDDUJnJ%N* ȹ/~ffoƁfƶ!"""""M]3^ܔWH/0m,z/;nDDDDDD}0c7lk8y( T%3[ODDDDDDJ:?a[knrS!Y^hc{ۛ" ?"`ƺODDDDDDųQnYJroy$DYdƒ?S,Sןw5/"""""AANrɈ` .s9N2}EEH.z/4cmCDDDDDTɜ$3Lej'fjBYp/Zs뱙ͭ{n2zcB&\2$k^ȹr.Nyͦ!"""""¬$󓹹(sHfrKnuh/qP8<7żi|C@}Op3u3G/kyn5"""""*{kztMfE.{򮭞ː+Y* b [6v;̕eHv`lnuͬ߃7I\uqw, [ ֙ 1ͦ뱮nJ'""""6m{ɚ7y'Z:u'G4[MrK,Cr4 4Mm=G(zV fl@s( & ˚ 9<ހ€ 35sK:8ɚODDDDDs&j&&ʱ䗀:,k<}<60u b,s3{]3mlODDDDTU鼡ɾXMV&æ-k>jmzrskuX=e,7S7Xhn*l8,uš7̈́J]PXCE?vMO>L7 5yƆٸՉt&%ncP\&:ʚljn8}^Ye왾뾩G"u1Q!ٍ|&ؙ zNp.nMݬw=uή|.%wyL0ه5wes_$ǕJBr8(̋5u}р=Opop 5M86(< `=u5[MXhElD3BܶFlm,m :\sG SiZȐ0ⱌeO^nc,C3>웱 k5mYL]XƆFDDDDDðe=sc¨zn05eMnCmzzlCÚ8X}M(5@f Pl;{Q&8`+y 8uc|GF\Qѹ$ұ.g;Ste_[3Ycz2L@Fpͬ5íSb؃dz d.{PV_36we85 y~ '73!O>/ODDDDDٲfn2$kor6|eMm==d7c㚹6w{zncBxh35܌u ` AYLp `{ssٜ_Ү{D0u erl6FDDDDDә ތe]Z}GWo&"XW1#f Ykfȹ^#je"BY+/OFm5[ύoQk웱jNmk°웹VU*DEdNmL_^4ynx #1]e琛d[F>^f-QU3E(nkeݶwT]]75d# n5(Zu3E[bV7lO &r U5f[M-\]euV'""""l!Ѷ(1:xKZmuF'zlwG$ CX$.TM>mԲI .+f[MiDDDDDZ}3{Cݓʚm&랞˚z왚W :ȅ)7L_=ӗT~ZZ]kfsqE*9"Pkem^rlun5aێ1lp5[*$;O[Su2 9cYj,YmP{ɭnNDDDDD{ns]Bm5pu=s7luUwayAQ}X7s8ɱ 7cY=Sc[M~N훱&rm˚֯0SD[sw;.ڞq[O^ ] 7(6…:7O^t?\6s}L=Y}96zQu uP=m5={zY}=gjfo{\N >ڹ*IV'""""-麞i=IHוXyh룝KƶVݔ8"""""*pD;t/y8e>j}X׵ps&y8tUNHz}s&B)%R+Njv=`?F4F{ pTGDDDDDPv>[]ƶF‰hחOA.1zҊM-%""""/\^շl5ۺHk{=hv}TT(q]oMVsjm:""""":4DC lkm5 z8R;FI`I1܎U=CDDDDDUC4A01G$ǖRȐ ,<)n=:GDDDDDN`@^$Jr|IJJzz@DDDDDD.HDe ry9V wp} 5F4k&,F6ܚpH<96&*[P+)ͱZt(!""""yHF.9WiJJsl(ў7nbu"""""b=O#U2QXi[iDi4ѡ44FQbcuHSٞ~>zXLL)V5V牥U󔩃--L*Ȗyc` eDDDDDDAYײ> a^Cy=QY(Z^S&WQHZQsr2>'"""""*cϩԪZhj(@lk@DDDDD$U@lÀJtx 2a.MDDDDD%KDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD۵E",IENDB`kraft-1.1/manual/images/en/catalog_standard.png000066400000000000000000001304011450127457600216200ustar00rootroot00000000000000PNG  IHDR% pHYs+ IDATx^wx^I5!T"U;^{k.z)*"^$ 4ғn}f~$@$p>MW))OKM;.Eܛ5V^d2Oҕet۬ސ:jXOͭ4dwv.yK[*Cobt4zMOg'tn{zrD$ny.W{y{OD*3vò&jj8'ϖ-_HM )+rU_?fkDbw[S߭τnXd-2}7~`5a}nygHo{뵒w?{tܧhXֽ־_L+_(w_od!d8^m$KEk+|N6]ɜۓsI:$L/eBˑA'!]x'!]x'!]x'!]x'!]x'!]x'!]x'!]x'!]x̽pq\ǎX_jb8\>]?~<"2"80}eGsr;wv_sQRW_hqAUh>]+HWtIHWtIHWtI&]wi{uJ](߽V˭˼;~)Gdn)]I+{OsWKgZЦ$֔ 1x)CF+Ċ&wQoz%&H_={o?fu4BDi]w2f'5|C;"̒+4zuzqށ6_ 3jS⣇Jw;NϤ`on~UWξ[q;KXa5{CDD$|9t[R_LU7mYǯHض[wƲury'KD_L:v~ڱ6+?;[&<½eN"1#]z!#n,ؒ"b~I8C5ݔU 銘f#ώVrڔ۟!K&Fz5d'E[Jib/+<)oy ]eM󮈈c=1mܣ5Yk;WLk ""vD_/ڐVnxVWlQN k7Xm@hi}}Un(6pikj$2v^?@}dٻ#4gK o=̯Ec[g^ة4 UU<` .wm o:xhu C<u9o^lDKIvNKvߘ*Fo t]_˷$ sKZlFDD‰ و~,,J2g/w *wxa|p=c{Ŭ'&itrwal¨Gwo4Cnӵ}cDD\حogVRGm G)ykk:Ľ ٖm{'%W|42mtIHWtIHWtIHWt٧+VSZZ^TѺW .oEќzK Zm\l,]\z}hWG '!]x'!]x'!]x'!]x'!]x'!]x' DDTmsM u "ϾFW׉kkD&)Fg Y]ݫ+i)62h 556ArQk .'!]x'!]x'!]x't%.zpuV:@#Wn`ýrx{̝VF˿3!k}s+fN MIY0vp%W$oxg1&Sz 鱧~O<,w+_}ڌ?-usjnDwvovēKczYEmNW|'~9Iȹݛ>2bܯ}3bYYB2z<{ĺW? q>Y4Yj$+{qܴRʽBzDI"!sW>ǛCԯuVQc#8y""GѦ9}*ZwI-V4qWn>^ |pUoɩ|&Gz3pѣ/ҽfYh{&zoWXm[rMVѧ$˺^`3}J7{7_w'3az建7\L[*uKl܏|Hq܅C77ߧT/ޜQbSy쳏'F3SO/]h? bCCmxj44ޒuξrⴝ'-۽-TETd4z֔W_&+t2ecK˭\N\3nck]U0+lUs0yYoI0XI8÷$۰n{|J0ԠdoErn[KN̰!_|gtE|2Gg6|{_. э߰/6 /5 5o '}}zhfDD\o1~G;#ybuCů ]]=u?a[vÿ7J\7?m#yOםvE{wɶ|#{S8jQiZحo7޾~Pqdߞ6}<&n ߸FE{w4.wX^#ɶbYF(pݽ'+;K|{ZU93 _@o8#'uƔ*degO>b^}WpM x-OD@3mV;\Ċ?<>{72sq7[܋>q7~F*)v{jA< < < VVV<$'Xa_O~tҽؠt!:ڽrF< < < < t%o?4KK@8韯8t_e.|5]H䍛Sk.}(8yˆ%_w$oJ8믉{lBg9Il.:}얮*_ 9?/^Ȼ/l6+lعĔ}vYrrRqH?/KqmnAG<.N1")|zWUd8*Hvum1$M|hxdʶ] #2tw??;PM̨J""rV^zW^:($O$oߝYPiD5Oܵ_/Ls۳v1 /M^~+md {%"WN_Ywti_߷m5[ ""jmuo wX4o=sOms6'J^A旦^@o wU#%9},ٸg[Z:iԃWLkhuϬ, mֆ}ۿ{S_o'"zJ?EɁTKvH ?3&&OCԹ_Yd >ws꼵~яzw=:%雷r}?+5V+nӷݙ _8ޖrY& ޿ꗥ(d4.y52IښZg438n`ac& 4Wv '\ &Y,wBzMAZ]c ^tCoplϾJI˲~{LZ5f DD0yXna؞^=!'Sޙ"N.=WͷO~ʓ+`Cҋ2r; $rϝ/N_vDٽ[P+r҆A"gj{^8kᛯ~͙CagO)lwxn>1?7OkׯsvX}X _GDYa+:o:ﳻ"9IoR|d_jDze.圡f]1/ 3XLjH5h; Pk.GKb3ϼ{L:o"ǿ;z jޒMΧҷ58oł>gĞ!{Sd|ugv֜E2\]G|?K+Oj5 l'WFz-[?0% U+FK0ЁtI ļnv{5$+OB$+OB$+Oodؗܯo_jE,ýp v/< < < :eJbbVTe4⃓~m\qI'hvn:idaV* bD&ܕ})dDLнz1"r ; }|ڔ . H(VjsDN{K'xئ5,^c@¼kݒeRH1 hdZI~K.Qbd5E~=ce\@TB0JDDBqzd}4sThvh:2xZbbӦ5p_"m|^-^^']DacD}rn%rZ%""*pyϊLʽ?$&&5ZJ&g=} M1ELFD̟_ oϾ#^鶕&O=ԛϙvh_XֽF4am?)SEԬv+˃Whab5HWtIHWtIHWtIHWtI;m.us/ryvE{ +OB$+OB$+OB$+OBD_%z6~,YQO!:]]|]\^%"+֫ʚ:!%>2( Z/**,(_u·Ӫg^,l@/ ;9#|^ p/ ~1:]r:ݫDDR)Qt_p7& Xfrʶ,;r$Dqq_ͻR+N52@˓\YM4_t;G>TVmزBDQ=]=P\6׆#G1zd?)?} [>9^>Ū~}\|h}͛ܛS>>/vtkuh#VN=NެAJVgz0"""Q""b2j;OXX^ڼMMLWmy.YA b[LdA~Akjt Q^;>t} m5t)ʏտzY$_,Kppߞ,V㓞xt9:GNIDw6y"-.p0מV5 ּ$f؀^޷[GpQ؛SiˮW:NCT:moHDD{=ڼOP~捓xC2K3ygbd?df96"U Fǜ5DDBf9QO%3DDM;lFwƆRq3*PA$],h)}ٌ Ps:*ڎz0ӛqIqڧL/aP2{Ҩ/>>:eJӀzޤ9ula5JL>T*kkDRŘa/Q͟ QHynsbM5K Aŵ눈ܿ.N[fZf7]ˑ&{KZ9,ԉ{fSc.yҽAouk{Հ]b_P~RIL#:{ԉ)EHuN=IZΪNF3XG_`8Ƌ鵫lڗ30:3HA↝5;?npm e IV;ϛ$EG+" [6FZ91rJ_e]"AP+<$kѺՂU.jPǔ=s 6LF$YCғ銈N4`Vgwhъf $$3ftFV$I =7oJ"NFtjĨu]v!K*ǚ"Ir9XwmQԺ(DՎ.LMtA}KU.3qQܞ4[UpPlZi$|Nk~A &N7-_hRXJ{QSRiuӺK8d9U2f5 Z9z a‚]:"VTo }Y&*t$}NKGSKqιtEDb m܀hEJ#*g0bq NORU SZ=){)UP>"9 /GsQfP;8Xn.6$:ۊWKy"VY̌L\ADY ].wI54ʪ}ە4'B"#QbjXjmҩJD ʹIUbe1?%ׯwGSQpF I8tE{w ^s;J$ILU U DDVsqDy,HUmyxq\t^>{js#i%v4I6gg~!U:֔ (DSwm,9WD-B3Ċa D׼]11jX ׈NȽ3AI6gw縷EW$j36U/IU w. kԩDimVD1NR7`)U.Alr2M w?2m$NzũE tz}Iqh%Ǽw4p !M}n6yҌ1&Mђ(6vT 6 L)ۺ߼x8T[,1"Wh锣tE=ErHfSIaݵ:ü:~jZ͵duY4CCe?i6grCd*ΏQətf/erųB"Nl`CM7hvH1O~\%0<9 LhED,lv96Wn%b2q G$_ٯչ$X;ZHt/uV'#x=H:XEi&xs2"qQ޼mūIa5K3%N.'υy~+DdT W]eX`jfAsUIzv$AT՝:uڵ{/sInc-Ѿ2PJۆ +H}aaYlopY:$e1M>9'LNS8SeS4O2Wٿˑ?{S;V D~[ZL%,ڿ>A=]={ 9j{y{rIg\< < < <}_"^{ܿ<ؽDD,+OB$+OB$+OB$+OB0]ƃi6ɽZXnY]x8e[M۞*\Dkܼvs@%w-1NU"|jqOe5GjF 1Wx@=#eέ*:nL U7;Zbݱ?*ec,sOHb:0YOJ~qOU19VpBmm*jCdoVzda˨@]b}nىVJh%|S$L%ǎ!#BtDDUfWYl CZd+\_lj8Mpn%:Rp^Wj""ѱ[DV]WVQ:WÑG$%ULh`\Å9a>Jlw7pBu'}:F72F^WQ*x r^s5.Wk|է[_hyU+J165j] % FcjA4>>+tE戈lG*}j͇Nt),'Od-N&H 2饅6@Zp͖jBc\$'"#4u\qD$Ry(JDMrT!]'VV)*4]O-tVȽ2x1""Zؕةcs*D'N&gYlߧc_/%-M/־dRH Z@:Vfgfearj!tSJ좌jQZ)1vUʃG=x5l겊FGy{鮂,EsEukg- O i@b+ !Z"QRSRsX%9ek I]TyUyN:GrD$pՋ U*N(:0($Wݥ8kXo̵UDĂ'j9"I#a'P2–[e p]DsiP_PYnӆ3 BQd$PZhhP`5يwQegMu+\,]׽De)y$4T;uzr !&{ōW'1uVunHSg2CkSxJVމz);h2,պVa֣VA`PTr(?Xa tV#"R+ ]d:q8'"o)fhH=Zk (ڊzeVSmSg|LymH<'P06ӧĺ'+mT%\@&爸@^Vu4eD ջ-M5M4..1κ1޷WD_+H,JvMw:F Nq|\GItEGQ.n{3ǁ|4[=5]d3WW5ɔ<]N$ddrjS tv!"˕. CAwT' }ťʀ^ze ~\qIX*`dsoqJ hV\f}{Pr]+f)[|4S"Ɨ8x剌J.%Ű oTO|sb+(:&]DDL)N)3z_S˕d얊b\I6] "⼢ʲA""A8\DdD)Z-'IrEp_Ye+ DzmNIr :lKD$Y+%vj8MFKHr̥ENoٕ s]I{B ==Hݩ37%ɽtJv*]SR3VSvtJ;1]YٜS(:z\TTș*$qJ_]9 UNSsOm/0qoH6RénݛwH!+>Z1q~S!!*620{E~r^Ex^m"UxNg]z r.XwSYQ׷2.~1-,);tx%q2}}\ũyC}Z Ip$[bWbحpܿ]Yqh$.(qtyU$KIfjF~M NסG #rT9rk:%&.ICRM托 H; [ћoVΕ1rxVrWۓ}M{Nggc#tepM:\JCQ rg=;eyNou^/+/u]e /q?L}q.`wd}G SZ]`خ}G4([+GŚ~#Rtp[r>!Rό۰5;huq!a>FҍcԡsF\)/;dL߇d-I?upIJNv P`.8UXY>1t8Vv IDAT\'R:=[^/<+*ה>u36+:X2kF˳Ss+-" MbD􎒺E:F|YrT֕7\x=MDJS^u]9*w]v؊o/Y&ԙL)##.TqQgڵ{;u1ʫޫV,tr95]jIm'qmb=I;P)i2:NWDͧyozz"`T%<Iuպ"hdqbbRͳVY ɩ6/"AS\m֭vE)pWzS-|ԤҲy-SX=lIy)(91Sa'sJdw$$\ih>/m]I]JcI85z9:0>1M1Ta3 _LĔ&S.MsݳhԌ-fNID4*)53=t6jD"Q_Pill ϕ; K]Sr`ivbZ}1[*L.O%9tEw[icH[KKrn #SX*\yʰF$kV==PW3KK2KK~8PRюS=%.r֫䵡kbnӒ1?e*(&o#""RhDlf}tMKoQƾ٭'I_ZE|.ͯxܭdCo޶ʃTuDO-t뉈ҁ6)ofEn u\>j{Ŝ$'’pA}},N$"e^\&V%i2ܼayr&tH٘,ے𕞛댪 +_u+=<=[M. vVqi)>|ngܲI-pe+ipoX۹30-GSf*ՌiD.2պUoO&+969lUDv"-%O;%MMe"tM j 'ӦR;[![q"lnp*}\f4 Dd(6¡9ݨC1U[dtՓ?U/9^dl֊x='͒H"JFSBޢ *yuʔ1Qk=N3uT+"ɕ%fV20')WZ -dϝ=j$+l,Q+ALbRPf8'"SJj1BETfd< ͯ9W(dNc}w';TdH7#y`Vztr"f#">(oɘ\fJUyF-*2ɡ摱{1V[3b*NW,贎|zFX6'UNŠfDiYMڵjҖ{wO&gz=g#u|߆ 7WoSXz~ Jsf}3B%8ţ$CcLT%EwJqC v]~QxV(J\JWH\LP]w˦9KL㶗tԽj3B=6iٴ߲p:99]:X2 K`*l Dߧi+ Yf4:,1L$%7B\ngbx2$)1^S]b”0ëYLTLDNDQ)JpSQ L9ӱDŒF'{cH]e"tD:jdύxs)N$9-8CNG{zL'Ss))M9EPd8y:5 &QQZ(5Uf=VE*˘*wW~qh˶q)D =7}z)T*FwI! 5h*:)/a4^ƤHחPc*ߤR(*G/ϭt͚}W5.b˄8*sQ96lSD Qq/JB٬M"9d\8Is[!j%@[GJ"AmmدfC#MQNLe3;MtǩHBiK4NkvfX"EL6w9XʾĦCS⧟gV]w-^SY;' 4WXZk?sphWad>ٰYh<LKLV a%;L9TY{LŦ"}WلtMHWلtMHWلtMHWٴwᕙ%%Y "]d@6!]d@6!]d@6!]d@6!]dCk>3ॗ<^Sr=ά{d]% hwgP IHL[rkEkqUh`O<38hhS ۟_^>VAEǷn]Xٻ;݂ڱZ!M|$Txk88bJCNq S,O3SQ[Ud^~X{co*&Ak/xύN?x6Vy.>Xpl=JXmnqy=۪PLcD2+l+Dyv}hWsѨ.jLB6'?D*HvMpVڑ-#S[U3?3""-WODʭv"QNKӕ,6׬Hk1k``,ظ h:IWAc5GD$OzlSH.ϩTuL窨-W6 ǹ^mf];XKWW3KK9ﶜh2M^}8leDѡI̧/^=.\ߤT_ otӧs/\ywYV8Yj/T̅7.8\k7ε{U@Klm$Ih5O i+ c23xtqq!jjdpO5 ݵev#2;[춅g9)8wjlBbug];9;D4;󛷻bk,i("yʷ. DpoW?#ض< QxWG6J.t ld!``]^q`-*wD"2#$9Ha`_Yl%At/}Df̫~cVܹn覲}G;;)I_e?q|TZ0m^j]tW) Dj˦ "(']l;R))OpR1"Jd,e(a(Ŧ ۊv'R ^->zPCr4ݛggM!cV5Ont ciXjNJom "3RDtsa\8 Ena~ӵ#J>\fZFC"x\_8[(.gq]J/t҉ٳT[o< R!ӽxtڣ\T_ccuZƌe*#9~LtuzLYL1Jxqk+[q[-jIV)n߹hzKcCHV՚OlusKn6>ƕ]Fv$:FSGQr.V}QA$yx[Dl]ϋ#s. 97>g\bJkdrs-,=jTvw>$jМ9=Y|`\RSYt6JФtK+m%UC'G&w2n(uvLDrl^;X*bc-^ҥPL9Sx~ZP\. ȍΉXddz&|5EGz+Hs|]51D26["QznxhB_)Lh~Ko "SXJ^Zh dtl'Y ڑ [abZNM$"wc1J"h/57(M~xGG[GxV{Wl1caYn#IɲLxr1k $IҜ&D A#c(Ăc4'DOjØ2\;ȞwEDjW{{;w^PL|[f*j;ZbBmS{H *|.Ӳ.inmnfDp-V6/6T* "-BDDZ)J/J>mwArh屽+%&:MGS$}gFȵt;)زektjU7ˇ]<1(VWtdkT"QmʫUr,45Wp*L(OŜc}$)Ķ|D2{ b=o9XwT֕7\x=MDJS^u]Ň צRΚWgҹ@D*JnwM™5NO?eϬ.R_˳ﻏG{Ξ >:R{!¡#DnG8i*/v#Ze"b$ UśBctk<6<φxWlyXfzߘ[h I*5C+SY,=<19qyB{eQjOwR#z90ȯ9f6ymqxs13ƈHe._S2]CRzz+3J͓ Έٶ]3I+Ԏ7Oq*3{C3siչjTh(J8{,twLM'CWjr\^J t2dk9& VKm|"*mmf]Fퟚl)\%qQlڅ`sí%RV D{pbiɿg@$X*Wffg:25s)ْtk36IG=oq6l-N:l+%tDD$Z3I>F& eO5 ƈb^Mii$"9m_Rs7گOY:t1UK8m7XƕQ(gۆBJ0<2D<18-nBpQZH%dq -[3F⓴dB&EuatF S<_p"(JSNDB.LkRIC_o# $4cO>{a;3KK S[f&Sm-2z5irXjL61]AӕHpTdxbpN]47ϗ20 Drs-A*ϐ m6{NĄ"\X%VOL[TQ1jŭ L4Ę ʒD<-˂ps5A!$/]mM.FDĔ{[Me?="AMd+KWT1S?!c5 ʛ#Fs"bFƃ Dk/4DDj* I4TRޜ* DDLS}PXHNE|=h-WSLNErڥBE.9#"\AA |+NɒL QXu'8+l,Q+A̒F]nlXx=|*jgm3YNa6yvё#]j IqiΥdV1YN'cDf""R"nŵe>,5EꁶI˦Ki*?z5#,is|Bk&f4XBi10&5X\"x|&)UoPnⳃ])kvmr4=+>>&(%ҙ DDRB O Eo=PFdNj^xX&` $hsΩ' Nrcc3PH[d7'{nSKt"ʹQ͑Ш_HNq dD&Y uNGFHg[b)="G.OM^Jj]^lܲ[RnlceM̸a:ZP!MV}W<qATvs#ND<]iaZ*c{DD̰)=')buXDMaVK~ɞ!uc97K˃́Dn۰_shgqeY\v5ɡƁ~E^vtl(O1\âfDJ45LJ"`Ի%|NddqNrJ~6d3kDO~ʞY]tg'oal⡫=ڂk#֒b'.{~g-^b:XD09s^Gan:Yx ]fQf,ad i]+3KK0@D.+lB&+lB&+lB&+lB&eyB2:3Ujgt  ^}].yh]#¡VŧSC{j_<vҲL&PtڹV˱n!O6}´([w'_a2þ&C//3k޲)nt&]ښʬ['1n.7"6'{VW/o[.MK]ɨ0oVSlVJHo4LFLerTZU#]g/%7VRwS_P,ٽ16C/DeՎǚ_"c\X 9qupz.yBDjmЎ|e2폤vS䩖[U5_X_ydK-G+-lm_X+XR_YZnѝoqSeTc@|MlpRHu[.t_ڕ#߼p]uxW 4?W+ Oۖ{[zI5Q_ez$/6{쳫P[ԇjsVKZ.;h7|Hb'kpWQsIN 4rMwxOHw5 o}V`[\a[ZJW74tux:w2,.:|X*Dzrݮ)ߗC}c""5ު*&b"i]%Wэp*o[]͈MܼI  Fd+)te=(kW̼>H)@R"mnYFjy+lNfJҗpD"R{wEJfG^l|Z;|#т]zb`TSx:n2=w'}6ٲ(16׋Dأ932*QT1/t 7tuwfo.P{åGjs2YBTFL&Sh:OǓ f1VKx@;:JbSk5,HOējf12V+OSDqibErR ?YiP:1{* T=($}WOo9ˣ\~W_{Kk?[z@4o.u"nv0M^k(R\ Xfczv/0$l[<%pǙ]˲`MI`Pp~pMW}"sc1"$ǥ#c)Q5ߴBZ4[,X,FjQVCrO2HD<qUE,Q%1"EcFd\)jMk|0pUsn[RSR쨟˞ᓒISV RJJNL ќsqEDDJWQ^sϯM9J-W{wՌv:QQ #Jp9Nn- +z5G&F&f IR, 1^ND$GG|蓞 &8Dg^XΌ"TwG &I}BwƠ)*i64Wc'9:6tLz5`O:y~ˆH,O M'd"J'fgK,f,, w")YXb?>8ɉ>lsdHa0(ã#Txd,3E>FiN<534YoZ#z䁆hv*W޳Hˈxt™9Zi#Ev_}l,ٷgHxgog`쿽F{>??%Tn{|\*y򵞈2|[{ȶw#] y+x=QQA$yzzFɁ?G_&Lv?xʙ_"Fą܏~sDjy&RX*)}_짎FϝxxY]~/] J.Omz|ڜVR"o?mf,Ⱦ{LWW3KK.?r8+`c:~Յt%8OZwm4^?ϝb;83|G= Bv,-1Lm~bٓ{ z{k?ffߺuJFH7rd/!bO~/Skg>M:~ݼdswC7?*rX{G؟ه1a]T̺o7>[~2ݯg^6 DD'?䙻pG:0u{RV}3_o|ٖX}X3kDO~ʞY]tmf֝_Cw0@&+lB&+lB&+lB&+l/g+3KM0@D.+lB&+lB&+lB&+lZOϴOʙ do ?:3[徼}xeA('燗{/]~ 9LR)̆Ϟg(.[j6~wXF:_o$ojɲLx>lܝѯ֓N??P#+E+wŝ&wH>b'{HD~ i^?w?0t:Hl~?jLb??1oŏ=W_?>z֥&;?,l'.'KZ:%{+5os]FVN~V%z@AmLS'S5Z1K~?[ϯJ<=p)S}Ng\VonEStͥg?JH6;(\wJ}}fi;.n>v8W_o[ԉk/}?'^>'dm_z{ƣ}(w[K_/W6ɓ݁ݿ/*]o!]w*3?5x67Wb଩˿vĿOEƣjƣsQ"Ւ+W|L=z_'RXK@DbzD\ʊ1]-EٓxbO_]hJv<;.kV"1-g٪DcјLɮ׾տ0yJ1rnmFlx^'&wh&~g.=ϿZF$i""UQ3ϼzjcƆ=vwهuӕ熒Ĉ8>گ~/+t_)oůV3?tJ}}fi:Bާ9׾\y[ MŚ7C׏<񗟿O/™~}#tv IDAT* ^ꏇ|X ?_#9/r?cEv,-1Lm ? '?|O\ ߱6MrVOGj7X?zb[ ڧ|_@g^'nW,+9p#-~hY$ronEzhVebÃ.tu_͚__q\"j- &mIQu|>vv>yp{x"L7ܜ/ǣqNW_^؀Rc\*>x"Vr>qoLM۫]"co}z"Qs~!" _ϟcb'>X RzM(^Mn{X@3=~ǵSY 4(?Ǐzo˦2+i33,m3TEH +6أ1DcEc JElQP,[f`\VH;Fܿ/eL9so2)}㬐,lZÐF9a2 [А^ucԮs:X>wL&J*TkٹC^F\PפZƭ\L=Ծs[ޥطsu*<%0HZ{ǖ,~ex^UBfRMr# QYw}ea[&ݎ\߶YNM[7kA4Vjܥ CgWB"c35{x6o;ӴwI=] |tEĊDDD1"V$byuBIſu5+UȊ90|iٵ%޼"]N6rpwWJj|'<:PyX*Vno.V su.E+k׷k݀Z̛OK#'<}f\jL8ɕ ĵ,{3?缮v~Iٛwh9=zoje$T55WZZma9Q*wZ{dG{ qU۷G/);8~NN:r[W}mN U|IUQ{[=:}I+}ۧu_T`9d{wo^X5{d6LwSG;Ew.'">{c?~[:І3Ravb^Ӗm9};:xAkAQvl,EJ~1{#ݽѧjj/DD}ĆW ~/箚7k]0b?t.qm^y9: NVCX6:W6q{jժc<;϶5Ť""bhXYDdvs~6:q7JȤP{GxaJDj=mYCFfWFKV^&+T15Ȫڧ6މW$"qXĐCzf|1yoJCH_*%F|53~IaX1j9zv8fn2KtK:% _Ę}O02&&ݽMN^._#*VD\&},FP3%=Cc,CD|;dP0S;/z޼yߏ{j5إ ȾC𼈈KU-kq/DDGOUlUb0D'"*ܿ^AoܼujJi@ކU?{''"=|Uu3gi"CvSvT׎Xͥ 8X1DD\nz1͌Ž=P{lel`ѳcݭ n9JN"z\vE5k::`F)/e7ǽ[l޼NA_=6cwJ'xRG=w9Sg5dP'|b72I|h7|@[¥Ɓ;qnJ cx۲AN쾐ju斵Cycm^vnno o!i֜5gZRMwj 6&=dkXmY7}MsbrrkDKަnݾ]. Txp h6lv] ]sji0UsWBBt $+!}72bbK6V"t $+!!] @HHWBBT]XIծ8+/xf5cW7NzZQ'Ҷe'rzYSSyW<Թ*nުʥ߾=Q[jP:~nw"ٵ'F/%M|~ڳdAW+3>/VgiJef 2!Rn=x^,mؾAmS]|YtVu'F&|Cz|RswqOgM8'Vd؆)CD:S6,(_LWn.i\"{wb&;6(cndi!$]FNT:[ֺ̹W\!?GT4۶ƲWfUKWUfʹKe2]l^x{H&yuFI.ӆHǥaȈs׮kOϯLY݇%,IL|a QV <|{ꍂ,>>0cjԔ_X7Q"Ubb >n Ebjn5e.r0ZѢMk^ΠAf-{ΞҚ^F!_ZY2v[/_y20^v۠ꦕ Wۿ.kX;^Z̴f^7.-l^8if1 cU;|tEW>mր!f" b TG4fBnOm+ֱյAy Ki׈嗼M+vagvjWuW HWBBt $+!!] @Hp.%,a @XHWBBt $+!!] @HHWBBt $+!!] @HHWBBt $+!!] @HHWBBt $+!!] @HHWBBt $+!!] @HHWBBt $+!!] @HHWBBt $+!!] @HHWBBT~v|JThWӮ+hbDRZb]5? @HHWBBt $+!!] @HsxL; (GJyge[h­en~kǼ\װ/|WS8ru 'stͫ>lm%_::W_Ed8q&]x(>eUF ȠzFz Y˳.eɤ>sWk^QE*w8f#/,IX4sm+2I;&4!"ߪ챞ᙲcgpc+"wyA;VS[J.l'r] v^i*R%8:ۊxegl]s`z:ljVNu+1DԲEO]s%^q7nXnczM?pzOi"ΦeJo9gЅ~}~᠐S Ŭœ*>OҚ׋ 3`҇{&ьv!ҡQOQ?ۋ1Ӽ!W2ꙊObͻF̪X"$۸5<}T?I2ix ֺM1_jGDN. 3˽ugv T!urZ|#Ozx_ ҕ">Ea'4|A|n&<\"w؋HTmF=""^?y=ND~TRGU1O[ܘ!"R>#_ri[EW+Qw&w=MDDRQm%D+RI|ݒ9* UqeJgMX:SGiwׅ&S5u8vƤζbPQRo=QJw?tk[|ם2m51H:mkE"S'?MQKιʓ.^gɅJNuGoIl{Q-\KDL[INwqi swooΗΣ q6j7_(xQ]-ne}+1\rBbFz#FϵYnU\ݚVȂ\ձ 3cDLq¶#A!Ռ^T*:+QA .] 9282/?#s_/+xv/nϧ.^?<)f"\e?[~k^/08,`Vѧ_p}ͤU7kt]D+U~9I}^Tk`آe]cFxÀqnݽC)^2_^Xr.~rt{v}$)쫘c{4Hbl_/N]}&nOUuĆ >yt3amdf9\\eGbeN<6c'ӳ=y=ˮ8lIjLT̰-~1,+*=;q4mpKxF&"֠Voy:+FZI\=~hZRj9ރ[yNIN/M&!}ඥc] ىWIjvĴ2˥?zT&­H#]2)3mш+W?WyhwC"] 5H|۪9; ۳{=̫8@Egs*fUʋ'fiC[IAY _e={6y{%♚5uBʒȼ[m۷=(޻>qmTē}F[կcPGn޸>Kln. ]xki ]\fĚэ' oPJ{)k"YX}hcR)ɋDD\qڶ3#ظ$>.m[#/**H%OH%rYƹ\zNfw*1v97^FLDT)֚G<.MV={--tL\}& |S'Xq:7pdTu [/ў@Tvyg=pyL!/J}%Ӟ%ҩ |ǾLO %61VNbe//Ɩ@ReIӄxk֭}-csTD"E\r>ϚhS'ԾJ^Z눼<7J-RÃ~5l7BwIDAT,KM<ϓ?x?WO %wO].ջɹ gDgZ]Dꤳ+ﺝq-cd2YQcZxH9z/N s6gS}naUGJ2LVPW8`UAFjF;$TnJxrO> lm_C*8.cԪWG7I(THsWDǼm}]3fkjRdVZFs#r:6;̡fq}o3CgJ68uJ~uGm\?Տkm^xt'풙5-t`:^#{J(s<֬7hdoӦs >wΛmuiQEie a9ߒG'8A1Г}~'@uվsg-[㑩4k3wBc=o]ZȋĆm[]k"Ef/k8OSOGz+#[{m|7is\bl.^+L辧ⶋ;o[L3_u7;l͆}b MY:O͝=F-Z7,V <spiF<9FϨ'OP(]/i60wq\rRқL bK s[;;R~g$'%JMծ{)y5}&_JA.dd.}>HWBBW0.Xi>W#̷ E6#XbanVg'B>9w'x/h GDH<=oHzmjS[s?b=ϠuW|/:rס~kg{*CTb*58ܒ%ˆc!,vhVMLD4C}uL[4d?RS x:)1\rB"smvFԍQ75pul'/>L927<-)0m+͞s<#>;t-AG|/+HJZ땾Z8pbI½ qk`,B/;*nq :Bz;2Pp@pE7o Gk&uTU}Y96j\JQ2#",Y"NVXxpB׎n'e:%9N7;K3%qEVп^)/MODDܫT}{{l5;uRbZg\GNkk=pX 6rcsi=CTkи}$_못fo )|ۑΝV銱A`xGTten]{6}-n>;T0$l5vs칰d;Ɲa0uuts7z.fDUhvwW# I]!"cXy,H2~^v-Ë5kOPLD3>q|hhΩ 6&R"_$+뽏hT*%yG^ҵjEϏ޺ʺ:"-Cp@ޭ9rRW?OÅ鬉{4 VM\NV6Y_YXXe-XO U>JCf) jINohiW1i}~pb灰GŬ)L}ʟÆ~+WHߺO/j*FO_($?42CͰϿGm]%$ŅˋzfZG#E3 _x|E͵s!~]KLTTfN/~)r^\;yB]c#C76~&ig-513 DyΤaDYY<.Tb"ns>*twda3_7}?;m]lʂn[J6QP]\6ulvOU%"ִx,#G#"R%?edk[CWܹ.;V%x,];̹dqI[DdֺZ>;c^㛛|!V>hMO*1ݶ,,G}5~_ҙ3VlжSߎkUܟEJuTw IJniv^|%I1`it08'śGɗSfm5kg&ħx]r<=~֧yynnqZU )^}?[$iBOGuL ?[Q̣v40w $+!!] @HHWBBt F[li?IENDB`kraft-1.1/manual/images/en/catalog_standard_fixed_cost.png000066400000000000000000001213531450127457600240350ustar00rootroot00000000000000PNG  IHDR}M pHYs+ IDATx^u\]kf)PQ@iP@o.|AE1( Yvg?na%9gg 7sfBM)\B0@!aB!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!` pA秦|F[7j¥dp\ 檪$TɘL@@-AJ$I+** W4:)))o޾SUUh|~jZZK z.I0 P)ASHPRR֟V-B!B! BaB0 BA :/p7Ri኿ 2eDJB$u>F \+TE#7 WiF;3zϿQNJuvC/TAZ-|fW k׻k2*ֵOϙ]fWL4\NNc.}p⍇S\UC$C3tʋ$ rt b5Uyqy(쿙=/|vڲoA'{[UӵbC w;s/NVW+v,a`NK >:ߞ]Zua=b# .@U_^paL;wxX J)Lmԅ[UJS-/9 +ۛ4% ;[riCdytNؽ-3VP֙=ZK T`4,\)QA LJ$`06M l4jck)8|ԛJLz8s6cZ& $az`gWeWcN+L.5z23+Ժ#O3_Ϟ|Npn;~ER\[c4AH(07Lgy"uj pp")MKNMc2RMc-tZ٫s<;s/鹅LS0F1wN{RĒo>omYGh:wwgʽ>|˸̼"R )[6Ƥi,%ۙ3L:-p -]skϾu-GĄSo*ь N-`w|/mrk#$lWP'Gy9Fk3GU^y|AWQkG쌧s~~ιIF22Oov\R:sGgyunƳbsLYcW-P5mٕ4>XcOP2$K >4#Nt^wsK>?q}bV~1KdФ11)|u1-3m?u]Fυ*щA{Vܯale}1֞tMOu50;j[Ms$ٿ善ǒ__ºV  bdnx -4{Yҙ,>n:T# G|2k>!qkRKWmuߧGp1i榅:yD3bʽ eWYtU$^[ ftRvtPQږ ?;߂Yo7o-]_ 5Xbd7oQ*Ry<>M䚫Yq96%IPtm۪[<,8ϝ@˩j”8ZMByILFzI E^@dKgAYG֋ɷy|+f=]:sك>N h|2@Gx!eetEuXGJ{vsYbeb4&ux00c?90ORM $ 촥kfQ-7%Yڭ2 UZȽ{WaTjIKIX3o鬰 >̯ǎv6:RT Z2`hONɦ-%\J˭츉5BdNiY{S&sSY18Wll*$NXYZQgn0dfx3HCY76Jr^hzK6!x|Ǝ "I?t$+P9Btޣ#}H%͛vM<_ZSY')XFjz*i20r ?ޫU K[IGW[O7uQGnK|wHy%yxL: tnRb< @tK :RJȍyʣRV x< @L+>:*kP-{=>|ukKSn*E-m91 B,,`r8_siiZE{o>jkwPs6;sR^cfjT6&g˦)ODc9 1{fo)q6;DRƽ<)qOsI OfpyV_B$_:3x:.e:3CQYSJD+ <񦛳 Ŋipocˀb u 6N~NULiTTh"oi0'aO=}xbm5qfLo)*5.ߪc;)dµŋUoĨ^kuJ{xXpy#Th"> HF$OЙA+]L8a{^Vxaї[<؛v5K{W;s +3wFxkoaem2t֙wf9gᙨ.NCї[wSɔ /x  f>zNy.>/ŗL4$߷*T>uJ? +^=>7}5>%a;1m-;o혾v}I{rdgO/lcaм/ՓJ 1u[/;랶IS7VM쿴soϊGfvXxFxz-t˳=z[Y: Q*W[?QNz= ~rGoKK+KgǞQPΪˈ~K\~1vn|+.(ȹ6d\ Cٺz+(9twif?dy?N]log%B\-n̋9uh%5( =sO~pemYtv3zmx6afzÃ7{wnXd+ sl=0J7_  n%iƕ5N{goB@НKkct.߻ wqJ_8n$SI|n\Կ9 {o;-=w#ޅYO6[a-~zt]ƼwfO6 f"ziŀ׶sesbKwnYAz )ԶK1% >; 9́ד1dqwnr> 4w\_ y>~.,F}9pfSOߺh}zt-Ta{o?;]kI ͧ ǩH%][:2k>{nǽ`pѦwisn7a{VXLi蜿C7]cs&CZ}gV[EH4DF8 !ubN[rX1mzk\c6`s5ġɍ@IZIT09,z$_BMS)!ERv_α9̀;pyIQI%m4l[;E6[\*"ط ò-¬CUESyzۖ2UM_H5n KnnƩQ +Ur \Z!զgfIq ٮ?&b@J<† x4-Bu7#Tݐ] jϜR+Y Pmm q!oA)\h΀ÍIIJ~Nk8, C#|HuΚlTz'^bt.с_!=ɐ@r -M x!6qݒ:1yl=l ,C\T!5ϯWKhr:JJtR0",AYO=ѵvS&k^1X4H-RRb<8RKuH9Ef$IPU> H͡;*:{l3&:jХ.%#(KH\ɋdpd9OEӥ#eʙ JEoʇ߰|A$&QV4 PaKiiE6 TqխP! +Y ^(%"~^> $G]]*=-PRQ,넔TfZ: w&APES)A3|K*"яɶJ# eG )^P"0&[NAAlUQwOl3ՑrT>){KrRShP⤤ yEowvYXZG 4~Hy%ٌd>fP ),Eњ * MU#8&z9M ;pw(wTʽ!//{qΆ߮ H(NILr-lmqYZGls4a)IYe^JBp 3@VSnR^I%&SN'oT?s%t<S1 I*/*Kiq|4j+k|Zt:v<0.Rai@|AI8r):~Bz1y޼I*ĕZR >U4MW֠rN NFd y6&dDL+>:B%+-{ IDATj\_\af3;8;J8,GώNŤ0۫&{UraLhkH H} dL~̇84Mjٺ<;7(~HiURsOgwCP)Qky>K :RѪ4m{e"34/#͗OśFL蓯o؏ G||h:OMUi/L䨸+kZ2XT=S?dr.S7lڴdž 4!mkeaqXPwxGKK+;q1ܵI`o;[} +iPVqt|z]O~sznѽXqʙy_ӟfaak/eNo*l6e0~"F8[ ^p,4Wks7eGmi&]m6je < G`zv5t,{['(0l-̓gZ=n.#lLhei7roUg2fOV \>qrk3;zu-82mȈvT ߦY F.p.&¥>bOrȭ~XDO P[! BDHH' khւ xgB!B!0@!!!` ΠHD!$ ;ub2+|[RRmYYኺT;_Gl //\Q}NOWW!k|=&ի_4\켈xBpE#.*Jm[W램!TbLsssNJ~^D}gB5FyDBz!T߉"}1 B3PC &"2B!&B{tӛ&}o@Tw tz\,\^9^JAU!3<߫P_N?C,nbOw@E57r!LLMPe՝Ŷ}aKN7"zABҙ>3^19uhhM^U ٴɧ"&E[Q;дYVLm6`x )z ڒff=d ZPc~g $:ٸ˩URv!k7ǎеmSlg~>pmOq[Jn9q-cJnsfY>Wz]awek?NvVN^xTi{Óo/:d{X5gs*Gg?ڽO/{7!.W]/)R7u䒳yKe$% Zl%bZv07dt~tΠ^zy_X6;bWW疎vsp2*7Hq6-U?})^Jٗ_x/non9FNy~byN=n};=:7vݵ՟~?HEԹlEؤ:hIʎ#{rsG_[7Ӏ;~+1h‰'ƺ[?sΎv>ˬծ@F*]238Xx,_ٹ]vNǯX]WP_N49;:o3ߪTqB(:ތ!<SVn[Oy*^\IM5j' P~`ۋN __c[Kѧ./?j{Wyӑ 7筋ͶzUT=[2iŒxNQݒazvLGgfvڟjwxf鹘 Nm h6͛;4gr5^~[O^Wo&-|o{/7g #;.9s& 61{@Ň>Ry$(zIff`͂ׯ%k!9%E=r$f]4!kf2_CEZY u'.HNcgE.54PCdY6!6&G6ح52ˮ;!h%{?xTwݵ_'㤟n*{>pє$ɖv]t4`Gi"]?m:oYw+n0\7^zv:U_/T[;`ْ`qT5 ~i=5% -WWԠ=srY9G YtQV@Ʃӧ۷c)퀄.N EO0Fbt;7CK.bb~5`0%ݺrFrZN+.]JK@ȚPvnsc)࿾cؐ$!էQZpP}c)*94$ӐzBa$h Om6/. 8?1r HYynɮ%H!ɑ) Ih,RYGHEwiy4OwH|b0t1MC-N~{lA}藖lxYٔ 9(l`ǝ@Q f֎e߿zĄU!P4T*݉Rxu: ϣYByebKu 3-SJE]BpkhQ1&@VF r+.+#FY8<3|d;=&9) !JSrOf}O'p N HyEd>bP) ),E) 4UC hU8'|d}˒\ȑJkB(JK͕U%,TϱޫRnrzG:*#=RJNN'Ԃ˱: 8/J@EQRe E*w4TCSqN[v~c\|r)HP |rWv ٽsM+i}OwZ5#]єU{rrJeXaORF&{Cc ;K+vS?$)KDz+>Li1!/O!FWgI<~Ӌ T4wsn *L~:bhYX?}ABM2b>:£ľXI`uovlZbAQFL*k+GѪ(ȉ@Ʃ $Mr}]|y1o🟙'RAڳۏdwE~!f{G{GNɸ7(Ygc7DHn]xG55"}7>,:鑕~VK5բzpg@yPǐCjrnu]r aM^C{%667M&L{6fY%Ev/l0_ЦqΧm]xJW*7͸GO\ca|vrKO'"PRsXhfU=,,&8w}q:VM--Fnj!~?vsV}[D WGwI VO=x \Zk*\QZWgDJ{.9^Wtڋ kIWԃi"8/RҳĽ%^jAWw}o1 P ՝q.E5xB!T59"e&B5M홁Bk9 .c D)E B4USx}k͖LJJTVVheeDͿZE&X2۵|%'LV:"ʻ!T#\.CnnpE%..!p8M >@F!aB!`  BP ӵ%. O3o~L=t22yσM}rqgaK.GV|d;/~^3vDkRT39G7^զڿ,B>ۏ.w6U*w]^*'h&G;xαlDI>mKn߲16jz|oA8cډ 7 ,WU9`.wn lo@|MslIIݶmdde+ lip]EgnNj#Wm枝O:͛+f︿˶-unM3?bi{ObIh*Gnm]M*Tp.E'{ ?R,:cŜ^-YP}Rx,vL# n[ߵ] mak$Z8ka/]րv;g=uv'{1=wg4k L)؄;ސxBy:wQQzmۊͦ%/|Aߟ ,foN9tF ۮ,*FHuč #%n8Q2}b7=s9ש(~|pUb[W=p_cG!>5C=-( +!OC|7Y~8ySh. xdCB 3m\of[oˆ=\\z9 )ӲMYS_cbuJF6ZQ1_Zi~Y@}Si.inV㹬d;6$| I V8)*5#35Pau U]eֵ581NmU3xfh V->Ɣ~K1?&\M5َ70HDe _FWr3Gego-*?&+A%}#Ut3R{6=UIA =܁k;.B R+]&?ria!_r_^GUTB Xz8J@QF|lJ]l|\RH'<B$l\<!.6&q*0O1ߟf~oZW6߶>p\l~ǻ':+uŸKSF[ïnjm+ _.ӤӴ;gk,0'٤lЮg@(:7], ~|c"9&mص}n8k9@˴##- ]}j$beF/;wYz]&&nb_, 7b"\ZOZ4.E/٤rધ^ TO"ܬ4fM~PpU#ɽ{ָ͛VUUU2<562._]/\ *+1܀d;_<.Cf(\4َ 5yUlf 5wrMg>.艓&=}ləǻG  " BۂPשּׁ?}V  O[GB~Maԩ`"v4 4M] 4ME\}U6%O뺈` <4~:mڌ3TR(++;ӳbRT={98k}:e#lXtC!šzȌ"O:`*ޘ\CBq9m3H\x]ڴn-,l1_}sPdCi6of̐BAO0un uPmۍB=yʔQ#F:ەܹ{U&4UbX3ftHk~qdbzMH?>o-E{5FIzKزum[jUբiEa[8_LAF"U2 bDC9s5ߨEUB2uinܼ~z Iڅ>ݾm{U%r rR/*u!ϸY⟆ilp!Ttڵ9s6_/6 Դv ?~ [@'N⃘yW2wT W}_,Yxbh.<7Tҽ+O~VSM0 B @tLwlv_|޵cGoV-J?6a 4-i:y}tko}L;'# ( X IDATVp~QB^133.ZK!++kǎֿ'BBBڵ3Pc";ZEg!0 Ba &6G B @S{f zxg`!p!TْII*TRr Ga EFhdddZKth9` #!0 Ba  BaB0 B!T/ ؒm W% P}"e M(EEm+ʏV4Bm:I***y";PGM D_3@!aD}\!B!hr D B^Lw!N!=MxgBoq9/\^ Bk`7_68MjD9MD%zj4z^WԶٵnHW1V~m*\l9$! t [{W Ա]+Ѿ;71!a¼ JXy-.]lBs,ݑ;TۨUXFeDe!FK׮E_UoBTfaDdR@Fy_zC`ds~O9U[Am0q̽m&e~~5`r>@tm~MjB(y'g]a\t{gYv`4x@6V'm@ mu+o)fi~à^}JUw_, 7b"\ZOZ4.E5yI 6j!!!髪 WTFF¥5w!2BޣxP#&B! B.3PԞ &2B!&B{ldRRpE#,+.c}vo+)VtŅ+Brrss+/qqqG7xplj2B! B!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 Bٻ?sfRmQ*Z.ǵ\\Ȯ{E+%**e )!jM{3͜E}߯<ϙ<<BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!A "~n999$.E".z񓄤$ O$ɞ&=K: Lfo3SRB_B}0 Ba 0@!!!`  BaB0 BB!0@!% $%¥!|I))GsJ>EQɕ!0)IN:0@!0A!0@!aB!`  BaB秤TTV W $%ٝ;u/}0HIIQSWSQV@!$&'wY}j@Ee%&B}**ʟ׀>C a 0@!aB0 BB!0@>̡:2fappҏOXTL W|Wq賨ys^},,\p)kWz273u3jjsiAm^rp(Qi{W=mޕ4WZc}: |%.=|%nع3zd \"!5A̽6Wn{|+/{x$p>7o 0Iˆi˳% l&v?z1/šog -Csh #sZ<|ecY̻ZF_]3s?O>"%:; wIͨ(6[ζ=A9#.:UB۸^p+8<\Րk.RPkӣKO:N7zRwV+Oʜ]zBX"swcw_޸gpgq޳} ś<q{Oq B ?<P'x>v-TtSZgpKJkn:1W#hn\ dKQ<8jI E*1kG:t쟞ʒb@Hw0Ӓ"3*k[ε2q*`N?<% !fbHkH?I:xzDF& 4I{*GCtˢ[I*=40xo*Lkˆv~Ry$ bj6}>gR#ddy ().R`<ԐH1'_S *-xpڶ|.Ө^[a\%I(ϮAi4sӷ8V.(.*UWiP!(/,NmXI4 xUJJ)AU^![RVUaSA=DH*( AQ UOyY3=BjlnYlc1B[ݗ^$ܖwf,DavSn4 ti fo ~hf"L)PTTTfM]YXXE@Wʑ e))slԴZxjBNIs))U۶h %}f(By~Z{8ֆ@`fy}{[R(:?9UFWs8\%c 찐.tb]b kf\B<@K֞h}cE=v_־#stxpWUUERn}Zャ8\#2S*6cB5mvP+]JU;t{Ggz}[ Vnڼe`.Tx,H&E=wd`WFl[V8SI*vqS7.ݷosV)W_FvVǽd;.{jwqwmKdn#lIB{k-Lڗš$:Zx2 d&L^2jA `D1DZ.EG?bQŢKޖ-#!$BD ~ \&Bc ` s}(fy烄 !B! BaB0 BB!0@!!!`  BaB0 BB!0@!!!` xK>#"N]_?{!! cIɥTz% ztGb4ЏALllppUOSS MMx*; onn{odVLkXGy&$sj2)ϰ Nl !|0xARr?iP!ڝ8q˵hB"V/8 ݰs*KXHJelBޘؤQ#G64=jԨ) [+LE5C~Q"Qɬz'Xf*Etbgtx9ZY4T:@<9=y{5{ JG3i Г&ӪtN`~S;)bRV} e%ё4lYp>blM53G8ٻJ^ȋ3rwo*t,O~vN'R;IcMAV_KDDz;Fim'wKTaH݇ i !K_~8V#Fnݥ$`É;I>cV^ \ztvf[vйX9S3^_;EqtjwWҜ vج8y٭I d]!'檆,]s9O>Jڡ2᡺^JDZ%ٴsRyu 4j2xO_\Z wkG[)e$ &o8uVq4÷^ ;ѐ{oxgC#.;޶p.Ѕ!_ zfUjxl+i]'Җ^uMZ4;{? ͥ Wp#~&5L ײSv U|83%&Rs[ 5 BJQnkG6m--8 3xѶR*ns۴e|UA,itWgutKQ<8jI E*1[lKK EefVMZKT#fztc2t5yNfZR$r&]YyMqW ]$X<= "#Uref_ fv韎H/-UQUy*[pE9orT[appgҥڑ J+IFMKۍuI҂fGJ'8`U9Ck:]g84NK8Z:ZMUV4㩢"nGj2**imӨ>=I:S.a C<66! M;'!#/C K4C F (#ןrIʳ+F4頂;Jj`%#P~Js]'$0hN# *oCo nПIWDnc"Ϡ~#HԟpJ)xwjIc?%-]>*g$eȂO =9Li{$er =3'<^YIw` vNRTc[ ֽ/t~ne=4w~j^κ:x?Be0eee *K8~wmvHn Lf+Y2?jwF )NqvyPZG5 t =#i!wE|vo'}J@Ufʶn/Ol J-WM#,}2 *OLcy )5njf:'i%G\rNja% W5Kj_nigwgTP (znYpJ,a!1uׯ2)iU*to< 44YJ!l3; #AY\x9wN^Nj}i ?psxqN93p+nfk@mzˠMG϶üc'z{$u1Q6p f>:@YF|Fe1F-ޮ/}_&/ײ4r(m{L Ior $nX2ךVf(H DoeZSLX7f뜤n&Yu{1Dj]V}lK_C{QE-m2`$吹#G0s+WzFE{F;9/}ƥ_Mpkc_bh ]Z^qpman{:)vQ:`1潅K[aRbҨQ~ gt6쬭ƋP+M%k(AV)vNM T5=zEUUVQo9or #""t$@_I  MZJgV҇Sjt{*sWԪ/ TUUUMz`  $jU\񤊴*fZ%It7UΉA̠rqvr555<d3b)nM:$vNʝ[BBBB_9O+xa]PO0!O!!B! BaB0 B(/-(MN.'|(oJx́зNta&'OFJZJ-\~\99yox<&EZJ{!DKtathuQ_'ɨ#mݾsv2m7ҏOXT,|2BߦmC -y朚. 1p+>ǐUh9nʡE V#@v65 )w:l H&K^vÍ|{~ڍe\˴uoy||󶓑T)[O-L^2FH?f̮w Pf+ p iL0S #vn8/k=z_zʋaOD3f4]'L $ u{ᦟ]1iU|Yg%M{Wv6a} IDAT|8qҼ{|n>ܪmǧ= gTg=P*;1ZG^s۔֖f?ߛvyTYnv?2QH>xƲ-Ҏy|cryY#{HVpD$p8pw$I`D{5ty_;ѾӨ?O>~~e!N66SW&_Z?y]?gϙC= 2u1VLqYMc[,8=eUӅ9w-e (ݶOa>y4>{σ>Xs.4 ĵ;|. U#] RDbЩGU$ L03Q%eN]~f;v\+BX_oi6R~C5]{4PTP_-8!^^}p@PT@{*]~9>π} ZI1IBJEsv?{p8 ݺvDΝ(N#ډ]&kdk~{pe Itnx T r:dlVVj h7Pi7BMmsh/Eӕ 5L5@˪ζgT~TڍYNzK7xqfJLu/`8xW\KIu=p$c1 ;YuWVl^ @mQvw@[jX!UWf%O˞qv};mS\I|6/1sӱwkҫEU|a8z*\d=xQLb‰l| M_ BW`عRݙ?$2r2u#+AMTi~AkQ\Rô )#'*.AIh;DDb$Lz dkA3K7J+IFMKp)vSj*tqa1 r M,. .Ө*;'\ uNG{r5{]VϘQ{H 58Z0{>1j k']~TvL[zpS|goڰhqP^9ca>P\Qgs|J gf"{"$ zsg%Q/ԠSHίAIUjZmݾDA7Em4;* 4@J}뢯շ<4w~j^:x}5.R縆"ά+,# F;W0PŀHzCU\G9w6[^Om%gF}Ӵ{RW<zs72<,,4ksTUaao=x]VFW%޾$<_k!7n$NIM+N{QҨOcsљUҼ' 95tyq ݮsq+_>bKӼ|Hhh*d=~R@e``)gS\"@Ti|pDj2rDfbJ%@a|2cf ȏ@Ws8\%c 찐.!&'/&1i|_~}mX;~NTk* _qY#d(2$FJkUg骢jRNȭ'r u+xz~՚pÅ徜>3syz=1A/ժ8-~$݉vv‡Bsr;wΊ[ek!{{;K\OR:D k=¥xQk+o>1獼LMK?ןq)ɨhw쬣 .՜W/s| I@Wq852P] L  >bܿHeC+C !A$!;~$\v-m;bb zS1kSM;/kbK (Mf,$Ҳ_)ȐܢLCwY‰Bat~xp7k)&N 4_=((4Y 4q_ySu&c4#..GLWR^G;[IKYQLf  j*$Sˠ%)I}0hhl VVJ}ZTFם缌{/klQ~]!e[  wL9Ci2Ӓx9xĭT!e_yrr ʪ4U]Rk@֔s4PWY4@U5%<Η3AA jpz_.}g};9mSxv. ^?emV]J֖%pq:oBDwjNN^a>}G$ߓ>䁱7'$ G5F͢CWLZu{֙jIrs^?d3zKo0:3+T> ܴtrSh)_u} Ҏ-FuS u$ *|3T#tdߒ];oy&/O9=U_gQzҵ'[!}Ӑ$.\7d0;]zyd^=v}\TH~S?k=myL=f.@BV1*^\ Lz`T\ڴ`DJ !ծek̟,Yxk}P0Ks߮+c܊!rLhzkNET'pP#OGmSXfKIc/&&i=ϱQ/oE yt+v^O Z?bo݌oO rs4 cX75fx٘m C':_v̮ݑq"gȎCF )] "mzߝۻ${Pm2ѥ6W6y}ű,Z_ (-[ e( ׸AsI@ה~TYLBZlϵ soO`K̾0~Kˬ@LNK6T~)oVK3PtY{jw&!g tӆͫ3 ,uXzvR AVzJ=1ۗ,⫥gru&BCٌ ` $*{'8&H'.Y4G51~τ΍FgSTTjp:U"{HJN{ϦUys|D` [Am3] 5Lko*e[g۳| y3n_e{mTZCJ=X? ,6𶄪'XlTUVAue5z;,,6ZDa0;ݼe`1 *z{CRFNU\FR<ʋ*=U*p)~_:;n3O"= ۵L:#ЁsQi%4ɨ)|)0+'eEqT,uY?cF!jh>[fAuU5 @TWWll ْ,nq$du\$'D4}㘒 JJJJJJRG| |K@{c.c虙> }-t)$&7XQY t`w|OfPP7^oL j7mˡ={!4gEt!U\}%{Oo9 $uղS3.!NOӠ_1t;h秥W%#P'U;KҊ:oy>#= B+*MIK/^6_?t֨|;>Y\ū*K{S, '~s)҅~<Ph&HYy”4\8%] @G6 ! [4M +?`8۰wVͩTHkctvvvF!m5wlECF{c醩P:|TW{{')%'9 .^Svriu3 Gtl[nj;vwP nCjN[X;\F}!fkWfgВ(y~ߏHa>KzƯbg3&݋ ^81~T>^1Z.E!/j`'wmfj*\D:!?N&W!H0:M?K3B!0 BB!0@!!!`  BaB0 BBU}{͐15e^#a͹8ʤ. Ǭ'**__O FsL'x7m{mҪߠ vFd@ZE^i2ökWg=ζà +ξUshAw͡Y5T_LLk=/y}XDDjB.qK7!5[TÛ&}J(՗1}'ĚA%dutl"oc޺uIΆj$Bi#"o<"cFރKw] ;P/jW i`{bDo"_n#z]d".G1B{omEyLp#97QqOX9]xGW@8ЪoGop3Ac=Y+j==-%3S3 usqwpr:#Gn}ŰmWV| FC8r zjNv5R`(t1Q*kS\y}v Ν5.O8ť*b `Gh>B0Z];Rd=mk^gC_7'5̆,z#XǞ]7eǙ+W BV/8Mrbj5kwA5f >B1;ǠkʲcNKeSsWo}o x}1vG`in>^ZΫ.]|z^/q9ݞf&zr<3A?9yn9^^^CF, j|'Lw@(j"ְe=W uQ@Yn$Ue;Fg0pĜ!&_Ȧ }hPw0>2L_=@~MjXkUom)C)楨v'$21a g?l835 >f#'lvtQ"%c+%PTXPFULi_{CFǣd;O1sלT#F;& //{P^y|Ƕ> \گEI<#rwg"h/ZI:zjG&WVg:p.*&5/ 6EqNt>Ro>iTQI) l=]0sE|J2}bjh}V읳!77v/!,1{H1\z'uGN;hS6yϜٽkIJ*滌N^:t/C`"eb Tbxl9ARQ۷3Cƽv&$z;sr#@~>A4*cϢKzw*N_=~ƺ@Tzl_H!sP>|'KE5qngp6*ozÇ h| ͽx~R,ANvgl-ݠHhw1gUZO)4M*ۺ<5(_U2mG:wQePULKz0ߴ\5j#Bi+R9<>ubқT h^ gvg]U]TMCC[ݰ2 BVOOU¥@PND4JwČ 3DbѳWn3b,[݄ ^fY-X?mƪ[ -KNZ-m9Iʲe:::naLr>&=`iϗQR~ۡEHo*ՍlKŝؾjQF dJZx@ IDAT I\zYFƭ[l @BWY ^^cH*Xf_Q).@1潅KB5‹Z3_y?ILMK?B!~rIC?11~RRF]ng@bbpŏ+''EBQ/CDBJPWW+//.b0 Ba 0@!!={,\` Wx%,F/-E!Q{w:XdbD g!$RIP&&=,^0 Tܔ KF Fؚ!cv?7AN$-FhV={6mnieFPZQos-1;I͝+@Qo.ζ:xۋ9L>^W69?'nNT*67]̓U/+0@\x}n%}. .j`Az7a,ELcR啝02N؟$/诿NgR6eYr>ځuǛ ,쯨=| ꆦ Y_xVlK;*MHIS4MIB)]cns0@ۆ[Zq:ggmjULi/fqnĴ:j}brhFy׬MR}V0^W.F.OžSMyVq GM!n.lO g0>qhSSGTQa\ׂRSQ' U4ByM#]Ά=ʑf V!-$jI-쐊*p/'mܜ ES֒04؅)RSNTWߩk#@H##w_.mH3$Y~$zUU-hJZEAo }UM/Ξc ]tZށHYy”4 W:]6C"dqwu:mE\a$c FN:yiY|~Zʪig4}ӦKK֑*F'g:;iߣZL]:8~ӚQw_W}c!!\OVTP#P{9):u@ߓ'Ot6Pߗ!f1o^~ỳ(}X ¥!mok#\}r$׋y-f¥HɈB??J@F!Q̓Ku_= ! ?a-$` @-LB!B!0@!!!` jB_^[nv0 P[G" \&B!aB!`  BaB0 BB!0@!jPimq9W5T۷52[gRm@>r-B*K.Hu@Nh$pFD%TZ;vzG)tve0 6FjsvYsq%=! n I4M4AʙoF63YWx y)vr[F̠t)Lߝ%+T=ܿ/HYHj}c3NOT} UpoIuyk7Ϋ_w4x_CL <VZvXRsO;w^-6Ataĕ !#?UƬI9b[ۻs]*mZ$ lCZwYF [ʗP=%I=K*J-%וd}>Y=C[~'P/KAĀwH=ψ]{0HACmtC/#K$B;yNP WԶpreK;4s]_C]5T2vSRŽ2dwO}& cǹ홛z~R|0geҼ^_bxQo-ŇgXq9˽ZP׼֌5Y 8pvnMXvLvE!f%6TN Me{،o3b6ݍ=C I~GR}VIk;Źu)h]TaRğ KG/G_ =KwSz!ͼ!e;uUp`BFxGQb˵A6De[[s8x>  bU K۹RJٱ2?ߍٹ5#ўnZZ5Uť䊁)=@&ʭn٩Զ@Q4a?a&_G D {.< .%02ݴM;s(mL5.R04(eOKxoO3L;;V޼pLE5Dܺt dY(~S;i/Wּ&jeo6g^I-M7@!Sgyڦ)\ h3ɛ?<h[t|ȧ@jYrVezзnԓO(dle3諴RpACW 6 ZT#@tt~Tq)y}TF"].HOw]\0uomHkkeV8'H7ljXfƣ~옸)\߂cF?+G,dRDJ?VFSo0jFGǀf4!vF9Xum0 hyE~.ط|]׵?]0cE[u͏+֬ ??K`2RR/+˞}+x"gU'FofǗ] qTF,ZVV1ա~לd-KhyM>Sʁs66WJ7hQ* PL#3#d۱.Åܜg9 O ujݚ73mk#405R# /[{EŅLS "~X*T_zLN3f*{x#ig:(M^8jQ:]; djjl54CCOW?-ᛛi6!Fwy?W둴XWPKK$ 55L nݬy%%U4ԇ]{Лa_]F=|~Ǟұ Z?Йcψudz/o2዇ZW#?97nW_'Cgi*w=2g[kxNQV6YgO^>+U\[046$q[K?x|ϘSܻE9wJ>0!nBaKyfr\t<c;y9gˁD0J=jʜ;n'?cQiUWҨC 9)l9"~ KMoYZ񍚴ag{h%o:v02fK<'3[0kg^xTވ㋻ Vç :2?!`l>Ti~Gw[ +ɏ<=SG MFu夿+ض}z*Y}Wi&ɳ|CoTr9݊Yw vg gW=+/rl<u2V;Mߺ4bi'^P-;;t[:(ضv^cc Eh-޸Xi謹)EOCAOnyG!]j2`oU&sz4>gՇNGhQl&*sZYu"x7(V{_%Q3BW6DLsM12n,Oy5C#'Ƥ&ƛ02#T_svv= vǞ;;٦]mܿЭQ H:6.]p2}ޟkvmG/k3)/zY*M յM/uB "tl`㎄;bp ۹}ӄ2g0gVt#. 4WnqVD~ɤ3Vܼ[NTg+༊nC>z8J9Z;he@ U>Ѝ4S_"/zЧn>U?od w~B!4UI/@jݧrc.ׁq Lq'oؔ~]rf}x*8a}-7 gM B B}!0 Ba  BaB0 BB!0@!!!|0y/UKB}y/_y<~QEQ5S!mIS?C 0A! ` 0@!aB0 BB!0@!!!`  BaB0 BB!0@!!!` jBّw32T+).kmVCCCp6/]Sc}}ՊfA@gp毺}```PS#z׵?FiV-l/FC!B-/ FHUsՔ!c g -nQ8o;Z52F& !n!-oc6}6h>z\&B!d{YT+,]*H|&bގ*+^I˗v@=3>rU>n!4BIRݷ_Uz*Cz;>jK*ZxlN {~K]^;k"!7R MKܾsgԩνutut\lܡC%K6voA&o^8qx޽z2fVw*9W0 j/F"g0AAu3V|T纈pkQwTU6.G(éMrTaݺ׮]/'b) :rRse⬝&c='^H7J/њph7IGJ%qVXd6L8"8[sWˬȀÉ#@?'9>yO!7RUX|_&tueHȢׯW$9ncJ_NǼt c@;}յtt؊΅G u4`R#O__bHqh}xM+уL1x fm:Lє!c >D";o>[$Qz}jJe,krnܩzLɟ&-83kڟ.7-899>{ZtnonKlɄ1j'Bk+W&kOr,e]r7o/ķkb7/fUCG_I'/x{ղa dkDDo%߼yƊ`PUUQAkjkZP! Uok$25jw< wTm`>h`ww2t5RSoGO^P lu t70ԴL@|= cZHR~{.|4xg#&o7^i}۴%~s$ (/*hZiB׾˓t]窵Se~Dϰ05rJM ++ˬ,g^::: ^"$)3#Ң| u*6*&~|6f᫏*()ծAdLAr-K]뗠*^8QCѺs5Esi5l{!DÆ 뛙9zt'Х}Y2 9:.AK+w}:/Ϙ{(ӊK]5}nrpm;wl<\imC @n# hq-DŽ'$$$&$$&$;r'0 jY4SL4ɠ~MI }GBV>K;t~+!p|.8]TohQ㊦6p7}051vp}C]f1\?m˓2K۬5xJ W-;/vڔ3Zl4ƌn߾=AYYYQQQ;- w4sӟ[#T(!9mzM t9uem{~ZCn_ 4Msa="O7kc)[Cm):er2Pr9gggf-55Ʀu֪24M?Çy`iiuF=3@Za h-F؞B B-lW!7R\5a7gmxgPWFHUsՔ!c m"Z.[XB_@*,*TK_h~毼<޽jՊfJC d؂Aa "TVVVUU6_ꍬ}8o0@!Ba  BaB0 BB!0@!!!oᝡSp_IENDB`kraft-1.1/manual/images/en/catalog_standard_material.png000066400000000000000000001213061450127457600235020ustar00rootroot00000000000000PNG  IHDR}M pHYs+ IDATx^uX]gfiXviPPAC QQIE;Xvg?]VPPX@=gsv 22!PF  jx0 Ba 0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!@L8NjZG}HSU</99L996I5h]T aРj^OWYYY⟓{mm TTCDc 7hTTT 9¥n0@!Ta 0@!aB0 BB!€ 0rTZVY![K+D(bYB%^[43PLCP7VL]Nr`׵奨/'F.GQ5|f{[&}mМQĆ=ҵpE5E6@h7~hpj]:+o>x9CI5̇NQޮ)CS @Bz@FؾʢsyQ3Z ټmVcuFQk}B"sL]OMr ׽lqwCˋK/儮p:oLB`kA{wr:93+}9Bq {92zM2"520wwfM'd[m׬AA$Ah+ oW֮ɰ9}a36Qw5 >w;{;Z 7F;PX]xr=4lZJɱ2ґEnW]ؽpMb4m)ͮ J3Mh2wx7e_0 ZY ( Hd0TƋˇOyƗRw=Ʊ,Qgʠ&|B>Sl1F>!PH᝕H:/hArO΍Lȇ|L3Swx 3f`F ]ʖv}V&JsQ3Y9jg_ %ZMY9g7-%Mb\lۨ gC19ESl5ũ/'58sOY<7wrټ)jl*op!ܳ̉<;gqVy:d1w%KӜOhޒ;Y!dTu.۾.'GSLa=[Jܼ{׶I2tFؾ- %{]?LB [ضLmI_tKwe^ 8NYkr}OߍMA<=b͇7DRO=nj:kOr,Q=nߵsY?輈~ ޿;x _9U)5Մ->" ='c#x͌ i^[,s۷NԠ-x*?O_ŵrtW`! =,5B]KY :h榤$5:tV I > oD2Ti۱Kquvo鬧A/L m77Q@BϦ,fz,0 ZS銻Υ7F1nQW1;-K5QO%;a3$ٚݭ!dU&`jwl%^fe }"ejDKWo˄}KYHNv̔Oc/.rww>~ ƴ}qp=[4~NGiŐΌ{nDMq%Z&в<ŗThDQmPhBެWoc)[v:HT^Mj׮mRSsp_hV2$)׮vLPHqTO4k*/-%Q~OTfTfF7ج q%a/9 I!)+[z%Ih.>I9\F lUN-s?k.MRTVF&㕥}KlYPëdH$eJI銺y"ddl_:9H05RUŵyY|2kiB7^Ӹ$Ip 8hNf6OAG!s)B^UZ IWރF3ysT r H$X_*p\n$4`IqyeGm*;3PP*]1$s2h+_sq)}C{ ݠz޸I>rN;ۈ)%>D-7-A}hQ\qx@2Y=6.UF*ZzN2En:dь2ݱ;ʼ{a2̴L F($+P9BtÛ|KKEOvM:WRS^#Y6K<#5!xiPSl6=:~ݓw S+[,SmxؓY!"55hNZZ6`(s~װ#`ok)f.e\$:tu%MAhӞG4Ix[RA%\Z6קźJW<\n@ɓVlLEֈ}k >A 9G+'KBfWƯTHP)ҪVu*4]-rpnv2?`:';W\e&|-ٱ, q hP0h晰/y]cRA_[U~b^[·LpYc|YM- G Rz&9o*HGj*Eqo>^xMaNTKEGaKV 9lO|%-Mx~Χ3v-˹W}{L?v=?4vuQdHc*35L:H+7 ]t4"¸KgRB5/5%51)I[[[6LB"e<G0 Ba 0@!!!`  BaB0 BB!0@!!!`  BPG€rb|rB!03LjЩa.]LzYrq*%QUP aBGa ~';4~&ƏuQO;!PD19M:}HvL`gmnoǙ4pCO9ci!Ͻǜ=ěOw[Q!!п€*̈ =z)ehԌ!PN*4>d1;wo>SqTp0{kbvnO1Z 8FI>Gk=[,:z;ɨs־൭v;Qtm3{^iUN*B}^obݪth;&[ZQזb@ȶjTrO`#O6NP66UOYFFxuf,jj/g8vk%CrhW!B.qb9:q)D=tW (+xd++Tn*MOKI[V;~%eϴ-ވ*$U!B} ۾뵾ɋ춐[ZE/ EEE+ sRZ#U~J!?n }7VO`ga0pǜ=ěO®5>1@g_/,Wn ,OATڣ}8X[X;W%E3?gT~5km+/De@}91zΠ]zUfQ{zlo;3 _ Yn?V=?&REalݶ*yA;,s~Wpoi򭥽{@!=m,m8cv::3txwtv[v7WoKg p0t} ߜ[<È>ry`ڲ+_^˱KT{`H& ]S`r{畉*֪a{nzkkIP,\>[Ч{@Z729_]?D`=)W_Z|բqP_.,Y1T@9-_pJ^_p?t`ƕw=i!yr+ݸs*wN'[ 8FI>Gk3Q}qEk[wθcw}v\y{[jA^:(xlu70k;5?$DsہAv㞜v* 1loIw!fpt6OW>x<><{Ka}z5o+`P%]B6r\̭J$Tr}jו78tmW;je3UtڑR&.ܼF¶W˷ Ky ->sts5yy~D񞓍uܼo# X :`tqPՉ< x<3ou{"J/9Ny:޶$P4k4I.[!LT@\͌ x,QKPVCHA?a[+kE;&($ Ku ez Q)]2IlfjҜ4HQ Ժj3) 5%duN*-Ypޫ7SMG gTKWWԠh>!m_li)fJ&~WB?d2-@wVq*@H7stq'xg<͚KKI ?fV$)m{#@ Б'dXvf'|I*JA;_a%It7#L+ &@JJBI-46peFH%դH`vڦ(5;a7gv*>-ZZi&5]O7j>*=%'7qxiiO6ﱽxBk>\J*<޷dd#<*3#PUW-y0T eJI$%_=I2(ҟ_IՇ:>5**%]Bi4Hi6k\&tAiB d++]A w ߪjLHYE!!FTo?mVG MwԻ X8I9h}O7jvbVT4wΫQVȕBHKIAȖx-1J|ΤR)  ~9ۦcCNMnb?c(**^=Hp)yxI75|D Օf_2U^%qh`@%%&JYNHxJbJIBQRRRA}y}+ K1^Vf6crvXFyտ< G󜒊3)>xE崎h&w$*j;~4'--q$7g int BէO-qUoljTܹK7?PTAJla}| IDAT@(扛_ i&ViֹW.DehnFOY4jb6HXJn 3P^#) ݽ4g3bޥiΎ=I@DŤ*g)*=U\V $IfR =_>0O~L~1PI<|)&^cGCt*:(oR_>VD,_+Ӈ?z<'WnT| @Ru+5qdb84F㋧#3Or#ess:7#h"4':8-.&n]3RknF-`BܔTRy ˳{[u9~󭏅CׯM?d̺t`Kv6r+^N'Mgo|orh \Ӧ־ֽdb_J co8xɻ:J 7w}lG}ɓw\fH{S3 A Ft_A@E.7̼=̬6^8ż ٠ukmw2wze'\ۧߝnڨ6UNPQ@67kT#L^]B!8{^E[--\{ˌ7ુ`Z(du73n]G],,]hp Dg:&țaBBuD63y"qCW:N9_j;Jx]+\EֵgD- PtƳU|RGXf m XFfF/.eN^љ>3L;tڵcORiyIۊ M ju# B zONG><*QR *yCugM F^u@=<[oe\:rn?Eyu8 Gˡ-AIWsb7w[[1.G\R)îGQKμʮά^tzՇ-i4mX y񻠝mmzGnodcmږqs}(l }k`';+K Ͽk=w=dJ.}}>&9X'nq%84}ר=N(br]X167dWpdW^ @ҹo/m1읆9𨼹1"y5r~XX|mR-`׌vN}7~~Ԯ~+OGONμ>noze0 4 {wGJ^~%d|fv-<>[c7\;:p[X_^獁M[7>~.KMgj~hEC D$0rߜM pj/;gx>:Ka~;w4'/\GSnիU }Cy'?{-?vR_viF7cX@l@ l6ftVYMwn &$z{ o8zgZ~^[w~~-(z}hKN߼&aC/;xhw?<(|jN~@]>fQm hlܩYFrŘd>n:LH|t6Vq kWS:4$;)ג2If^cJki_2!mj&aس6MZd'/\C mu$}ٻ0e66Ѣ+K_`4\qU3kʯc^djjn;pƾftʎM0$^ OnH9^QBLZyEPXCrD,-]LLWnI~/#vD xnJ>lH{IH0-$8Ѯ~޳g_(*9,4㐾:oCsi/qeQᷖ| 8~a\6 b% %Yo EEl^t ǝ@R]sp#^9@q>fJRdkI2%$IM4nR̒jEoh())%0l%`E4 zg @xKE((+),r> ͦ?nܴ @4N2t8y40PUUeуiܵPIi J dq5M2HOѼ+])q;v^<Ձfjw8iN;vQ5u6 O,\l% QޖМ (LKeiH[|jk,u[+Gۯ =1} -$dLLA+"$K JϰBZ*gOj))ȖܤLyv8LTPHG$l2-9VTN7執GrNJϥfY+ ;‰w$۵Ѱ.JUKZD󋸥l&:ZlP9Qb/3@e\Ԣla!)6:N {W4v꣯ZLrʌbzNOa?c')F __H0ޱJ+ƭJ$n].l=KN׾@}]vؒ crx*#z٘['$ކ祎 Ts>U qCԘyzWY:gѱ0soj?A6&vy  x9Ѽe:Q_xFƷ{]Ok66`ݚfij2LTu\qʜ}&z0e7h~nw[ǹX9_rY:E4ټsG^\bNr@D&ҟ6d4/mr(.-PX)B"#3KFDw,\ZGᏍ ӆlo<:xH޼}p*I VIn.BCCt544+S-jݙ PIP+*B2so- Ba 0@ l B@Cg z83@u 0Dd BL"\Ԁ(+G^ Uҧ?WtRRp?*)9%.a-7.B5x>.*NO/*uttp?J^^U+-II~]-BU o+\d2E:90@L&SăcC7Ba 0@!!àpx9B0'gөcv-F,\ c)jZx ^[fb(_'olj`dbα9%Y9pq'N7/~&hm߾ԁ.s]^9֥a=#s ;BRR]3بE?O6+4؃Oz}Uo-S.uUnŲ_&ʫWyktg߶QNMD?~v掘Mi*g€ƫ.zY/;kSs̢g^sv&;?-/k'Nn!usztc*3+f\"!QwX{~RQһ u\+lHkڤy_7tq{we*oy[uYgfrś woGh83nFITzB"6, /ڨ 2-kѝD&pO/>HkN^p@[UPK ޽fxnm5rA #çg O?!1h{폓zܗ_}qN.qG>Q)E,3Wqh*q׷}e WBEq齴KͫyPql}ҽCaʁyF$\@g߿ u 9=6ꃹ.$ ƌ49V숉%Öb]@Hzl٠)6F2@(*Ɋ`6[+;C^0(!g?$H(/+#U5)9ɉ9lrRIE1/!t'&$JJ%ȲC%]~S)i%*%1V` %UvFBrJOTVX& ҭG   }doZ7Ŧw[GhՈ!Ӳט%THY%oR,f)I%\Z(cٻWVfޖ#e>qmGzTCc 9MRO8:'ZC&CQBo=Z<*[jR\a|q3Im$٨z/EKW ;,XY)d)gIE@u[^ ?_/,yN/ܟ# <}].ߵ1 {T :xY7g_"80HwcsiW<0ëzb ^X| ;~> 8.rƲvr`9&g>?r$Lζ !;ƞy#.~|*ͳ/9|qE-mMY^Q@(; SO*:)=*~tj>G]8oR$d!ۤi*Z5DŽE|,s}gml׉.F滉 JIs0ϕc#ty͓{.$mycQW-[%eܾۘuߺt%\VEO#"t.ǖf¥{f[+]oqlVC_l=.{Ҩ6 ]`pHE#ɽ{ff4n[!!!m544+(piճskZ!E2Q^ U'<7Y|es97PAC54:&fupԸb\XZPEKrMgSBUq<~d)Օ \l; #;MY!`݅rtL (wV+1 {Y0 B*J{~i-[蘘 oWI@@4 ln-dȋ̦M P]CiӧϜ1k.''B5ã%Gpv3fWtsF9KEa{<x[X L}ޙ$ڏ0ؽW/woJǍB3e#G+.pǏ&){U@\ݺ)Wtb& ʝPVj!TU\FAdM[o޺UvKMN+|u. )N -%%$N4(^C_ŃjU` 5SM9}M? 6HIK } J fc.'lt 4''aUDlffɼ9s6mbCB~@6vlql| $I⁸ t;:^F~] [21C 4MD[|*Ε^JjB(] ##󧏻v(^ U˭ҏNqaec"6j܍}zyAhz6t3'NBT|2b?ATJnͫ?_T V̤[X"b& IDAT];vݜ =пEw0 Bu DZgB!Bh`kDdg=ÙBk9 &c e"P'##&\JJNf3KkBk:::F%//ߪpEM0@ul6[_}nnpſKRR!T0L @F!aB!`  BaB=|p>g #-ݶ<%\Q0 Bu55HJzӶ(?ZD.77$q8" !Tt=g!0 Bu/7!3@ !T5$y1 B2BΣ2[3*lK>4c- a^܈huoP!Dq#E033B?T=ZS`(tqS|'p^f>Z2$)&&8,Q_m 꼊"#"UR+"(槥srh>Gђ4MSR9 ]n_US\AE43U64Vq( PCGʳy ܜ7<l@ŖLCMl;ؤa wr1Q+^֯}O}YVۋ4bx}6V}'o󱀦@ u !9Xʛl {qC>So;yDFfpY=0Y[ "F¥P==] < ldh(\ZE83@!7Bu]ao- Ba 0@ l B@Cg z83@u 0Dd BLddUUՄ+QI,ypi 0@u^GGW[ҒIfwIJJ2"` &)!0 Ba  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaBwq1T3{iQ),)hT*ݵ\\k.];WKTTRBh&ڛf9GIMlc_y3[y>yΙ90 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaBD$.ErrrH!\D)\' III=Mz"u0f¥!*Q/!a 0@!aB0 BB!0@!!!`  BaB>KHJ KB}yRR¥(} ++*+B}aR:u"O= aB{aBaB!B!0@!!!0 >OII@!IJ;w_: a,\B /HLNҹp0JL*TT?˯}0@!0@!aB!`  Ba7t}~;Cud*mA8}}0 gQXYڹRB=z2enfnm:f҂lgѽ Qb3jS){F, +i+||=ttAK \zJݰsg3-EBckԃ{7.lzƒ-$-PW^vI|}qo@A]aʓ| 5ӖgKH)L\dbޓ-^C[-tɓ=G^ywJfhw';{|A?EJ(uvQ ty.`&pal,\& 2өk/-OMtnl]&.0qqMy2N,W}Zx1o׆`KO:,d_'BnD߶wo;w#g__} 2N! ΐᖔ0 \tbFܸ|{+ɢyNqԒ CUb׎t?=%%%Āda%E)gbݕU׶0( kcen:nUQk{9:@Gy6KAlCB~RŐQ_ *;~\w9`u4+L^i0U1E"Tzh`,U ֮ }+I"NO>87]IlYmz}'G*BIq @PR\&!'+y!bNTZ~7D#m\QE% ,RTPEqg$KP]!6nh(9ȧo#pF;]P\TҠBP_Xzg2A %5h8l99g)HRBCUåjà {TPD (૞F?fz(BT51y3W=bZ/TI-X yENhl0?v"x.;DS)+C:x?͚I=1-Օ# RvS[(٨i ԄS UW}S,(mg@8KXtQ> 5nqC S?QB<4\3He[7'QTu~rJApJ,a!1]"ĺ:ڳO(&J xǣf=K)=7{쾲}G஛(͋V/!={Ye5nq-;evk!!#/Gd&TmƄPkj V'bv8mtu2}='X @Xy˂\`tXI5*M{P)ImF?I~q$T>i ݧn\orS>J6"Nu{Sw\SzIvF.Im[/CIuXeROAMjeՂ.!bNp0-\ЏĢE-[^GBH?635.@L0@! Pn "ÙB! B!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!_|>FDׯ@EUF~ C)Bǒ*KJ$2XCi&; +KUv^Az߿41!Q ɬڙD WMLHdSa2 C aIt}\CC0;qD5kea` D$0":_pAaTVՑXS啺61I)FlգizԨQ/SR }xV8ۙ .ok죶EY OTx o;UOx妒Ь*-?G%S/j?]t667vHÀ5JQF^Z]]-\4l+ö?7,- Ǭ' KE\mճWo}OZot%$=t'ڌ'w&Q>L:I,a.Z;S T'}q_\ع27gܹ\إJ";ވlvNMv66^M8n} &rHL#ns.<7ВEG5}}_})B}'W עkG_ TG_kc+]`o3eOz;Nnn ^^p?ikY OGׯUTUKߡz]d".GW/;w}'҇rsgo1uÍ\ OM|1͡掏 ~r#qج=[G05-F2IK͡#Gn}Ű Mrk?hީt .yr{?k@ }AI%4gS2'MU3SwRb1Ť KT#Kdgmiز|n`kfvwqw H9`g~>UYNO\{)vB0';&!| a4 kz/vjy55ͯNQ"kÐxfCx=ڑq@cuG/Tv1"2hKI-v :}Ƭ ݹ8srf: w#0.ﮘ9αYq:[;iTACNU Yr{}NdC)eCu2 eJi hd*Dl[׎MRnnI(8Mp6KݱZi0⟅ow!lu&+φF\wzm'\ C/@|3:VO- ohPw0~KTEGB>LjX* e[8qfJL de kfA TG+S֎lۆ[Zq:ggmjULi/f7"Y~(d+j+2袛yNqԒ CUb8&IʊͬڗG$dJj5Mҝ,̴H L ?I:xzDF& b#\& 4?^ZU\C&r䪩4R|LOϤKQ=f#+3B8VB—I)*3͎u.Oqhp25u#P1SiSEEăeUT ۦQ}zt2FY]@xmom C@j)AvNBF^..,A(ӗhNPUW=4yATQ}G?$gWhAwߩ5J~y1GZ% OHaЮF~A!? TUTŅ+"f'<3ݠ? ݾDA7EFD3= ?/R$ո;};J~^KZ|Ud3Hˑy4ԟ>!$z;srH$:W{fLOx` 3 4휤ƶ;7{__"de 4 wzti fou5 :CQQQu+b9Fa~Q]TvpQܽA&&=Ve:ȉ~S . J#R[YF;-kzN 9E2zF:$ C5;8NeN' I*#m_ZFPɉ*G YdUہ)G $ASjxtNFQJJnuyA*kӗHվNΨ@PMUKݲ]p 5XpBb_%ee S @4Tހy<h~iֳB fvfAG4rإ" 6>sf@W6ր@*A=%mzcNj7AHcl,&}u@&d߉)kcZ]_ Eǿ6M ^8e_{iRmQ ZE1Iݐa9 e5P $ʌu oN'b59Ie'ݘ76Lr9bb%}}׭ },8n[DeI!sG7a7VF.^Svr)_ԍKƮ@(޽D'tRlui ?#tbbc-{ ,äĤQF5AϜlY[C"W˧J69!ݥy%x/ܬ}nUVyOo={ = IDATAڱϨ\{jtUvbr$@)- Z3m\ &7 0ze%>_e&^|je; /x[^c-BG uIЏp8 I  % S/j9v}_Q|Cll vL~`'~Ξ37f ]5{5\e5ct%ⲚƶX}q{P7{. /LsnZ(Pvy#Vj8̆.}x`x/7~vS7ȥhM|oFmVp%{gmO\uY) ?lq7l躷!.wKҴE~u.Nv.#<j?FUtv\yllY{:xWwZ)5N{eplqIE] R$lm+ܜbV J:s2zfᖐ=X6Ze9U4sfJ-U M'v}r!$m  }<4>i|C}l\h=qk7w ,=\tyy7w#ܪqOk =(6EѠjWwz#|{m4 R/ZvCi[;DamKi !K_~8V'sM0bYq&ܯMzdѲ[s^uܵ jG}Fnݥ$`ÉơS.H ;afJN7zRwVD7}υFM8ӂm4uj0i,ҩ/[vq^C<*,-l$ U8%r/}5 .X%bu*+'u ~pu ; 7QF:շMP7=6\̫7h 0@:[iN SQtRJ T:Pon^h+eo+[AjXkUom!i=mPq:/n q̔LC_f qnoV{jIb@Hw09뮬ؼ"`N?xkհ[CJ=wPx9˹g m ^=c4fAc-JW(qP#4U x!zt'񢘀CńL@ޯ6 s;Hy3I2ddFV$(796iE5RFNU\FОϹwt߉">IR%|>o)55ֆfn3B8VB—c  8R**캧 UTbH)Eŷ &I .X]]QUwvߑOr$ b#:PAk1@j^q~m?`}&b6+zy'`־OΑ%N4' CU%2ݧ޴a-d5Ds}$yy<)(ACDDH!#.ϢKzw*N_=A-) W_EX$ @8%մ:$,^e},`: ԫ#b 7~d?&ΓYVa8Ee5W1~&xWUUf9@?6bgۯ:f~Yb7 O W-p̲ZΨ2yIHe'ʀi;2TFJRnQp5fj7u]b(꾮{{ooou9)gk$V q&K7.@K nЅW7:xzNY⅍k&K%cӦL!$5M\m&vS"\bbc-{ 6^Vty꽸.} [bIM$݉v*}PTC :v$F=(յ!t@zK W|bzyD ~?3"_SQYGA].9^@;#pjd5d(v=,Fue??A|vH%ʆV->B}!IC&vI|0 ;Zv 4b֦,xqw^ e#=Ŗ~@P,t4XA)(He*S֑!Eii9J+TE x%\c f"3^qZҳ*LIv:*3d$=`duziH@g+[^'s(Nt˺!U;lM~&lvfꬺ) )1^Ze dv%`0:ueDÙBߣaoUCRq厦 eerj, t,tk+\LM^Fc4q$#/_yCP E-?< kLw_yf!H.}}uy4>uIw; ͑ kLw` c R0 Ba "' @\\B++%ěԷ\mebj?2eFϛhڶslaζ-\ZEs%:-ûm۴WoޖV]3"FM[<%4y8X0fQڻּ}~\ *wksڦ&]~ >}m'ʭ-Kb-dci4tsr;u՜O}H7'7}cko`O$I:jE凮*?3Ւ&ǽbkȎ%xyeg@R*5ah?tfnW}inShQylS6ч[8̵JWe'&WHTmogF6ɾ%=w\ӑt'ySǗM_s_{:X-ΐCk5Nt/C!IRCC]o`0ow:<,ɺzY׹3\f{l Wz|]fcT4c4; 1Ni>C]1֘?Yȋ`P]W5X?ưCRe&J\ʳלNWFڦ4O+r_L^MҠ{,Gc6 _9v߶mPWvK7.l[Ħz/QߔQCiǸ_oo?k 1LNt:ә]= #MEϤ^(8SO#0@;D;g55;wI HdKoml $c/X`ʡ;6&o'VMQZzu;? \7)n=5ˈP誢jv cW17uu YMG{yWǾVQ.e 3)Ri|7D5[b]zq}Bja89X SšuNSKNsD]:8~f1vDv݆t4y~ ߻Џ`Մ\֗PoB.'j~7_MP0/%t3ch?t/&N؉5AKjNQw'E%3w_uu H~qeGE޼y~E6Cۗ%Fvb^ԚTqAD?8Dd,jWG'A D\z{c˅]t{9F.Esno{0jpW7/r #sSaS^?qUߎfWZ8lgǬ{V0$պ{zZJff /NyO`2~tPYG&ys4[a"#&/d 70~ χ 9z]qlueZ#Uj(PjcTC*+$ ;k\.pKUU  I"|*avԥ{< nnOHk YkGƱ=n3AWί/M^p+8<\Րk.k:}F=cwAהeǜ:}ː ;5_w@)blݼ}W]r^r=L>xfs1sxXN47/ԁPDa9zܯR{zʱTIywa9CMV4MAѠa| 04e:7p%=z0-:۞SBRtKQGU.{P})u)>7f>ÿ6{CJС}NJojB#h?~1lTp!A-L{XW;ZA9).b 4>8"vq#2S*hTu3ybkPj@U''len1ێ./.u"tˠg-<! [4MS9a˷iùjFӸeWrx|nĤ7%/nK-мީ1(;ګa e]vㅬ<)xu=.K,5xǝihƙB T?gPOFŦgۯ:f~Yb7 O W-p̲Z~ʍU,[JZ\m1ێ9s裭ettutj.HMI"|LzӞ/F C2{Ucy-:;}բ>ɔR5ww.=ӳ:[3o@կ~@ꋾ IDATM ].ǐT2QN7S"\bbc-{ "jf;ޓD ~ QB鏓txte" Fw ~3pfB!B!0@!!!`  B_:C}|~bbRy{$t0 B߁$-m-uUUWNNDc._2!>EyEOV^^.\` 0@!aB0 Bk{X+0@ .%K/Y^ZBxuw&&= BHj6LLz,YxW` )`ccݍ5C~&nPIP[ќzmܼI.+/}P3B\t~!`v}8-#"BEM!&),@Ox$2tM9?h&P#\ wWG ӫߵ{v#t7<)C[I [!U^N$9%. }ati /S:($=yϿS;F8DǑGF?yĿl\ڞf0IvH*Z:7J֗Bo6ߜ^=Ǟ:贼2)i㏯^uWlDȺs=.+( ?u$xʹ)ItҲ Z}!UUӦhqqM"#U"NtuwuWӺG60xMu(3q5կƿ*Ǣ?,BBFI),/)tGrRBuꀔ'OX4mj+/Cc޼/&}řQ).@1潅KB F$%IqV[FLMK?ȓ!~n $1<BV,uzB}&&=j[H0@Zx!B! Ba.HKK rrrj1Q2B;ŋ$t.¥_ B;@p)|p!B! BaB0 BB!0@!=vD !aMD}LB!B!0@!!!`  BaB0ҮۺspEkۇo?ˡk>Ve;Ϥ+ڀ.}~ >f[5U}3yf@RQCwk CEq6utǺI•-f*FG6& ]xȡ$IK R m,;3lVޡu~t}c5|-;z)Arފ-1 OWc. Ar Ҕrp3'NEzlB=I-J(tW):qAaA(u[G&Pio}]*TbտH $ݍJȩW1vXWO 6(1RdaO:x˩ ҕ&>x\eS;^drfM%Ή(r5RjI%ܻGRܵEց(yy}\+3j•dGv L*W;IE:F5oG99mڄWZ?BѴ-*$fLycӡ2<ʮ<ܢkÎM0Qn%;t6owȹlʰ~+w{X;a'Ǵ];6\;BBD3g^TܗN!@B[M<1q4Z-AWW9J6n=}T.4㇃4G2$x.aP~  WqxssO94UFKGK/{'x]\WIkLǧ =BLJ^euc巯e'epAVS.n s=- ޗK<}ޱj1q1>o3wÝ>[B)Km^oˆ+Q2CG~(9:YWPr|Ŷh.!TA~PV窑ܼK';)9.ݥۮҦERHŠ"ېcl!kQA$e1/({&K42Ȓ$$Zn~JS_,}s- _g=t]6OJ;^_ nΗeW^!}.+f;n0-{|ǟ81UKZ,anmNUy=fDŽf<)bXU  lhzm¨ӧ,"7] J_FLFq!?q{EUnNĭYM%s."տ8tM~!\X,Mkb2 OHju/=}y?M'6hDoJַiL)޹K2hŃ|zUE0LG!-ٔjXD' (Qu [.U*m.3(C9].֌;7r5Fzzhiy^ @W;'(t}D*z|gRXS["NEф4e%P(_:ytPiÛշϥ waryUX$A!,We|Z*{{aƥՏdj-yv ͧ;j&@v_;;Nxe3`Zfy֕jҔ\v2umFBm`+.\{3 GCߢإ'lE>RÒ }մ*#=GcX'=6u{ R,+vщm@ ͼO 5^@?}&"4LLPETA$`[MlH}uH_בaI;Ւ,Bv>EX܄IO%ߥ7OX~Z$5FPn`[Q)/2\ˈGzp[pdעDX0h^rle\NZRoJё&1ls3+~0 [1肂Rk#oEM| @H$ @CTWEe1Z\K GJT# o(j |6̶Ao=ڇ ڬeNТc BNȤ2lp1@zj¢ɻcnCT+W= )<87g/Oe͸YOGTSs} )~fIUr!6*#`z9MRt nFGǀf\IP<-,R}$Ruk>,P4H((a1M-tOh HAP)Ef9-:m|:,y^3vr9-  kh&~W77l5B;l9*J}t_GҲ^Be .-(@05̻t痖VPtu7=C#$d{g>˭c]~IGqeg5FPWϝWxvwR)&M7zOO ՖUv{x϶j 5l {ϞslGahlH37ϸ{v1fso9-Z=ԳaRֹ}-Y  yirlO/۫|.fp/+&ͺ^(̼q{s_K{8rFB`eeH\νPaicIoY.Vsk?Q-5hb7-^}SGgQFCtIff̫XytaWP=j$.:^*+u>>DCGN ~@Q]pߕl^ wv-?p_r9݌[svg gG]+/rl.ey|_+ njy/(XN=}~dKp 7zZ /l}pl aϐemnPβ'~YǼ I5ot7㷌䵋fFt@5cvhY0|?6T9uA}Ic+CӴeu1'Jq;8n]3<CĶXSfb$А+}Ύεs&ڴMvU7 9;"Qgq̓e7TP9gʩ;8ORc7t% ղt==Tȏ02}6B=O= B!0 BB!0@!!!`  BaB>K%!/000gAxgP @4M6og!xgBN#Cnjʐ1 B3ZK(B-@ \r#UUaBj薷1h>4M>|pbb^^XYYz{[SFa d2YlZ%%%/I$~~koG}7nΓɡKv@=76c+sU>n!4BIҹ~۽gjE=ƾ#tsnQUȬ^v=.z]DJ?F#Cn-uɓ]{깹nڸC/nނK8о={ts;hԌKnU4r` "_D"3w. QE>-`e gN%7Mt ]KERU[.t ]9GNuoRmCIuk, JKK/'bI :tRse3&m]^87<`_5ЪoB_"JfϙQ[l3Ut,|ppouj\-3AK4/>hyNp||#CnޑqsqqY (ڵkU$I5HbRר"^x1>Z:vlE]y}#{oԵ)P"F{}קOAwkj$)H^?kWo^|&Eߑ?&o36y"Szhʐ1 BI"Ξ񖇽3 @~ORڭ{뷫^-SCЙffWONO[nDtJm`P7;wS|҉Qjfk+W'kOt K:m\XDonͯ[?q5>'E:yl⎷V,P9J?BI6GE<*V"̞-h, e0J UPU֛ º0]F"S]CPvW|IU +i-]l6qWg3n#@ju̿VKWCCMLO ׎a`+IlwŢϙ sPFk5edDy6b$ 0PGW'$8$FN5DEPAJ+=%,&]?W:/|SjlXYYfgeiYX肠eaNYY kLAQ5q^}XI4_aWv $d VhY2^U(uױ֎ͥjGTװa;P 2xVvZ7zOPۡs%Je{.srP]2 mSSM>}W$t>^qwQKog'ea ]KVj׾MS7v_Q j8~Ֆ۶n b6RS[ |QZ@ t"'%O:~0@{eaN4oV7% 4e]7R|~ , Do7V B4uX *>HU=AnڼY%B p>>>J_#yBDy^%T?|XVM[i1z@ ,;v(R}ycbm{>ZCn_ 4Msn]"O+׏imICl*:5+'"ʅeܹsZjjM֭U+>d6h>x$_(zxgB #W90@߹l52Z}=9B!0 j Zخ@CnjB-BK%o| )C0@!D\.jE3U@Z F5wTWV4S%4l4˗UUU͗z#k0 BdB!!`  BaB0 BB!0@!2cIENDB`kraft-1.1/manual/images/en/catalog_standard_template.png000066400000000000000000001074471450127457600235310ustar00rootroot00000000000000PNG  IHDR}M pHYs+ IDATx^w\]a&!lōX ""ZܵUUZ{=^:[ZbuV n&PEH~%sw]{><&%5 0 @ a0B! @ a0B! @DbaS"#ssUKzF1l5kkEVիUV]b3SSaT"#Y[ +[X[[ + jubRRMAT9CF@8*rC@ P ^aXNXAiW􁞕<_ R^8mlO󤾹1g0ZZs;Vvv07߸k8Se.kò,9 ~y\8Ӑ1KjٌQ|~ͳS{whj"""FZuK"Z#j> mw.U"MLٿ?jx{i k*Fʉk|pxgth%,*Ja@İeV$ [_XM&N^䝞ڷ~fƴ)#_͸lÆsbyeX3JOl }BfEhᕗ_穙*&9rⰤ}cNgôKviE^chk>0,#""aaXH' k|ˤԭyLP\n|ogLӀQ#ܪq)zvFϢYü\Iv?w/hPPs.=N ջiuruMMkߴwIw6NX8*秷,535k󫯽k'X~a-sVc M#UL[ҿ~x|ˏ53;~_ie.& ,֎/cg_6|fm? DFV{CcSuf>SovAE}k0VBO^Lur7aOpA_ AGƦet[} ?qONŧN8Y{`o5gQWd ]L\66 je=5mF_o:et(ޓ5'+"xۨ!gDfmܮUwe{M[enj6fE6n0wxՎkr^gܬPVku7>oǟ>OKHtfٶ훗O֪L/=#o6m]=={Υ5~$2i>jϼVo۶omZAFYi9?lٶvT'vH9}u: ȉܿ9̤W^/4T;; I'֯<}憭~Gc8>/(]g߲u˚'׫{V0K.Pnxk'DD3|uM[a楃wSٚSKOi7~+F6ihKLa>^ܒY l= 9tmŤcݹ3:4\MDĘQǀa 9;X:Ș%I>_ݥ{u k~ĥ$y֢B!]vk'y>~#KI^7jѯ٢BVxoro"qۭLG$Wn cP˾>K] [ݴ"-*7e=gN52ˌW]CXF'{=ޕGzoc3&0|ˊeX|>eIO2ˋ]W޲R!Ӗ}}?y!7i$&j(Ǐy'#N?4Nk@^6^DfkS/[^ĩxg[O.]Mט8P")r޼Mo4Q 4II8U..[MD&'Ê҂i q-et)-'i~<yxVJzi.9!9^;WgfTa=4ò,khTpϲ,vyj-QօuC\~aY>#FmRx+K>5o͑ڲ'm 눿z:<"bs I(ȾȬ̜PӀ>vM/d ԤT P nH\-=9J¨.fOAMI;e:)/B,E//P]8ܯfanㆴ^\V+5Sxb2O YIIR;C$2muXSOioD[Ȗ˙Neaj]rg >!dÊ̘R+C>KDE_4P&nQ_ .hiۄ*ORu<׻mégs^[|߂|m[z3!&V."Nt~cyr7*Y36v9r?#r">^z;[~%.'$g䎮CIt폿ttfxb-jIƺ d\I T(QMgn* le:թkC|γ4"ϖػ sRCīnmBF$HS-mPtZ5t7<)c3[&0t>6g~[ ^]Mn1ƮC͝nE|,^zBʼngw6nw3Zˮ߮Pz~9i14sٞ?v/ U1z&թ'.n0iDԣW#kԝ;V-%Ol1; x5J6׏.I>\i zV;֋%""Qν[mW{,Lrqf&ONU4p1w=R?TTx[KGD\n {5ҩk {>5tV|GM)7;|%׳h1]YJ>9"]]0DnY T(֪k|BTS;}7ᘑA͎mY_$""Bvn-v'es:Q_6 aRRӄeoڵ[V ^8`}1)4,Ʀg }l[NaTZMka3xwwY_a)3 a P@NS*EUW^^^JJяsAy37ǶW>Ca! _}A\KX$&$޻wNX7L237= a0B! @ a0*o-1yyy "5ˤ2"! cRM4%òº 07Sdr/@@m dބI9PZ@FڿNmr37vcdoڦÍ@y93?J}y;'>-;))G:2XۻևE㔃?,S&e:VWX:s[ƒ\MC᳦`+9Iԫ]LDĥFܼekY#-NZ4pwŜ=wk2? ?СM=)CD|ng#5N5vBiV Pii5 {a$ϓܜˤKLL òelv:Rg/T}|yS_wך7-يiNIʋ?n5x⚙mJ5S=bHswmm.y'<&(Ʀp Q^RRXL I966z :5%]Ϥ>e2W(F#DTbF;H$X,,d(?N=.8M\L`@^ /Dss@O]'WZt~y_o^ghleەl0 n+54̥M3Erunnn>|9#"^8ܠ^E|Z}=x!+Pfx;ݳz:;wz剸rG}_6­Xʮ];)CDİ)ݯgSv䉈G{WOW'ユED20 ٭C>ןH;o?ݻtGCT,+iJUlё+ 2STR5j2x"S #">/gO:yܥ)z4uGh4iiiūïk4Ai5 Jwsą-r"p7}OhxjiY[e6\iv#وnآ PxQε4ӏ cFޱhst@wЏaaG:'fSגMj#J 7w A,tp'vD4[ӡk{:q7JzkٴK}&͛ vȴ:cHTnȨHeZZreZZdTdݺXAx+ڇuG;L2zuO԰8p҄هLiSi֞V@@Խ݆~!%0|:JKҵgo<戈}q]tS[0"So/+3J=eō>bKKgϔRLQ #w߫!Kk+اa`Ɛ%V֢}S0`kw^]0z_;q)]J>ˈ]le MLZJIIJ(LtFʄ'UD*).Uzms=xVϴv l'"FdZP'^|z3*#Ճ6e3}alCe̓QYDQCIbr㤨ymaFBZnjOD qrlĀxS+E YGϔFfLOܻ֗<"?P~R]C;Ri١?&lZf yԟ&1g͠j 2c!Cwd.R?!^yϥڦ]O4b)ڜs0Gzy~!sek3g =ݜ;X(WLf,-ݵ]GOoy0`ͻ|5,8!w㗃z /1염 fv`Dz'oc7%e=PɊT<u5$75fKSXL'Fײazv<3oܸAAY(,yQ?&5IeˋhZ;rS"S2p6*]H333a)TDZXQ.^rtp}ޓ6.!?ĕNae aH}W?~+rK9FF%| *8L=hMڧc+dKJUٹao`ea!'HDXQ2e I$cccaiEBko- d@a0Bi99975V2-[?k("f,,@DDq o}[4aeeqaiv@%03p?$,o?#@҆kC7N"a9T|nk2ќ4.N:|'kO{|>aTݏV% tiPIFnz&u;\me=H2VLX\j9P%Vi>ȍ_[H`\ݺ>qe.J#mK8j IDAT_fV ki\Pk7~Z!̙u>;'" sL[}/E\Ou3VClB7sj[uPjZY^=+e]JAThpw-t^WOtoD8֕\6 763\ƠkrzΜ&Yw Mi)1 ddpdhIތ0-ȯtVC-RǦ]bGg_m aШ,u/- e""R+U9zzDDDRy(-9ZQu}rO^XND {F<"~j[FVy;sI P5U0};m}M)wv5б3tO_|IyFI\Av0mR Us,cGVVƿ(XH\G UM`~sʹJg#ݍu_Teſ\S#WSj FG_~oӂB2*Ż^C4w3xHa&i/\@WqQ=="Cʉ8gkCz C$ W2!gD ֒+T}dp,CE9! :EФ5wU L֭WESʕ G:T!Js52c^:eNm0K}帇1 Ҵ ҕWڴ⟋\_o-(ĩoկ::ED@+aUF0a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0B! @ a0Bi? X',bccYV$,`baAkټwV,۲Esaiv֎R=M0B! @AES^VTuv He2a@T0zMjŠ...Ndd uoRզ222>$ "KKˬ̬pH墪 y~$>VFZ|{rDD4ra1'ǼUr97J +i-hJr >*˹ݫ;z|E` Z4Gە[+KQgk |ejtx7y Pyy͏p+OxS#,gc{wt6J}A *ӳ=S * [ ,xU7%Q?z%u, #wtKDa[umfz >8 ÈuV 5YAԈ=~AB6kdQeI4.ni[Zvk:Sn WN+NUNjNmN|69"iF}ykrp$iRGO[dңMu ]}^=zʥWRdĭc=wKgDGghn/cY]w4ͻm76_7ɠ>18>mܐDm$锘=8ZVy€W_?/0|wlͣg4b='{^Ϡ""'aV}7{x?Fk|7ܯwY Ut1|CWmn..t)SϬ8,>fu&,ˊD"ea 2fH;ptmмCLŹSI""">-|׌^oPDJvĆ/z+y;_{Ժ|]+4 ç߲#ebN - %z{L^oy]IG U|1nP޳գ<;z`T6w>]]>Ͻ*^yy|<:/ +tJ9xp!7+8Ğ -4 m>bH'[kYj̹GgwWҡ=4w~CB[S͕֘C}m69rU7n(\~ƍV};r~]Be_Vn/I3OW'%`_o~ ?O+"xBȶׂG \;6_ilNHrWVm \lc\: !"N_ͧ #Z#DJk'n %"SlZrImtjLУ;ZkxсSvJyp Sۀ%K7{>ivoeMQǭրK:wZ_ԗIUʫ\~4Vw&*؀yc. Udf ak?lp'sbky>wT691so_3i{71t,;tJXC1|yk6Fpe~%rFiOu{6sMn>KL6ˋN/2Jv1=$(BEŇG4UHbXFcɓ""F\r}=][E{;C6ZJOx^\,`HHyYWm^$b8{CS|Mٹi`͈5)IdniμZ9`];~zװwc"MYjU@"Zju@M wXņ$T44)ybK>XC "1kޡ+5QY""eYXeY4<{wP\q,%WH\ͫ " #5U]#RHj"e{'ܠ[׬+V<]+hTa,Hd]Vrui<+R%=4yQ6hvÀPBlGr^\Lы( C$LwHR>)>Bc;k;fMƮQM{Jf> `̼yhM1&- 99^o)M2#x1D3 2>mNKUr/x'{X%oF0g}-V=$"۵jA.s'OFYX%mSwbe?c[`HP(,z?ٱۍx%1̋ä}.Vj!q~4vzݱ+σڝ&b۳ OUܔVv/[#KbFXv|IGgc{734D:Uj{.{+[79s든)rO9yڎrs2ܺ,kۖ *mل!ek*"Rdž<&bQ\<UcKŧ̓]kO爸ȻϲJ} =*# Sn=y?9GʌF}gAܸB;to/e>ކ!_W+ތJ*6qʘadn6M4{Uk9kdZΦրE 5-tl /3gFRXM8wiڋuȐMؾ[<{ ='撞y# ؼ[ m\?jĄlVfӤCE?koZlݮ,)Qu/yŲ!^O34bmVQhDh9k"WnRE锖VǤ፮\Ԧ 9ޱcGa̙3M4VhNGhV{%^Ax[\ ,}K%_\@y,+b dh*O|]ͳ7Uo9H٩{?@yjaPɍ5KHV@b,ʅ:, 366F_ xUs|頻6Md`gaa!ebJP6U- 6irHaEU'JmmI$a@T0͚gdDwja@x' d@a0B! @ a0B! @ a0B! @ a0B! % P oIIM%FFfef +4hЀeʾ7L @@ H,,x{j:***3+KX@ar(K+Ks33aTĻ6V "B|fm@_0 @ wr=9ybPp6wʑ^XQw9Tr(ۦ˽c[׮!+Z9jئQ/)-Xk1 mn9psQ?utuޮRy>-|׌^o坞5vةܣG~ڽ[wzb% =W8xeخs.ncSLVOg]m #{zg'WϞC-7Vbߦ~\ݺ^3.l0KN|O톒'*Ъ"* 1ӽ[!~GD/&DzRϬ8,>fn-! }qq׮Fqu)*ThF拏i<*"(4ù4)xބߙ7 >?0#"" +ŞƌK>fSגMjj?[t΅-~@VR_[(!ÇI5jKI8xP3sLsgZ=\3o;aq"Ěwjpqbfqk36U4|f˧o^l ظf/f-5-kNcyL޿.lufYkӖ6|MƬ5YkW/i*g`Ywa^?c:dH ށz&l_ԭ$[cRRӄeoիNmZ K*&eN:8mHZKҷi"wb{oKl?va!F0a0B! @ a0B! @g/ju؉1ϟ'$$UND"pQˌTrX"c7f>3 W^ n׶]KjիQ̳EֲE ${= yWש/QdIw<v"/^5ed_ّ]rrs99Z@K=̼nTqYI ̹^OZh *B+Wދп%  U yg{YG#,/3?wZ!IxLC#Ry>;7ZjкM=R"'\$MFz2qZGiW.'r|j.9~5o#5r0Xu_Ksig]]9%:ʊ9[@(iu ;q]۶% yɓŠ|~:s_p1w3!sx=8E䕗NǣҰ87VmvwsqgK<*`X5kFճGQ~=FlT-TrӝC=yjW.N}3n_8Gz#w %^A2'_j 1bKh܃=Qpk`'1kNʼ-q)vNkv< JJmytxOwtu[Y}ĝ_!{zg'WϞCplչs!?_ahABBB{2>!Q*ynٽ')Ս c^ÌQ5OmXѝ`H}yu]Ӷ/uuIn?tu^_<<2Z""˲ۙdl=\𱰿9ᇣɬm%;+j]sСMCDy77O\b!'Wz>_;qSx.I`n:waW_h!*~˷C!qQBM}}fhoaHצ]Z)/Puh*&ν}اѯ ҭخTLavqQG۶mcG6v\{bs1_;ה:ٗgb}5">~#?p+#-=>/}z\ͱ4t}Y\ںtZgI ƒ'ǘҚePcjlVҚǘ +6Nutݽڋykvn=K([_"{}8>]CV#4M7`Ȱ [{X3㚷c[ǡc$c/lnXgGvG1wnzϹeM=K`BGcB? B!0 BB!0@!uyk)EQ3D"C?ŪMx́Я}%Emlsdf~ӕ@bM$)(`]8Pݪ0@w" cUI2*=h/BtimGQGFw/תi"~M{ޓ"R$g3W~zdG߱oD e]6C-e^`ir4jZSoyޛ( U&}&M䋟y/Iu{s/]W@ٸrfmsU &8v-EY=?,]pyϞc!Qi3{_6,zv"A`) )g8=a$KX}xʇM|ȿnɋ?x$ A@K‹; :rd.n{ݜw1l/Mzd7v;1$C97l\1Xd)7q30^^.C]Ld6kPgg;g@iNCޖvW̆.|gО^ۻ2f,0Vn>^=}C+DIo9sn×-$1oG߹ų)o˚G/_x$.,My8Ra9^Sr+ Çw?2J_]w^7JrmME= vqz%ϥV 䴙y2*=M4g]ݾ[th9e剳~υt/8hBЩ@ rB.ҳ&n#r6[\ϣ[;w^s6OZ}!^z EæZ6ЬSBe_3BV5CzvٳǨ+HRBOlbXy\o@vԶ3 Zi6H$RU>9I(his2հѿ_wۣ_NjOHhִ)'$X4j*OAwZj\ hZRR}S$@^}7@ MM5@޾RN e*ֵT!]+ce-H=+=05MxGܺrf;-99#1p'SO`;F puu,mVr:涞G4B X94D}ȣA YeK~Z j?Ͼrɯ^ꗞ46c.eS xN4OEZVtwiWj3}]uHz-5;0!+/|A]YTEFvWd((IP4MS9wwwTֈz%TH%%Iz~ 2{$]G$$I8 )6T3u#H ٿtxJM2ĹMdT")hiq_ѢsiP ?V0$-|‚Fo*eT^]A7g I3J&F=#uȡW,>d;H -[?0[L>6彾`Y}N~Щ坴|CVw[_&oX;]6zus2IxD5;sRI]c6tǑ壃,k!|^X;nReP + >ZɋRT2?WǮ]7c=B㾵 >}jͯ=so.*,>3Buoőm նrp¾\y>;{0zCS]Lͨ1W]+F[-E>}344杇/ Pܔ{7CCnܼeFQ٬uVhS+J2^>w3["rDO'HĤU 4MӼG]zkfރ[v,*T".IKIӟ=(QTicZj #8 ZbyyɏgHhiac 5b]ĜY>2r?O?3En-t?1AДHkjRExF>OQik^i [6T OcTMJRSkao!'̌~!gRC-x2jfoʢEbΧ,u 5QMUUUOG(;4q%3K)z+UQ׺];^6pNٲeV3)o]Ӫ.N~-n֢/VмFʹj(4/~KSzrwQڴ6DžN-d.:;D+kn<:G#leK?3HѷQRS24od RLgZC|ODEedsR$;ѽ@jZ[hָ6A7I0 T8rr ZK}4FZC(#~\XB5,MkUiajl*qRScd-4R"y))"%Z6ie'pm ت}S@sҷrZKy#uhX.-LTjbcDj֢a||4Za.'r OS ߐ@4nՠ))K0h U30H+t˯З^G?VnbcQ1P2hbkr&\El ؟GT**q-U_O<"yI(zj0;X(MϡU Z" "e4iaʠRTJUYƾhbLgYyrN҂b!Y_IȨjEFE"gHZF6LxiѥbGYӨ8-a^[[#xSۯWCj7wmYOuM0lt9 l&Ą)bU5nJU| 0 2,MskMsBIQ@EWCl50[SI߲l1/>IF^~4נ y%*LyP֘~ 55GӕA̋ЬiSL~kQ_jOXc 0@c?ot!ЏaBjйWx?C]XRG+.-e>M_ ;7vQ0}+&ڶ}CN}S/GdI8Zmc߾Y[2IJmjFE]K^Մ=;dTWVvΝ9w6ӡ픋~ܠ4Ύ{p3.!zsumG,,,+ ɭrUwjgf~'խL_c{= H$:6dIJMݱ@^k5; mdk0䴦P{iUhEE}'0npg4''G 1#׼]w~0=4\]'ɉot+?yJkz5}ې$+[/d0;]xq6w[>xu餃ܵHI/=i3mEOsd@c[~:J;p;'ku@†{^H Z\W9m\՝[1uf7R0$ ]p9D{:$ƿf=o7x]ĉ]r:Hm]|Y ߶[Ws\Fz1NXESIBhun_ EŐOzШ54潆Yt9fBfOC+ym2i;y+a9}] "T<FW) )6n$Ltݵw|nWv~Ysf?0lֻn祤 q,̎ؠp|% KZ\,M=V6ROiH1lKU9K4F@eKGo%P\3:B}1͙wgb*7I1hc\>rMt3SDcߑfhȗibV+|p*8\UZ*c /+ R>JLLpA~c!`޸0ɕ*Z c|w7cH%%Iz~ U*˓hX(KϧOՃPzL>aՁEٿ4`srZӪg"{N$CZڤT24T?bwE%kAmf5m[倀/@@p+s<- Op9@*/r95wVG//)Puħrnn:ɖ271LlcTАxP'W Hݧ?q>((/*A- 7v#Xݻ9 ]GRzN}ı5'NFrZ-DL=SJaljZZ/Ijr*CDMrzI]o`Ze]QYWVoHt]xޢf!+<CGH2}7|CL1p캸I~UB$4;7f2^Sl-:rTVU}#ko(^~۰qUP/%W \V4M4%0Yf-;Y*ƥԴ::PBQσuڻ1ed h z4>͓R%.U|-weӎus/Bޞ[6 ۬VWy`nsxuhשt7" m:k;b[,\; nn=ȹ}MI`495oCioLvy0}urUvRcDoݺ=IG0ꐆ}Vo(;[9T 1 _9E7tW]M_OCйW|zM9 {.hbivN&^Pjr+.p[MDd%=cD>[okm+[B Qnk${ٷy8Z+U _N,Ѹ{ MBupm <3@!aB!`  BaB0 BB!0@!!!` TVt=#(+XP,[az4d{+ށ/+?λ4mϫT ]J$[Zv&ݎ'lkƶ}gm .}LCMٹw$5xsnuؒSq%2O>#ҵC.N.Rjmce]Zu}?51_-(_gVSx%VB(pC^dԇ{ʟ~ޚ5ݻ7Bhx. ~Ν36O'=\xJhh&+w%s =qdȈGfX/KKRJa?>z}bKmɞ9C{zulҮ˘(wo$[xx - յc~3w<̡@{GWWo;PK]gՂ!ӼG6oHq}Frwuqub6߾8]aO^]?i8p aUX,z- HmFzXjM4r2?TTiP̢֨!Jh)/P][K`0 _ _mm~v3m1B.ܞPԳ`7 \?\8m0KN'/YAʹ| b7}mኋeû4zի}=ǠEO\έ;N r)Xg/ߞꝗ]|V,6V&*_}f'yu䈀Ha걩={޳O¤ !:{XU.8 G<}!w/9P:x6 4XlˀN\=Nx-Vg hܥɞK!YuojtaBدI=+=05MJyw.q]Zo>)3F|_Y4=hU3ln ^/Ѡ-=P(Ymj%0[L65-rˁ2W/(% ?rw!dg| z;.Ut+V% ʐ]ZG ]&#+*i!O)I8IPyy„;["dZ@*W3:+asrZ*Ld> HK=;l1j7yG^1[ .H^o0}[?#W+w%\aԪNaP9Bѡ{;uqcmz:&$9p*J?dH\"e0nޚ%QͬLRӾs.޾6?7;}@{:e?$Pk٫n߈$ǩ"qtmUsnu:nUH`s7_cMrf4n)^~۰qUP/%MJ*ěW4Mj:{~}4 8I oKkkX痣 zk.}[ e5Ҕķ"i _/V6ijdH",x^Pwar_ @^=u_lԌ4?/##O@CP"  lbJJ_߈N/R -Jೆ(g}"g{,mז*&, w2WYNj1Raî.qc?jO7#V.8[:ìDŽ^OF9U2Vl =FfDÊ:">/ oٸq= !HHH404֖seff'4l,[cQ з(.)tuueK B!0 BB,Ϣɖ$!DG?` ~<[KBEG?[j[0oU Fu BN%AYXYX0o*?~~aз:'vR&e%H`;7پe+[k֭ݺX/"mTۻ^ڬv,'&@9"kV;Mmtt9v ~Y3{.+|z'`)mԳO"=cޡ9~Wxr޾4hD Y,ZG3@x5Hӎ/ٝ*;QYWvX,>sbV3ۮ@r:IiZ7۷U{yʪŎ\ي"LE}])ə4wvq+5t' $ GWwt5^ĬAqi't/^»ƗG r⤃>G5&l)'[Coh6KKL _ LE'| TՁMP{OGX1@ܺ-isq񜳬!ۯݺu}hO8͇]ٿis+=ˏ7 AݰOKv`u-[Yr~M}9:џɑ h74vv0xP !ܧMnMj2g b-+s9r"AMKq ؋!i?6bf<ټlGe>?b66ˈ-.zkz/GgMx5%b=tC dF r-/7eP mXu^l-j' }lh#>kbز icki7 ?-P-H|bTR(0$.,QV- pJ C}JaQqI~)O;iTl~~A@s| & `սR>kTՁ2B#Bݩ3B heq8ըTVU}#Aebm$Bk͍+gϟ=sSK:?0$ʼ!t&lFFR%wAJW}gcǍ[KՑZO϶\U_`hskގnn ޽fe6)*/t-APv;)1ӫ:mv-C˝9}/+&+-JQQvmeKBy8I$%Ͽ\!/]=-Ju!w$A !T`ނjOO0@ʪEOX I!"1P 0@!aB0 BEE,?ZffB/& 4OLs)**6nl![` ~$I6ib)[&B!aB!`  BaB0 B~}G#dB?ޗw}x8BI{s,IRHߜZve7CˏL;vͶCBa-omؿn=Wtb,hJhuKOjy/= ]hbzq 95 Hm'O?kJ==g#c; 7.kIuFmG1Ŕyyш{*cg9m fݶe9}*@ydH{hg%:Cr\6-{mѡ4>-H߸'@Є׆S9l?ky'VRS) L>l.K8e![Oh$w'`hi>9DbR" MРi29S;+|QK߻&~ƒ'LSDp|.ljqÉ9DuG [2wSFnsϏAtn%+F~*/)"⽍:ds|wגaAIBA]ϼ~ Zi€zG˻9t[{+vmLrNGՒkOȷoysƇ sW*-_-MK<4K3z``hȋ+-M n2p`w5ο2+na'Y>l>ENcqΉcvʮI۷<~H HN tiJ u'Gjq#˚Ri6싕6s7"}Մ}; o7 ܻj^S⎭+]1}˱Ŵu EE-Q%/,;pF!OKJiG^(YA[n֜q$]z A',&?9+P$1vT rTjȮP(Pn2b6_^>|']K vka%/'Q:=19/X Z .cOB>?0liS4ӂ7b6AKJ?D~jг4t Xf=saQi&0A\Z"@QT  Rej)۩Gw3.&]:5^uA%C8&,7C| 먉\Ǧ1Qbv~Cl4Y@ESrfWRA|+5.@JPO;HJӑgETzpWZ6VjA澔Hŷu5r936cҨ3gMl^^[_Mǽ{/2:߻ #"-;{4}.ٲpg PnG@[./jsYOΝ3^1! }(H(+MaYyGu]?\q6\\1eLy>bmŠr)K(@<9yƎg yy_@T34yiǢ{k'=g*pEBk_*3 H!,ŲB^[5۲k+ͩ]\PPTPKQӕ_ʧ@*`Z`s)IE}%bK`Z8s(dLj(X;p2a7sG);vѡ8!!qr/,x=CcmN}R.#yŒ#@,I☋giJ|wlΦl8:N~]|.zMwz-)Lmܣ-m{_+#xur>S'+חr8%ӖM WZ0 T[m >QAxVl1 G+'z:rTD\\մb֜d-i.}GJev晍 ʣW_$hiLIBTrRhL]{iED֫OcӤ "1cY^QAV{F"THuOZ_ʎɐВ^~,{q?UdmY {P[ HhX f@ e]rq}j_!@\|׀;y-*IDAT,q<U5o M{/%55hPf3`*nm=[LCE%/͜TsyHR~G8A.Nʫ~I]>1m[qżׯS`TAk 鷎\ΥbSL@./)D'%/qn[W'^9pOPV%%1gvi+4ۥO낦ZJzgh}/O7gvϙh*yyLԫZu4rt)ٝ(0޽SNjF>Soд/+uBLx*umTY. 3e'8}}4jOM{UaC!fzXj Iz(foh\rya{oN!T45>riF 紺5856P}| jFAQkDGQڍBVc{]Ë>E܆A`59KWpʭ$QNǨ0Pc'B#S6mixȇ |: (RM 6 9.l0JWN~OʭWwq3'/kK,6e^Lsx(ikhSuXgP5[-[N:@2kmJțN#spFTZµRn㾫#}Z?*1`0zJbCJ߳c4tt9t2,,yLeiaNJ$GYbF 9,$tC1$ؙ֭j<` KݼIvnk*_dfXqgM{.=\ a֪NskѰQ̬[.ݺu#BK>-B;qq͛5m,Z/1’*..>Сkׯ/_LSSSvz{xԐW:qeN!L$͙;cWOճǟQeU4tߖ~p /jȵT}DӴϢEϞ?0nc[Gu uM M'G[6mtŵ[Х׷٫cNN_s:Q˻s0K֕LqaJ7Cl?5sƈ"E;cvYo@CN5|=_lϜ;N(nܰaODDDE9AƎRԹ*5L u.;|֝kfq2SϾ`ղ:h0OD"s+꧝WvtXַ㳬qnŌ%Y|u+}|- .^1|+2B? 3g͖_$~LTscv29s')sOO0N훓%'lZjy4nluʧ֕=QrhYzl?yWH*DO\WµgX'ot= >gFv_}օ]wfwkW-nlca Ȏ;ޤUS(Θ5KIIy RCTqa!Zu!TTUWT[#yBPgW>i䤊yF5ۃ׼M#59Xv>䔯PqBRժjfz&JڍnaU kA$&Ӱf$ؤgWwiPc#_lk4fzE+jiҟ:|2 QAɑ|o"q)v0"RVp|}v{-6۽CيvW ]֙n}hgNMZlul{vз|nV|rx:v;[ZF|(z=n799>k,ї`ijM}8CFT:.]LD$(7 <Kkyw|ΡȢPy8k։1PF騪WWWWVVJ'jxbɓӿrng (dV2 rcc9j0P?= ՒuaBP`]"ْeJA Z\Vj8_|2%L6@0 ȟfJEff6UX dٳ `4ZYt"cM $d2)Uq5 d@! @ a0"<vZ6IENDB`kraft-1.1/manual/images/en/catalog_standard_work.png000066400000000000000000001437751450127457600227040ustar00rootroot00000000000000PNG  IHDR}M pHYs+ IDATx^uXMwR@TQQ@ENLlLTBIAZQT 8P8BP e~<8;7;;-V\R  H3'        `   `   `   `   `   `   `   `   `  sBUUUh4(Gt^eo( 5F#Շ9_"",ż@0UrUa^w%%% VPX(A`*IQ$$tzjNMo."   ; A A A@A AYo_ɼ[klJ't j鸓tWV?fNoEc&~ۡUt"wے#e=)7.|]ǜހyq{D-s:7_:)2wM?^Lg߄~&sKu-V@]l{NZ."&.ỲJSXf1|Ȏd&Pe 9YwW߻*wZ8NЗ};.7G_*謼brm{1/s-.@8#.#ٿּ+lqtY 8sP7)v$%o?\RMj˜PM9f#`8c א`"zvQS\3@&AȺOomБf^ҹ(}9C^VЬ<2b%LŸdTF1'"S(pBů\!d=s<7VpjQ'?CfMIqZ~ӗNS8ydSg#ٛ˪i\OŖxmؒUn{gGK}_ֲ 66{o 1p  P(8YxC{g$7d̮UjN#w_fʚ,ڱit?6"?s߱ 94ξSV4f/쾱L,<@M~Is)U;]ׇxءkAIY5bj xV]V үvz51ݒћ_\P^CИu۫V_}KG?3);yPBVpЏ%4NI V3bjݭ>K&͛'i8NPWyyG3+Bl^k7Vzk[7Zi%+:p9*03d{KKBl 8Yw*#1ql}'rJXݖ9lZUI4FiƔh b@E|ͷ̕rJ$&.m ޞ[T[ȵ b+q>9]9N,Dc7r{'Vm{FX{jq%*tRkm"ɱ1"<՚=re% P& Vb3O(wS^'{cCtUlϞ?ݞ=&GO{iv'UԮ?'<,"#zl>uީB2)hQ\&Ȃkw 6TDr ׹:/v%!6N~B-3HC/78HayEPNYq`V1S7- w0\@PM ;=x*]\\溸̝Ʒ1A $]PoxInvv&;e"&jQR\J}{y@Ҩ䈚` W q]8$I2Z ӐIPHL*ҵYя&fT8N+ |_Ҁ(-.~2߻uxj?6{2[P~q8N ^WXwpQ j j@Cb%E1q"*UF jF[8Ww] x[PY:qMEE4Q`,IgDa\@DPpJZLQdm֮1P B_Fκ{5VnLUppTDYI)&(0cq q\ʳ/|+JV)1u?gq7Ըt.,ū(.e⾖qȦ(3n&?~PF=:\tH5qI6e"n 8?c1!JKQTP6z=ёSK!26nXШ?yo4am"("m0nV~SIU"U&9q'ɘv^yxqc+ #0hҒR:Yl˔[Ks`ԐM'뗴TWX5?'auB"ŒvO@͑&U< 5cyLP++qj:M|𺠈q Ȫj>~ "!(CҗRVRT+(˃ ?2cT3.>w;DUΧr&'|8+(9Ԕ *ŁAm3| pvf4 R+ |鹈nn-ə{ ^w&h⅃W?WRk }VBb# ȭ%]T9] I*3[I X@#Xxy~ $2t*`I?*@T\AV k2"?7[K7P /S+UFoL}*ڵW֏#e.gK\,C'~}nv>yQ|)3 CFLߵTOo᪚kݗ/eM.SEn]u=\7p.7$0a+N7y.j>o֋}&rsI[)eNֲK<s*6vlM.QLG6dY)`:g\SvLSM<:dI I [FF@Pg+Wv- 9Ć.uġ83̥ Wi31Eq\qH :.k0=C&_HO4MeUd 6M뭕gx5 V~ Jr9z?+.)eN_OYa-"}$##Ȉ9CfN^2cNBz{od" A{6X{ـ9AeAAAAA A#7i U/ARSi\\񽩲]k>Y|Bs*  rrstATVU1v      `   `   `   `   `   `   `@_u[9A] %ZʣTugm[@0g";'6y# -`2A\ltKtdn>'/G7+tAE] 0>F) =dgbKHY,:}l #}]{_ @OjiwuL/Y:5bWw7O6[[Ԍ̌ gzZ?=Uhl{3c G36 A]-ҽ~UYJt\PVg<,ʮԨ[ W%t@mX1zif-6OǾ"$$$fZUF˫J881w@Q Aֳ>ZIQ%,XȼL| @_A2Ɗ;<* $,mj!v^'-/J߉ YKwbŗ[&Oq+^ZyeQљIfΧ~lJ.ng`RB $Cݜtf_ V\RʜA j̩ HUUQaNue t  A A A@A A@A A@A A@A A@A ho<&9~16aGQuMo?([#C׿68펨bQ̀=VFF֫} nN&әk3f],{Lgέ<_Ab]ciz^{xbkݐCz#(o<'BU=NUʬu$sV~DFu Yy17`k-} (e[ه:,[c(筘^+S|UD lNEKϝEwcc#;|d|lL% zٙÔ)+QE8b(7Qf#"3Bzp~gcA5oʚ&8Pw@[GI +G|?2?G A"] pP( c?fBȲM]k[|cg:p빘!G;Z:pR!dY5Ύ6Ɔv.s e>;r¢q$?^|5<^~͓w`-,/-hkbdd9}fqG;(y9uvdsccc 7ޔDV_o-=nDg5fo iO;;,q MvFFW* rѝt4ՄL] ځ,v7QcF$2lȦOÞ.vȊGʷpxoҫo|a>QwBeV_ ;fRtn.]qqH4_Ӡ.pٵwBv_j=Qj]©C/7~׌k rr|#ẉμjrI# y|,곯k/'nn$ u+%֞\Ǐ,vu`@N vY Q_ZہaK?HT%#žWI?L @]]T8G,q~䧫k6q4$qkv=-`FO B`6bB NEG~h$^ |xϨf7>[9f^{xJBߛ..eic_!|^>]xO@EЃ;?0{Gߣ5tvOW\y6ǪSOo.߸q.ay}yl?mzZ0\l$ttqb }u܌l:xR,g:qacmRCó&?nqSgS7vi-h\j+l}d H['6,sTa;kjc)uYѴ-ǯ@y?qwpP- MiW6z6W]23ܭmjKkf)/.k "F0ථ"¼ڸ͏QWKhU~,o(.( pQ JxԢ}%ܢEbp^i6paA%V\v_YfOxҥZ)]8C=DDr fZ\eVˢXYEҭz\0mTWHcsYDk?YB֑i+o`Ŝ ֬>'{oY zR߱UEE$bP[_ח(BBBbUmyN6p)WV? @@e糉ׇ @Lʭ""7'j0&qgG 8eglw.ymŪCRq6YNʮW@ @czq-FٕwrH;V =D=jĩag\ubI-.Z,().e2Pw IDATDYғO4" :`)nZ]T~oZ6ޭ%t ^_-gXXqG%M-lfP$Ooאd UMr0^~ۇ*Em?< jS>dT@pgç Ƨ"P7'#==]n7m aU0 S'in$Y{t#Ye &Oz"_|@1X q[C5hu6%JN30qZ)1%߀"7e.Ӣ.ֆ:zc\Oe {`󈤝NfFC$^l (C]L23u>"qY=MN8[,O:'bQ]`dF{soohgdf6~wƆExYXϲ07]q[ǙκFkXÇL.n_&n݉*{C=C^$u"HKJ:(>!AC]9A>dV4qIH/œA#HShJ(  =Dm0>#v̩+AAAP0@AAP0@AA{555IIoA1#YXZh4 Q3/L-ΓVZFFXHy?}rWoocʛ7I/_V^o_q /_0yYi":AH HDG5U^Q!..$xeuu_ u Hz.. ouP0@#{_4 ` _;Az:]  smP0@c|W` _ާthI쎮cNov[*?,[7zW?k3 >fNee>+O/)h_$>t=#%κ|2]5MMuMMuC 6 ZŜо0_CqwqX\m& |{v wD/zr~*ދ}ds-ɵUvMhih>~A.OlزWw_ &`Ƃ})w};r-@/w,uoi1#4y' lݎp@̈EZMY7"3f<6ծ-|5ݢDJ{_o݋~B ? ݭr+PtvΤ1:t"m뫸:zf2(!I}NBCCg.^]SFh dŀ(⼂6>j^p^ʼn5Љg>fj.<>vx~Ko@N6 Š8pjjȢ 2sc&2Yw`cO(OՓd]PwPEFf\NޟeiiixYLf80.cp"<]']G~hH2cP1XaӒN8h^U WW˅?Bk({a^#[':Ӧ(jAXhJɒaT٘YξڨEt+q5bV`v4XgpgOY=.̛ݖ#ZLi䉊|8*F߲ %yp!cF准|dQY r²T' }UNҒ^quDhiMZЕ3]>gMHWv:d]-Uvc J9CƀKi8Vo~,Q(diZv(.,.-,&@0!8 A cXr~BdYE4 +d,(n~Rc}) < ,Ԟ+\ ayNʹً. ̸B%;-M^-N*25 ^G0nಪ"qc|P\XDͅԈSn4n a_" 3 k &wkf-NaAWZ0%rn ڿM_l_L)E. "D@P*A҈M6 N%m.Mm/mo }ΆŕP2_UdOQzGm!@!^1#~ YUTTC+}q ;hG C|0U,c8DC+)-%Eð4uvzc#-=kc0D"7RpPCӁK@XXa+f#Q˺bA! a0_ .5zG[rʃ/;qJm9͜"(,$jjIŔUH -2 &6/c2uAƥO VhԬ [8oQjJ!Hdney%>JI+OK(YU__b*AP 'z:@[5$P]WWҘn}Ma<gM8}6lWST1xtbI->sf iE@p[+cjI heߒR  qQj"I7~T2RLB[[4ʝ ZbI Jn⫫^ho<&jjLMiads6?03hvcK F:!t%6JIv^\0DlS=6c Vݗ8ʲҔUv՗f:kf-p[+9tp\T"OWN:cSٚ+sS--gM spC3 ͧlݧ)&!'ӮMuW(dh¥6|g 8^E$y\j$'ǯ|:+ϗ >n+t?=h4KiU. whRgsm]}.&$e s`CM>u9~룮.Qii"Q"z[~}߂2uP|Bsj+cbUUZ~?=K?Z1[}  ty` H{_:+uuQ0@՝co =KgJ|AAA>sҿHTDԔշ\?ETD8[g^eNd cNBKΜ@a?~y?WVV! t??BEE;;{_` _;   (  ЃAMGRkOkxxKdb=-񰣵[D-s?xt[?q`@ߛ0LIquN| q\-u1dyCe-Ռ'z@͊8~ZS| ߛ^ism}DY*æ^I'{k~=Y|oٖ_!%]6rFn-eэ@-xtI1T`Ä0gke.U`p}G}iV$gub,{ ]~g&Ÿ}pzO,_d)yd`#gam(ݎG wƫ=dwl&1T$2?;u$P^Jsş^kOW:lU=mOh_pqr* ϼ3u{0˨:l8%T9fQ_cB7?p"YG7xXLj=_;s;M,U=?*Q)w,h9a'vU M_i8IM?裷$y:s6YG` jSM"K7wZ^ith Hzs^<O LG>bd%_^6ZC/>z]*mǔP֨{7fJP] _-8K`gju`mZ+ju_%W"#}<|^fL3xmK YyjuVHzřroh9YGDxrYM-/Cdtm ("[7Jg8~]B^Pg[it8D4Yʬpua;/V%}7ĦRw9zWu{<ݲ"fdM~MTFRQQ{"WUVuP ,Bu卂Y< %<~XKͮ9q 0.ycmL:?~V1_K0~6&H=\䤽~]`0k0~z~pЇN:5 5FL8lDJT29sU#1I1^z=!ݟo8bS'EPXS0[VkiC2$XVm߄ZV2XK5>m]MBp􌘸ZdaoL r`&yx?Feh ANNvƘ'[zGr-A Ȣ`RKca ֢q1.:ca\\Hwѡ&׾O{5Uk-d?[|$ڽ K8~EŘh}7 ?ù*'Nnq1!8E\B,.(&@]a>vU@g\ E}煥='P_]7xۙ -qa#|ƍO~!?f=s\PTሲPpJОZH j6pgЭ-uܶ GkɴGjT~4W{ ʠFVWLjF..($Anܕ~G5q 6dK4*eXe%  wyIझf&zEz@!HY,zS8faBdQA!R8@eyeK5paQ9$`@ń  YE٤UH 0&F'Q'p疭Pz=8߽Q&ܬ?1 ɆP]RRC5,#F\ Ʈ>>vIfek_կ}[UkX,:( o u5^FkDf YS)*~ɦZ)i" 8yyNm %N;(ٱ`vֵt㺾ʭv@]^]Fq]Mɰw/Dj2n/WC:H sxHz5@z!orbYiTזO}Z@ }ɣݏ ͺs?jN؉+oLe[4-#cnNE Gk}z'@}x^N{Pn^"o AV_^ ;8h;Sn.g{c*ل*~Sdx;ft,>rqS8U,|svi ʒu[ZPp t9, /3^2>W@z{֡$:6Akp"./:Bj}m]wO1k{G-ø`̀[o}(8h8GڄKijh0~f"o饦5yl9J .i MʽD6툝bs IDATj; jCLqzwikwEvVkX`%iƜڊXC}==:%eNA+֓N WP,))ɼ%1**̩SBzRPCU_|.)b .A?T^]"FbRbn!H/BiO:{.(~7=gTAJIM]hQIIEN8ܙKP#L9-㢋qo&B˂ߥ{}y8Kȓ7念~ʿAM>~\dI~F|$ $I 0D_[ HM{Mw4zAAƏ))K\]/[~ښtiӌm,-,r+1'u٘o~a|"vXN:N}saowA/W` ȿcJRW˖[8e&~~s! /y{Ht$< Mpݾ W2w:Hߺ mHIM]x3,)ς}H@~:q( J%&ކFL0VcF_q>M H/iԥK1f1 0CG8hy'xYWKhVP\!('B0+ƸiC1?XT` ȿf%]]<ٷo'簡C#"#95EPX[oF.N׌ɪf4&Bh?[RRv 4J.QKVE=M\:T+P۸3Y,}DܛTM^]"le{Ͷ~']6ѓ!;8M/`[ȕ>Io_t/|oQg"7̑o櫁6eՒ"?8Q։/bc {gݕTпa?,% 㡍^O0^5!YYkHh.cUQ45j_pDYge 0޾ZTRNDNy ut\ND3ή/>+hM= Ulfch5zY"{\bhfx>xtyuUW6( ;EEnkЏ[jfe2܆/+nO L78Z-uԐsN=t?@[cV{-Rw0. ۠km>hi'Ԥ<6@CKGl7E5RcKHE!SgH / MT"<554M')YpoZ:[#t"ө_@\K[a|Nn?X\ }-A_ DmPqq~z {rֺҡ;_5qǖlOkZk$-P,K"([eDE\uuݓ׽[EPd((CQq"nAޥM?R>zN'痜 >G_.^5fG׍!n%Οy}lhYom%W®n&DGx{d̫SNGDDU@Cݯuk_L<#A8{59YIͫ=JG yJgV886 xb>$Vt䉀qZs6܂⸨D+'v"bi&w NΞtZn]?c=KO~pɦqeyDD== צ2,ƛ'TeS{:2;^s'j,|sq]FuR ׫y$&=:D @<>s"A| pigsuUTWPe MӢ:&)׼rśR܏Ҹ=T.k~'Lh}ޤrwo~z.FdMe*lo )%(m#L>9pϮE}S{O1Q_#adi\-ݼ8YK o-"/mZ6R^7>b3etmQ!m1L :ZM[;C7Ot8UI *pC:$EJ&?9ͦV&GvW&$we  Cg0%;:zVqFQ:5BV-dIpc+nG soҏ_gSg6˲_<|>B^Qer*O(ZB%?΍ ֎*-....)e€e?5o^V:j6W'T^be=L/Tt_C',u_ضg0ZZFݔ1l {ZZB/{:44 [F Ml^z/J?&?I-5ojo+&ը))Ɍ/Qdrߺ&}f e;|R>d%,z{pnfHYL0cMܞҋJFl=vֶPDI(v}Kj7hyX~s>U0Z Z|g:AO)QTڅ {/;ۮ"o!8rۄ%\5C^~PMUҵ%&mDlWW.8KϿM-R\evF3K ]{݁vLRm (6rZ8wI:cŦ╫',K}kiVycYrjm5 CG<CɵiZB?BI(뿀CQ~Q43 ++[}&}!P0@!aB!`  B">>~wRzm+~% PSw~V3MUU5?TFFӔvzz 8Mj $55>3PGt5x{!Bk&€M>Уm<6>?Ϸ._0LaQ!4j9gFukoP_޻_˙1NOA|,x ewOm7kog4tvsCBΏ31'N^3Fg>Zt~4}W2 56p0yTasΌq~g!Qo7QT!]nרa<I$=~xbXKqug }CCཹ'J4T>mq3w+*|z!պUyGTZpSMݪG%m(~3w;և"BԲ]ZB{ ν,#:2AuPt' 7j5x= '$A1t8^C8i^NV cUTӯocgiaj?؃{$/5tH7[+sRJ|v$Um&O-IB Z9˅Tc&x֡j/&o;ftO;K.vS<*(k淯긼ku_?rCBFl''U7Nekeew4[4Μce{;%朖)q 4]p+*݀!R"npi({{_ʌ*i~N Svs@gjAL!6-λwh{–@{2,_KcAWmhb[-_wFj_FeGSs3|GG M=TTl~e,{m.\%m-~;Cڻx-W{ϒ>mdk:^cFIͫ=JG yJgV88lhYom%W®n&&x}d̫SNGDDU@\[b}H㺵lG᭻%qQ:VNEd HM(bAJ=?{#oݺ~x⥩S9ak|p]6B5KO~pɦqeyDDna.m<_CS4|N YvZݵ^=$VT^멎'Sϫ9F%͋o "b^ۚT 7`+Fu5n lRvλa#] MPLnӝ+!d}\q}*hg"RZ($URUu:'͘){xh 0-lhj>4m48N>LW%Tb@)T^bͦV&GvW&$we  Cg0%;:z2 ըN 9qBRUhz[w4io;}`t.@zU70;ݺ'>A )@탇Xi^2v៚m/o g5V|x+*r/Sy@4W"SK(AQڣt>{0DRU?hfǶ=Z6*覌e l:Զx׷|AV $T؊}7JX0ld8|U1Ij轲1{ۊ oh5җOu7ꠂpb0ogg3w+J_\9ţτMˁ`A;J2Mg?EիKVmmYјM \gb5tJ%gW78rۤZ0;3{A5Uyv'K6~Y Z|g:AOՕ ',foSaԴ0WYQCFnw)tc~w[GIiYֿE-BPq$} bS\pKھ5B4MCW,LfE ɾyksNn"_Ii P+gfM](njWz~:0vlmI=3iv я{3پ&Y2-q8'\$& ".>F!׋~Zxpi-# )~:*79znT\uzJ{]4;s6 @=x]Y7xnVpx΍=7gglyxG+z39\%"i4ݾp(q &¥;3@yj)-jD /@FͪSR'(defqh_TD4M 3yW cht.h9Lղ ɀ2B5.RN^EvUXPDK J |m"դ?) 8/4_2MOx!TǥJΉs) SΞY@lfĶ+/ (Ʂef_\>}m> . kYkOa T0hBNΞ#wui<77y~Vo]{Ywu)Mӟf@3q(Ktk'M3;fKI'Rzx!$q9,u/  7d<3@!BM]]@o- 0@!a esDdf m  0!n^_GA;=0âz?i8jse=D^\t =EXHя<輠 [0ɀTƱx.Mq|K#sΌ6Ӌ+SA77U\haT?=NICqorrrmڴSfFۇ:C`ٳ#ډAhDsm@GY׷Ysc҂bwe syucdw#朖r(AvJG({{_ʬ.>dt,b¨Ut 55bնqe^pq}גM/?S$.xmE׶x6Tg;s:1R(E%H <8m~HQ6miwP|[dz/p=+Gel]|AjΖY@u|؍ؐӔ/gqTz5l ^-oA焭u}ptz%E8r,,\'ƣThŮ^&oΧu1 /T깣/^օ*l\ј8cFlی(^5fG׍!n%Οyv-j16Nԗ$`4Ro# ѷ1b)~ane9W*+Ķ}!2JI(xW,UsE\q9eqۨ߸ݸ_Rq%iKo /$Wz.TsXA2@+d@ aP#ٝY4-Qݿ{mKt=FϘC $,K='kߒA6-EľŽԷ5'nV<BF]M:E.oH**H7[tj>aXTD TkC'bhofdE;ZZݺz5 R˗S/KAMx 5ve c/ڡ9* PVQR\ZFef;.B[2kZJ6u->bh3d̽E >r jLM1Ȇ ;/9ٱt=e4R_l}ȡ1nml%ܾX02.)UnkLwW.%WC+e={)߀ʼ,Oe 791F۞KױSd=jښ'}շX\AQ"iJ> 4MKrz:ta6.~U T1ͤ?z_?hfǶ=Z6*覌e l:Զx׷|ӡȄ$$T؊}7JX0ld8|U1Ij5ojo+&5on~6BnmGzXvhd0PEBJ6jQ9zZHјM 71v` Ųݻ|n 272:v$؞>} ېfaXqhgL-ln[|:+~;3.vnmumy2ݽ:*oR7>uJۛӽ <+u儉頱/rty5%g;kD9>S.;8:+n˿6V]n.Z4GN HM sbΨ^i\ii Uݖn@ލca9yZ:PqڙX?K3cӠ/Ko*Zm"5|%BI㱗nKB?B! B!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!`  BaB0 BB!0@!!!` Ag"n$.E )\uϞ W b$Iv6$\PC451.E!Ԩz!PaB!B!0@!!!`  BaB0 BB!)a %%.E!q33K'\(JNI).*@!IKImۖ$'Bݏ B?B! B!!`  B.v|>E!~1))Iz?Gg?! ?VQ@!efrSR W| (*.$@Ff_ aBwaB!B!0@!!nIVÏS@d3=Dx^9r-\5q(a>]M,\'1+u]w131u: 5lOEhHԫm&W}~63>P? ? hnaswRkg6)uǿc>-^A(xn'6Aq˧},^@Bۼ{'?? /wo24`^/mI i66CVunv6.}Vɨ؝u>h4@.jCMv}|(/ǮV^zɱ"nZ 0 Џ2&oigèV(mboƸ \q!7h!66rYK$l =6I5A'n[{'8*m:|5[\'AqËG2u1s"6ܵ3>/Weʊz^qn/=qޣ]ӗ?4Zt:,2hcڦ;OqOυ2ڙ;7 WJxnȬ5!X[׍.;~c'&Į۳,|2VD{`EB yٲrFWwi{|{OT 4G8hI %^; +F:xLo)) 1 dښhI@Y>/ .Nٸ\LzNE/'$mGNqUdW-а®Ç[ .s (OV&ܨ& 3$0[d߈z&^]|j?܂1>6Io5@R$wߧf֫}/G)A^N J@S !/'ސ/B%We{8X_l_TL dhKW }CW2H 5{8CV.WlͮV!ʏSQ&(݊)8!)//^,LA^>%(Uv{uo @Q0@|&IEO[ (7}RXssli,/0o @uwµ . ĀPPR{bcHL9}6EuZ}@"NIyEٜ\> %%%UggȓO⬬83@<ɐPQq~C-oM++Bfz&ҕ9rJ U~ %"mz}Gw,~Za,Uˮ Hhnӱnc/(̔wƒ][@E@kwD" %UTY79dwW鰝n@S=ϪQMYs ȾH.lmߕPTч'2ՇPv8f_ljA, [\;U'&?/Bu_C.Jy{X7Y}>%ڪè=$*e=71Z$hM ӼebVj NߤaRv^|QH_=e}J:5Zzsj)cς6_DqFzP,aFv3f\kQ<B (.>X4B'f!^3@[1;L>{Y 0@!aB0 BB!0@!!!`  BaB0 BB!0@!!!`  BЈQ233P͞`/P #ϊR$ue2Liwkx7:n}*.=?uQC}[Q0X釹$ޠA1exs)Kga%k~K|\Ė 7:XQgD_]ҠaCBB W|R ssL}7?W/;8s}RBtbjljff5t޾.%HxOآA87ZENIRetn}K; ?JxWrŎcbfeҁ?%:s)!STإJ =FDFq,,DTGӴMdTpEBeР{eJAɚ ژ/0;Lpt{[nw&Pg3]ÍKoqonvT,]7)̼_W/)*Аoikڴ]> kO輤csyvwXbzG5aٷ|_5 pZʐJ":'3GطUf1Ť9VrsX9 ɤjytL?G;{3?.ӦzԄ#=ޅmkȲ +NR츝S}l$pU]/ҠaYqWk}䖗=o]ا>Q2&=~@uG*'O+)02f%5I*6_|k7;tW;3U*zDyc >A r1vsVMޞndT8j7tɴĀm!&4(o~dŽC OPZxULDŽ͝8J_>\7WQnIqDՈKL^lr%lgJڽ7^xq}Ѯ-:1mIe@gur=r΋:_>q5 4;{ܿA$WtoI§}4W#@\cم[4ȧ*K߄s֫DIk|-ֿ}k ɿgNmԉ񎤬<ȥBAIQ*5G BWx[Hq|tw<abf$Ռ57]MZz! Ggfp)hy-?L9}6EuZYS1Ti"sYٕݏ.((VuإXKujs!: "##:1ud˸#o,eS9y(0Q`hhq}_ 1y.mپ nB͏""e]' *NZ@غ< *LI~W\s8B=@9SZ1 H >/wW =Q]͜s0EVqJ IDATYi!˿җHUkNoySD 凒ں'tinnrMe﯅ީSzMa;ȣ>zEICShzVRإ  ѣ_:yꔛn%.=:K|Qlo}F> {Yébm$[N"wqwC<0t2~XvyO@(9^;X>d 94h4/{+{C_׸WRL&3.-ˌMUaXf,޻&&%Y,QTq\{;3bP;Œ_Kd^Kbmisڑ'%t-*lQCUB'7p-8+|Fva|#6vfO̦Pq£hG3"Z{;*չv?+t$& .gjA'OԬMD_fDvΥI<+eΉccoT3҅X`gkVPYQnn&~-drȧOlKwbcDF83PZZ1Ku$)))#SB wYѫbh%x)sKHHHH|q&;'4r|++" Tw!kfa#B ?|1BB! B!!` <L\\\C]$CGYiiUI *,*JO.\jbIKc]dx8Pj0@w[dTA6C*_VOt~$P>.?niS/=_:yv՟wNs÷)?sA\{-$5cFOWNNlUVzjZ-gk5qO;d}==c߮];J]gro)I5S?4/1\6" {y6Vՠ@1EMePpږ_Po^E64B *@jYjǴGT~ԫWn2g5wD ׳|@ܬ@e&SetXFɨ隺-Y7@ & odiJM"#8WEο%M X2WM&x]X&m7CwOӫ9n,/8R0 X@gڊg9?,p$E_D*Sy@*(W^#H!+/[9$A4MgrKҮOvXUFjUS!ee94( ûE&gI{WhpsԤDLݔ ۿ̭Wy4(z)0^A7W͖| RUMd @J+)UU0$-9a!n=/teTӻ]M(#I(|_$֧M ZCe^^:|ZAJ$ͼ׺0;?9e9xY֯h']st'PfATǧ׶-1)>G_jFY-^]J5BI xRVIzЎ#*Ga&FrBz>q ԇ3 f\hb^+Uq:'pj|QJf bޟ$IjX.+U@l7oX`^8IEP3;JlŢ4@e$*fF_ r1u7mSA|nOtlG5|f۽Ⱦ4'R;?#gW'zx J.,?#%Uۻ?8,qYmI)];Z?y4EަvBBC+z>s3*ڵS󿜛J^=Hv5Fjtg£n%Ωv/xvtxؕа;)\ @,%_RRlJ$=n=(@r^=~Ec )e%gJ?Jz^Nz@H3Zuxhġ2z) fx%g*7'OB]PC"_T(! OM~^ Pl؏@ uM߁.-Snc";ć44Mpe;ZǬ^|<1_^}U vd|@bk !RbQvǵ*q""v؊ "`Ԓ3 \|UT|3;93S)M:V^ï 5gi^޻wy|x&eiIaY.sN. n6Լ܏GbiѡvM ,ݦvJI4[iQQ>_JC.%eVE؟a0 F5P:Beֆ.YJɪ5|Q+ Pؾ!kJ$JVX:I>Ǖ8];z^bĿ tSD+ bE8Ѭu'KU0}I;8jzvP  vi鬮γ,o9i ޿v_ &.wi(/gίutu8Fo.ICco! \' }1bvܪ-2&ghmk7. is@^u:$Sk &[ʹTƁCSDm!c=퀝H}蘘V-KPV%tqXU[o)4k)47^½›n21wߨni"E ]tNz{cCRD@ Y|{(^+X{=%EMs #UϹ s߾ʄF*5$rEJP]6 L/剳3=WB1^> H KgK׆B?$iq7 yk7SRFA o>ic&@.^bHL4MjUIaz|:; RUe{[aH 2C05-Le7jh2n_RF X*>) ճZO{'iB狾\Rh`Hb֢IRR Z&#%O %G^@h[96qJ !P?? *)$+bA09qyENrbgJ6J E}'}'ݗQ30-[;>wtg}^$IMgkB~9-f4KnJ s(a79@<Qދ6-LUD"HJQ &J/攊)Z",-(/DSOp蘘?R~{?}d OK/Idʩ6p0`PH-@0JFvֺ,mt.FzUR]#AzԣWE442s0aX:6i"Q1nhbnewOee)U*ana.U .*+h 0ji$] L҅TԳvԳ.F/7d'O} [RTe?aI' nնOWqϟ@M1 Fa~9***e?aI}B!Bՠs/͗OB0-)).E Zqi)Kߔӓm>jpk%Ӈj!Ύ>8wgN;t 1Պp/<*.#dڹYoIsۺ }z`(gVn馢7աsܠ4xn.m/>חVuk=bTAY)]6kkW^ӷ?̭?W@n17[~#,YYdE1O=kp $I¨tjQX鸹V ^ľ|K*|.N5a ;6)fş_`"#;)w$ZI̞qLk#-x_ݍzR9dta8nnjYv 1MpZsf쫣s't2w>FNyG^uY.|f I:ҥ"H Mzw ^Y:i.8vA;'4xɞc4flQx*h͞[)\1Ycu+Co,3 \Kl^k `Wireuc+v=Zo_ZD|fzh⸠Ug5lvD>`+v 80Zg;6[ ѓ޶[WsyصYF9>sfESqrMܾ $@![yՠQ?k7ګ2{ <0'$f}I ]xgE#7јs֜Y;5ܴ63;EyiF]g'u]|d5 KZTٙ,C=[otu-H^]{uk*2lS3.tI_7TE+;B˒c3e@Unڸ嘘KIBOɛw&reb\z'N-0jcXi"TLM2^dH"N>s/ @ 5Pj=ٿs'nfQw L5J.{t[H$_]Ns!~T=cwO^n9i@fHjдȍ@ڶ){l f q({n_e X^Ն^͋t>+y<>9~*6UZ*S +* 6 RKL6SL9l~!~c!`^.(3$*[ c|䟗kH}cHEeE"ԫU'ִT(}Oɴ=+o0}T{Lh0شUG"kaND$CJbS^N*QeGe_ \t}Qɿo#[vYM`sil 9rlS?Oy|l9Ȗ r^;AǔSUWWPWPWS97rixh &JqTTWtP'WP'Hݧ=z~{3((/*A$){-l4vC{]vBjBafCjv 8OO}9I;=| $36~Q~ ?=5SԨalj^Z/qzEc#7e8 --_԰e]QYVKXhfזGVx-lbe'^iϒ2En)ze '{jtbKHQ,M2bTRQ}#k_(n~ nV TV4M$;q1٬`{k,Jsj ΞʷK.gEj0c{.OȣE}\ UTpTdz/O#wMhѥ~%0@V׿p<9kݕoUߦ!ڶiשB m1G;Ͼ+[,X=FDﯯ{Is9#oώCi_dLv+(>\>kVS]!嫾(`h؃{}/:;ORD?]p߉+6;WR痨w[ʭ۷O.k?,ʟ@(dqb fDs!s =Qtԣ訇g/KQGAKL:tQy.#WwnӦ 3W|ƬEܻ&OWtCC}<<:v7sۃ qADŽ=rx7綣Yܱ$I,Z0䴛Zuk ^^]<= ]z.]ԛ}mu;d[o/)E^>}v 4t{"FC}ڰnʲJ, dH-FvV`6uU IDATXeS3F,.!i 7PMKS`0 _ _mmyV3mEq.AgKB\>'ty+x&Qqb5cO.@\^6(1x˥MӺ \Y.ywUI׮խr9ƠEEOpdh5ąGf$O9B tn^=:/=~tGYec;[ꉟn9"8Z~xjϞ=b'a҂Gv]#:w\n3/w_s6hΞHyE§tjѭ?Vz KAͮײD̈́U&umlJPλ}6QCYZ9bЬ!$@ J$ot9H08Mۍ8:@8s"@5uaIkaND$CJbSi2T^v 9tx}e %4jtJCvִř8t39OLTkN[,zFS7?dLt 0y,W9 T}^Ig-Z^1Ƚl&z]//0uK?#S-wE\8 Cb[/0@Ц{5rz}>왷8-dC J2$|PQSe>F#@q6AT3+S:p"`Y[Cjx_#_<%l>f.);W1uzj3 ST(- k_7:H*$18j>=?Buo?S|r 6 )n~ nM*䗥4Mjy|u(bj@_$- auGЍ,4e.}uZ| + TJR i*3"hp9[A\XP>9 %:~OdԌ4/ݻ<> ]#(:F )yy5MIQꥍ{6Nzi W7ڱ$x`ߝJf=;y tVslY{VvZ~,U9`kZZDYw z= GѼkGOM:Gt>i"IC/BmkO;Wѱ9?x0{(d霌1ɔײl3poMιuIMN[ eך)- ]ZlEz!޸Mv#鲯Ӫt)B*~A'>r.J:!􇓤?M1S/N!P`4wt/G!0 Ba  BaB0 BB!0@!xB SK>= //gmeUoO;0@S u+̬Ĥdk+2!EqI]\\,]` 0@!aB0 Bg}T'0@ 6͟^ZB-6UVX+V?om F G!Tʒ,lm[̟7oŪU?}|aз<5'v|V܈>pkD B*'AY/GsOOvstwjoQ9tZͫ'f6ӘýYQNOvk1jӅͻ缲'UDWiW_JyAA_N ڠR^ 0 fG=)lK9.չr޾7na#OLUw3y@*|u^ #wSWϨ ;Y.:ytV[.@޴:UjZ?8m[T{zֶŶ[8"LV|mEif~o֪wHʏPwwwRg{f?]/'cI—GgޗqlIbݺ_{ĠH}H;ͫwzMLY k݌ n}bWKw_KU=_ %Ov"F!o:ss朒WBG\)vaoqʏ7;AondX;ZhƏߺٜyU/HIS4MI#A<鐁>^y!ng0@7iݺG_8|YqJ h^c:v7:ܵ/q LN}pD.ٻؘ&Zɛ2zx3~dK_. fɇ†K1@-ymmynn&ˠzC]Pyt-' t5>b`\It0^J⧎]''IOjj #$Y%jj%N `t^y@T_J!jc,"eoվ~ ~}ns & `տRsTՃ>O5W6NO0޶]=jJ*/s$@4\pOlA"z©3N9uNjFn) >2Ϯh:y ac8-aZ|?H)7vj'}:vx_y ]==ڒu& c< 8tkyy?X"XX TЅ7탲I c:g䰕ɞci18ӧyYٝh3O#"[ ]cbZt.E(w7WߓM_ޓ\;u]>r.J!g$A=!T`jŊaB?m0 BgEb 3@!aB!` ~ Yҥ Zff|/&< XYZ&&&%HW4\ VVҥ? B7@t)~p!B! BaB0 BB!0@!xB?^]v0 P]'!S4B! B!!`  BaB0 BB!UÀJ#xӹtEm{CBpiW3w]MIW]~ӜgYosTQzȄ95mZYJ{w_jf<ۚEHWքur%E*5,D)ˬc+R7?lt CV^UIK*J7{b-Kq`:^MD&ɵI *7M|F{ yz,]|X@?>vA)#Q¦=#j!wftja\0БG]G{3*L{x~»Bsz 7ȤLenTQ; )&m<]Tӻ.=X@}km8T?*iƆtWOOo}I4M4A*N2Қ]u¿+]t1 @om]WWixw긭o;O&?"%k.-Dn>`XmCL볆oʹf)%sN79b@p/ݧ!cg&CFBINK–wPYWN[z"HAIM;wՃw^v-b2 x6[7>@6o$cOl J~gc' TqFGoruX3cozefml%wMj?Fʺ-*/"|x7&mD٬ kb գUz7nR.hXz5U$蒌{o>Ϧ-0Cp:܃(xuuݴR~/J)qC‹lͭ< QoE$3ݖ6v٭ ʶ& Zn uv{K%B{}͒cvNd}~ :> Hmn̿kB=1gvn\%L-,ێ5b)+3|%{O'y*cg9m9ɻgݲii}u+@}XP{nuI¦CBh^^;},UMz;@g?>瀢wJa\g`qd<=>~DJo\zŲ3piUsYYB(ܲK=5 9h)ˤbAj2ʦlKy‚({]Jdz(GtYm0uG\MivCHʈ5y({6\Z+t{3u[;k5ץ{Xn \X6E z9AC$]9~|BVI-G.N t| ztp[[+u@nletYP~VFƸwodDV(I2R }/6ZLl 80׷Ғ?J=>11tk {b[vMsNM\n⸽ɵ{Ysǔ s7*-_-C߿wma/kk_rfʁaVB;C&^6lƹ}}EȐm9c&'/nu3ǔ*Z).M{#?hͱN22貦Tu%Go_37PO%y?^(t8za![/u_կ=%زaBlih+ԇȣŴUEE)V!nX o2[ǣx%4bvDJ;V?`PwӁ-w?y4CE[a Btq͓wRF|) AJ#$(&lF8A^Boܴ fv3~Ҹً/(.Lv?K@y|$|~zB&rr_O3 D?)(y-b4@ԇ72@@55sl,EQijqØPQ<>+$":-!!q\ڣO'7UZ*b_ [Iˤ吥t$1j)@iq\Lն Y-sK~Cɘ~w\YE'ſO׽5R Jh:Xd[iww-ݻdK!&Ts|A{ rѭ;,m=&sN}7iS'l/Ǣ]BU ֝6}i7M]$9x`8`M5(q{6 ˄%_/S5W!USf4];ƑMm<ם f^?Q@1i€dTS(@<>yƶ 9ee9W@T24!ei'=ǔWQHU O'b H6$| e%y{[ܻca3RKW[JL̡V̚3L| @ХoѠ\i:ڞ/iYgu(.I2?s.1/Q.$H޿ ?*Ó KH# tYćV OVZQ~Vz"IUWR_ʎ{' >=?.4[nrˤ+=um ŴH$`d@ %ey}jr {|ǀ۹n.?T4/  !4i@b1`*li9[LCE% gN ~mYWOG(A*ʫ~':?ii}ں券^j'"G7/'q0<ʋʮ5] 4#ͽL^>2g>[Mսw*M+Dn\zra]~Y=CGOǝ ޖ%oקݑ5ح,/ųpQ2.soL;έ$o^c;çɛ}Vulf(xpj{ku>^ʔE&Y!۴/{%Qqn 7^0frU~?F}m; o;sm^EC>pGN}YU"T<lX3{PJ&mFh;OYҎ7sr^Ze)⊷_ Ztc<`Cq#cWؽG>ܴc lM3;o3Btzɪ]WFYx wҪ/Iet@g?x(ov>)UThUώĥc7ohRW?Xрd+W(Y$[IMMAĩ6h5& 6vfYkVp5O$ :5+2QPQ58AUPk_ |ƗQ7seݜqs1\as'Lm,sovݳ|j`5}fDFu zyPrDJ [NjѩЇc8$pND>@+EIz:cw}Y}<{hKoC!T7ŗgwi \GQҥ_ _äܱWo~tν.0a^L(sW5  G! B!0 BB!0@!!!`  BaBKdH"rKw:RRRJJ+?S!P}07'o=aBwaB0@!aB!`  BaB0 BB!0@!!!`  BaB0 BB!0@!LP#KW4P6ܼtިB _zZZ TVVԗpojJJJKKy5ި 4M҅ [-ۋ{:82@!a Z6.aB gfk{K82@}lr-U U6!N!Z{3gΜ9w.55||nkb HؼYsVNNExí-)ʕeKjhhH/3PoªN骯Dv  s;xtE*ɑxsiƣ[+<ͣʪh#-'`` yԲɵT}BӴ…O=0nK[5u5 u W77mtE-+I4TgIDAT٫cήN_szQ˻?s0eKHוOq͔W_;e+̉룊*1gEU+IoUҭpiP~ݺQQQA;VBQϜԼ2~bؔ]zۗj/ê:5|u /B`9,6kLfԇ O lmaqT /E~]ݲftsoekpܹG899 *$tܹJ?>^ش/ɝduSf$Ѕa׽[O^neQ{˼^4cwK*-[ ʆۻ{ }.ճw)UzPM0@YV֘IVuvbU*1wm"YnJⒹզJۥGG/իϭ+=}ڵqF(z,Rx@օq ᣣWTl={7@cYb .ۼ\.~<{{vN\pxQ+N !T'۶oxQO@0c,EE FRBZYUjgC((C!< +7GsK">>ͮ|YSIs iuj٨yk UdZ9r?支PvRRŶJL Wo1R7`NúɑMnM^޾{Aaj8ԤJ ˓FR}c_ةGIr$S@AdHBSu痠 sJ?ܝ},(!] Esh-*oXBz>fԨ'&$&N9]CS}I@@crn% *oG4qhPe.윳}Ih·^I|}<@Q.[0qTP_oJ?[ܻ|ɋtFke=+uܴ@**rs'HE5M/_:w~a aa;vښZ % 6ʏqfQo EaѻKN=UE K_1[r-RUחA[mʃeKϘfs|}}+5#l)/ $BY}K3PE WH/XM{7=䊀zOv2+ׅu&B_um׼yL~RjA㷾ɨ6s:WsOS%iFcV|Dz?`.| ŋO4xKKK$wݼY%ƕ;N޸F{[r$[ݨn}ƹ݊lUn*eNC@4aɛ֯| Pj`K穫n ^6xkV)%f6zJ2PrMݻ5Asgϝ?Ux{v?GQި#A~~~~ B ]FUިC!0@!aПukjx?Ÿ6K^;_‘B ղɵT5Tud B8MdeejiiKW4PY?*)*J~{Zx2B _AAAbRRiItEhjf*##X]'{ZK.Z>_0@!'Ba  BaB0 BB!0@!!!kIENDB`kraft-1.1/manual/images/en/company_adress.png000066400000000000000000002545451450127457600213550ustar00rootroot00000000000000PNG  IHDR7\ pHYs+ IDATx^w|TU9LI&! I(*EZVVwﺸ^VZ"*꺋 {/kCtP!-dD9Ν>:B!B!IĆ'6B!B!m cB!B!mcB!B!mcB!B!mZkYϣYB!BȡlZ]k Ash,%m'B!"///.6kosȀAB!BHkx9zP㢢"[]]rB!B9|A yyy2!']-9Tbq' N EB!Ҫ<O\usvvL6`\PPf̘pN 555qB!BZ;'Bx<?C CD\xƌՋD# 10 #JN!B!ҤAVu .r#SSS cƌT9>Dqb(< 10Xlui$B!}iT.].N8VsrrxEE|0 f&,|>eLdvvB!B9)4׮ f]ץavl8nC%6Z)u]T<,ٶͼ^/ox<&B!Bo-$ NPN ̊Ⱥ:(tBrzz]]]-vjSqbgl^\\\. aplfm3!s\LѬ!B!9o2:Ct~u]B"%%Ŷ,Bvl8n=6Y)6 C*AE4n&wpvG/`B!BHk_g0\:0MS("m۶n m`%X9>Xb*T۶5!S9m\4f6WUI)ais7I9B!Bo14 ~ Ì1iYdIιBB[JiqMEQLV9>X_*Ŧiꊢlu]WMTyb6R2';;Q矸>!B!hc۶cmBQa۶PU`ijihf8h WbƘ[QeY.EQt)SlV8\EaRJ&NUU@xB!B6b˲3ƤBDBJic"$ I)!4/S0>@R(n^t2]@ 9B!B!ǃ9Y6(8Ɂanwc%c hUVVrXLBreRJnݺ >JB!B!$94Q^Q:l߼5EQl)m[)LӔiiiFee%RRRd]].̘1HoEOA*?? x<7 +aR߽ B!_ǮB4UUM(0  X~~>6lVqTjis.T,R5MӤ.ιKJRү!B!o,˲l۶].0MSض-C4M޽;Yո9h+Ɓ@jkka6z, r\J(HGVNǸ}UZ}Qb3!B!*\هٶlfBC+;`X-χX8m\.fYs۶$㬜rqqm!,3@Pt%))i4=qu,;'B! c 1Ç>c`VFb1H8[\UhEEE@+ M0ncRJf̶puePn+%J6K0t ǛwƶE!B!Z0KѿoEܩ#:wꈓUkW`]űm[Qeq)%Se1]oX8l`lY§bLUUf&B])TyM#m[G Nv-ݎKףWA7nB!B}[Cכ}ϼUk'.s!t]giLQBa@>UC"B09SUI)y.m!ȝxȺ6ыc⍐r`퀆[sOLXB!BIF44fƌ:;ul߱ 3faf-ZΝ:4;;R^uuǰ}GʱI)EHS0퍃2VSSBPܛrX0d@MtGŶ.A%hlus;#b/օ RJ DŽrܱnCNf[!%+_'*$>W^;qBM躎ne<]l۾ХsG=$6'La lcˢx0Ly&Vf-tMC^=ګ.Jk1)% a6ssd(k%N8niZ\M@m!< >QQ`g@ݚ,t퐟xr9gsό^3!BȾ1(y} <0\[0ږXM>f,M#FilF;utPfIBJ!t=:fH R@JdvE3cَi(/V-FYOŧſ^Ks̈́B?]py]({]t\}p).@Nv{<|ߝ3O`˓QS[;oru_.|v?p |)𗛫.2~&,Y}z g=>~,9Qpmx?okm۸{޸ѩc)aʢ6")q|\ Q0~31wB뵷p5W"p\ض}&<e G}K?b<]A FL*~w<鉗&tM=\ѐ:(?na>݇cP~v_G'na\ۘ}Ŏ1A9V^I2R$L0m)!Dtǒ(ݽ 2r.!,v[uux񉨮I\YV] ϿoAHuB_ª86%+]bpPL!#ҲF09 0 x{/ 'kp F ;~2~/c;l۾ X&̚)^oz1sَ4Mſ^;Ks4Jiϋay h] ߗxWa].Y}s1>_GuB|x;`Yؗ.Ա\&;nOMEci~@sz\0v*ƌ1B@ BqI8ڑL_Ьo@%zgpa6Lb>PL!-Ygf'g~0ƐVZZ݆eP%~NM.ݥqJK3Fo[MܶmG tl6{5xR 8Q{ PWsW lˎ^h{&zceI_rz@,]^L\ϖ, k!-tx>Mn'~Oxnc]:wJl)Λ4ݕ?"_[rD]_Mһ3(E:Kox8EF%a4 wxmx,{nk6BWz55?/n89Tye%<^w4,fggAJeh&ßvJdfwCKMM,lң ۰mΒgwXo\׫3L kR`&N=7||lB))ROVIp'ٽa&OxnVb`fS qD[NN6!pfW[vHv4 Dg@oK]ǝ7 O>"(IJxl$\{ ֥ ]B nw5ƌvi)^l߱֬evҋnjYsa& y=f D)%~^ݺa葃!D98!#,޶ztt=sG' {.8i̱so/Ͽ{. .= 7lB0F<[Y]n])KЅ.t. > [lE! X򽽬߰Ek6hOY66hOv5w~x'Qfm;!Wњ1f]`RJ 2oS[qWcZEWT-FUI$6G3ns]'}b0-[Qq7>B>J8?kYGZ<6yRs,Zz/w剿t^_^^&NU\w 6o-ƂEK"]%VbxQU]]%~̜=eex)\}Ÿ?ö6mيG'<`0ADcϼ3^cp͕ߝL9'7;mlze!_1 ?(|KNxx5m?A(gU !jA39f0srr͛7˜-?L *IދH[flV6c\jK$*6{ %>!6g#p u;~} }NBȯl@s$.j3mێﺵḦ< m۞$qH؆6(HI!%mA:Uuv.\Md`BڤO?h|iN/B!->;PXj5n7?8N5ZA0NlIkp¯عUEfݬmBi~&B!*޶w=cG!++@4+W942iC>'vk//c}?oY&/Ml P t?(B!BAJ%W`~h8&6 B!BZC<ƄB!BHK`L!B!M`L!B!M`L!B!M;'zW!B!g!͢1!B!6B!B!'ɸCU !B!i !B!i !B!iE0.((`EEEj@ ض<B0R2)%S&B!,bYYY,|TWW3 Ze;(1!B![9PR'=mpXMMMt}˲n6cEB!B7B@49gm3cLVSS|>,**b|Й:ij_S$B!ҦZ=1pS-v~ 7B B!1`|qP( ??_nذ HR99 Mjm0cRJf6 eA [ډKitc\%?D!BN -pA8R ű `b6s\L43n)(ɍ7ߌo0gɯe˖&,%%%%IlgU!|0ƕB!qRJ&h0i0 rd8c'%VmI4X帥qɵbcN Aݬgee؛9]Ӿ ڠPn&r}_m.Ml&B!mXTUem;EH Zb͛ 3fد(;;;nyyy-R8H ıa >@l(B,++,b!̚}#B!B!{UMBrX0dN0 p0.| 12kT[*G]p<"a <7PC|0 f&x<< 1meqW#(iyW_yƞ~zb3!B!Es&`!<)jynnT@bP_i3/cq PPPG~@ gLur˲P].7 !im38bP($ H-:70J(,,DNNdxqS)vqnn.sBpl#7c9gpipB?(-sR\!B!ȄN#EQ(2 A4dn[j&@}ɔJP}'Jg3xKV5'WWW^z1+**s5`pB Ȍ1:\.SE  .TTUU8 %R16B!BH!EQm\J9 \ B4MvCUU ȪJ\_n;zb/))999";;[lذ@8DxeR̝P\\\躮\.WVV**TMƘ*8jmm"T*cLeT۶5gcLu$˲ƘSٸ!B!BpƘ9WEP(.!ռ^K)U)9W9Bk5MS4MSBv++J^Xuu5T;mxb+++Ås̙Fc۶si!vB.tplV,R9O8!B!fs!D4g !4M`&\.B"%)Wc%\.({]M2m۶+BrDee%x<z[r8*vLS)v\a*۶Dffa0[Qf&¡3EQ`Y,V9 IDAT,1ݧU۶uEQt)ehEc"B!R]`0#"C:S5Sa>󧮇T47|o;x{L !B~+Bc`YX޹R(b۶-"UZ%ѐXm.MӌvvǶm 1&86 BL5p=}٫J1sE\Eh7M)pUUUbL C+#ᠭruƘ.0-# u[῟~s`Ֆݨ54:ƀᴳ)9K_+qI<#L? +>}?0 O{ [wBic.)鹫2 `GqtlqX=I NUUmRJ )Ns d˜SN W 1hRsEp_uթ"=YEa!2p)_0>GDoB sf!9\UUM4ݶmw퀴,XR8qם؟{ض ۶!D]]]$-0~.4uۼ&݀p:¥W `ͨTȹ3 #NCVԃZ-|_l v#2C*2)|iyc?R,ų9: ƄBA&##ᔔ0Ơ( E|XOw{GN$\͹iS5 SxUUmK]%cL.~ ɢ"VPPT Q877p9Ղ&9];aBi%[k DL(f<=GNHQMԔlyŖu}'NGC4~8~8ex_s=^zwa|lX<z+7wVB!Ddmi2Mز1,Z9`P͛7s 8`h,f04Mb57Nm_w <)?\=qC:!nXm|u¯͏b e?WzP:2ViJAbլcw q/2;7"P]!?YHJQRGytFm%B*RR w`H Ԙ:2|pBuẼT$z*wV3qDUE-ۇA:8kS4Ԛ5~ؑ]ۡc\h!J^hF މ;"9V-j,7Rw]MBi˂;QmH¡87!rR6:)²9w)bضm].WU@ $ *ljI555ncB"PMTUUlib4煕21{ZNiI6|19XGUڷђ؍9 3 gwaXd~xB<06?wr6־>6{>{#~M\  r/[ϦN[ed`zKŸtǯ5_xޝ6 [-H0pO6y.$+HdRJoN: y#O KpMLqx3mL;|jl 0o0spgcPfd .,xXw66{~7z<:_85}9?//b{0"Jdz$}m )YRͿ]Wևc:xJBiMS's5ќuY&isUQŶm 3MAxd kVhc0  ,++¶mzY01lCB'kK\Df۹s'9m!3fnVyލbgŸxxl~?bvř8fPg.)Q 7vXLҩ[3ZvsC(%Ǥ6C3w }[* iTb˒ҲqSx!H}rJNUb (Aɸg#j,}N(-a^ʙ`Têɨ)P_=Tڟ_bycjcQGGfLT,C@\n;0ۿLÏy|xqB!-9} -Hs!mn^WW9vVVK1_hdò,9mr1!Gxjw>;n-w4 QQQj@2|PU5mB`̙'˷:NC͙ega< ",)pQCГ/Z؂%KK!06PJ+"#rfu.C vEodcO5z= QUSQL[pOPOHlp+P3Ηq&%s؁i¤noa) +|Ybc, s4L|+xrY;Dr$0hhZqeWsCDIy]x<:SAz4r4a H\3{?NC4+q{< C!}s q0B(a UUrx9z9|2r1DOz3s|2td9,c'r~G ?ia![SՏuVzS&} !{n2mÿe娭 mHޮiY2wl\9wrh$2۶eY0  {dF}_gYV4 !LJT( [wm" _z Rӽ-uV%~e=!OT2O#}fD<=!@EY%ÎEv@QdFV10k^i|vf/uj6-Z#pd_Qٿ_uDz%s+ T[wd,|=*~/n>3oNhd,ۏ1+ zq߱=20Wޅ.-*a?lL<=u0gMmޣC7/X˞?Z~@9`["wɭXB%sX0$gݐtBLUh.M\go$^ֈP( Èa5s(eNDR3fMhދ HH ڥ`ɶE9@LEմfch:'pcаApEE2,@٘+_^:J,2\۱xH%A#Y F= Nq:JAyN0Dey\aZѩuq蓘Y;*yXV`U0#PzؾcG'7hML9=TONhBetvɧcI[÷+b*6LN.q݇!BZK.)% DYYyt(Xs){c9)2fYXN2R2 ww۶b3 lT P@Y]SS@VFmbn%4BH\:\3)zO Sept005ԟ `/g8xp?7Æs5˰x]ÆDQ^fpc¢-T@yȩN4C'ޱlrNsXksވ[ia?ݳ7irɤ ZT{{?cyspk5NZc)8s'B!!*uMUk4tRV )Q^^gPX4f}&ΜnN8x"d TWa`ѵ7ו"ˠK/^?R2##/ iޅѕ92#ݰy ͍&V/Y:s8cJ9r99]"0IJW 9ΌnFN1<Y?' [T)~0%KEfaxGLs07v<:OBi ӄ.ͱ !È=c Yp˅̌p2 CNi&?c3m Lӌ]1`\RZH e%UֿzN]:dW  t!i널wn*f[(^Uo*mkO}*=1xu.H/AQnZ딋3qF ތ96bDrT93°Fr(-:P{Sa>Ϟv*|[S cო<Ԍ<M`a8Biyisd*JE'X`0a(+@Vf+*.23ڡ!È ǁ@ }Xn{0 9g]T0mE ǟhCH@[\t@ عsJvĎۣ턐 *HK᧲3pftFm>mmtVa}ÎDGߠJ|Eٯy=h5<}YS;[9 :F|i{gQ t]'L!=u=~|5D$*G`)aCzT̯A7TnN!g&jkk9v6m #+ ʼnBm@}7jj[+%lݺ8`_mCHJ,\3{̞=;wD(BaJ,YHiCd)f=s5~7roDOn/ LhaRQ4&n8e|9ei`%Qӫx(<`;4 uk >xgV1!p㈑C@X-tf:;:ugQ,V_)Yg;zFNcX }Pb>xOC mv>{hQLB!-4MT 烮iui>*צXvoN8@fF8 7em^xh}pRJl޼9]33;a |dСtfΚt[[667H =\ydm b;~b>Jn-y'y-aqw p6.ق{x#ش.CZըI PuL0͔\u~$M`^ =4xCFy{(aQ#1y?ƪ^D/gČ20|T^ (&/FÎr[-':t$*OMC/PY< cDf:Up)B!Wb_j*4M5-sʥfz+fԽxo!E՟ ,!^MWT9c˄NT_~Øb9wI+Cxչ(imagQb ~?ʏ7]&%cWA8:u nfޅO_N ͘9O^DŽ;/׾ΔLEoŕz}N2+q0=OaJazTFc%uo[Waæ (;ux[#ai,a[۟LJ?Vp"L~3pS[]:F(?xZ kMŇ_,B]9Oì7_wE[m:,)>t;ӏ%;cNPOb;!BZLӪI .]GzZ*++a63LHr#3]q@hi ^ϝ,;R=63pWHD+Kb_ F b˳c@7w1kS5#xr8+ P <{+ N{2;e5;Id9cWLn߿Dzex'ˎw>A?u־>XT*-<'tvkxoNXyٽxHcU]g -VcNLt.numƝ]/ĤA^ 9p_&rΛ.}+=Q4Td/'u=JL=g8:#s&mIwqK)/CrكxҼ*Xy# HE?ୢW8ڏO<"IwX76;}б;g葇CyyG֐htޭ&bʋ`ڒX~dN.G}6$t>_1bS!iÿp Z8%fk9!n n4,nI@)xm)[W[|!^x%XpÑM~#0E HH{xYn7&8:qiG $!BZcVkڥe^]Cqd- ܭ:+*tv( cmK{2l44;wڅpAUL;32 6}{O 'cY+`[T7_j =_sz k؛wN1 ߼ Ϩ|i-Nyݎ9a]g=?T('1cE; xPY* =?4{>ϟ|˒lMųˆg0qmW<}}|Dꈣמ}I7z0@4>zqt>b)8rX{Odr|,Z #@ks||q__1,Si5bл9W#9O|3= IDATy22஭A(5;+ ;/}M9btv?*R:DAMr .ܹ3'3aYPgnö2{ӷl@\בQ)x?,3y3{8iDF6ovUhcQ"/S F%rgvk,=C>}O~0j zuHwaVToǿ37e]rET$D'JHw ݡHII ,vݽw]v&s޹sĝwΙ[YkEףÙf 3; `S%OMk]+IF5 I_e_u"P3V-dDfT*艣724|[/J˶6̢5)YFէ0tY;} X.g$9Va9|^ccסw'[Vp90ch>jQBX:`aمޖ*Mj:5X  zi]UU {C {'^ez+/C UU }Hp=b["u:-Nh2H1UI~gqj:Q %.0$/ѕalX0'DiM$;vϨ2$WN9L[rK|8Y#e.ǻX[Raf~dY5|lhg$-XFR^ޖi\ҸW4nɂ Cw`eɣ=3,NGv*NF:n㲖-А7#P !7o=yȘ0AHXX[:əEVz2'̒$!K..~=8ood2ύWZiAc b DE」,1evF&=~2JÇĺV]qvB yDcIVI{12(%HRr"j_>;Iwߨ$A,eJ"W6o_=zq_W2qe =Z3GSE|zRJ<7'׸×'g{ /q.ϟ&۶^H\BW iF*Ypww!`/K?tO)XfMZRV#TiD hX)m[&a#-'ZR1<9_a: U +$궥5D OjFƫv\Ŵm)ǃ_PΞJNZع?~e`&b_䯇wb$;9v+!&P7z5g2/.3ip75O[ǑX(ܶ{rd].^xH $:!yZ |x9n    )rL3ͨAAAU/(Q"W9ֲU}SNu{h9  3PMK#_+ryAAA,*1.Q~cU5qbf DU\̇ReKh5_'vMCf~֩e  rss '9UbH)_j* y}1LL)UU$))2Jt899!IZ8saFY  91I2*Qٹ4Uɢ* nr-br@"##-_IVVVX ) eQ 2$psNաMotaA^y9>|Uą+(\5jT Hzx*<-GF5WxBک?||kvgLuذ٭cO j,ԙF DmHޫy\Q=~9W__z=?ңe6lWRn}ʂC˂/b-q$Kd4a=^-u}ɺ,~9Axc777)66$JIIIUcܾp2yPQfҏʣq㋧q#ヵuz4XϏ|d4z*!d"Bo7H:X|E|/~=hZ7+|9ş&|^Nϸ vܣpӊxȀ&}>')0=2(<:aMYIBNw0=ThB)^^Rܕ֣a!= T =JYQN9DkYP[:/޳._J>4佚=YeSɰ3]af׾*gY$!=k򦿷1{y"_5dOu?7 cXk9N_Oީ3q_͉SQVjb,K}Ϭϋs~,,uWÝQU0]ByEYZ&; gs⸸i RVO6Gn/kO{S* |kϢ҅\P:(ݮ+5lϱv85D@n_F'ZpH%)0v>Zѐó8pZw֥zay+NZ1Nr^΁i^˗s:84n@)wmp9ЈS4[3b5珞b^Ӑ~H#XM?`G)1__֞T(悳X>)SEeӞ8 :=66LJzytἢ5c2h4&NJp-#Z_qJ#MVz͏R9Ak2g)q7cfH&.ʧ7c渦5y.fV=y@f`Җ)Ԇ,7Mw}ԎV>i(A4;BxK Km/0rL\6~82-"CtT>o:Pcf>U;u/gA˄$zcԮkMw=y,Ǧ d܁0b~BYz*[DT_f64xw)?Iü?eH{W? pv r V3Nbv(S&YS/z܏,=vD;_tAf#j˟}%f׬I,u EawNw`8/ZJtCAt>VX{|ŻۘLF]E8 q-АFz7fY!EB٫=!Xl%6MdN/ncp:|.ٶ|Gwq 評-J|=ƞcn߁,r`Sm(&ڔO: Z53){{:"ۖ/$h "I$B~DV)ȼU'iٷԌȶ ڰDtZ#9,6 co1\kxlsx? S뗱6f##QIF.Eh©KY@pNĢ~3\ +jY?wa:Vqd.#ulӔv2vƎ_ɛD'hS=-c~[8 k Xu$ΔM^m<ƌø%'[B|Vc}]W3HX{cYSUU9]j!mG?7Gr3LYv6h4g^1Z?˼pVtyrcXm7[gk&UBw1zgu6a?%Xu==7燷R|6/FnFV&2>YŕW:mvofzh__&/\.-kwfX~{tUD!,ߺ=+?' \coG&Y LEO!Z" NFPyI1%?UoWb߮_]3ir2Ι}&0-G~/Ob}iz1kz6:ɇ\);d>PQ91/ #Jar}Yuٳ-Garo kwoYmcߓ!ZˈRv/灿_v{.[veèܘ9M ӳf^hC&l͞5hh kg62k7$yٻ)MX6~Wgj|ʀUl޸a\tA$ުmıs9DW ??|<%Q6SmaWп3{mn/w|еAH1jB/YE09}R q52~:G8mdŪ@gf}ɏpwoZS$Wg*Qg޹Jse' >\og߶i4oXl.) ѰǏܼ=FR,fy?2t۳ojFW3AO't?l̘8lI,槣~ ZǾ4-bZ^?ϸ=(]ԗNsa˰UU3$Ŗ/BM~ Wf'OxEklzyXzIr{/[*NUЂλ>j9'ߤ~x 'g_h~b1}]j;x. Ծ e5 RvU|q4uN?(G+cIt]J%s3]o#5 Vg-ꔂ{wCrwiA۔euW `8}:&0^dj5 ;ء'ͤ=l9~ܧ׈. }@Qک[iҝvle{JkAo[GܣDt.)m(m[U>,B{D 'r@{zɃxG6ۓSTu /`u zO߁@ꍞQU u]é-4F '%SySUi+ ^5\ڲۖ,,%]QuEqtTze6f}1Fc匯Y>fĂ&_C:FKqzHHYыG`z_Ӆl?p.`r=-˖c(%=7i+.Oe DGa [qvs^JFD8*pefe;ܬ$Y1moEKl9Aq-{[\ W{ ^<,a]d ;5 xYNOANۘ)(g gbaHήO5IBq!ͺo{Oe1@@ro.e>-@r!&0Ή3ns9{ ̱L"C\YBrb'Y~|H2J̣GĺЪ䈳}$amH&ڼ rd'\#5BIeIEMNf$@$͛rdϜ0_Tf-3sWGdˆJ-i6k/cy6{\xrPAOt$O3 d<֢,=B*wvz 4Wtũ[CŅ5#~Ro@rI"Aei\ƣA*XmѲFȁk͖T{{1歼H`z9JP+~j pήi2iӕA],^$P ypE9V7p>ZTb/mff2z_ ܊LBEѷ~& I*}L1Oq?{dL͉`3]u@y Xы-*a yҹ+{̛=~M:*7"*d_vf{)==Z6×,??̘Ա`jtS3y̝%_E.ЖiY 93)GL:^"1=ž-K~n=uV Bv3~<ΚĈvK0f3u2Vm>*ZwtԄ"])Tk t|JԆ x JDz)J_ й槈-Ƥl*-`ĸGP^b,J:-Ȩdɒ@nמ(Q".\L[͉q:dVOբF_a_}'g}: Iw$MIÈH)I?RuNg3c/0.l6?|C„hQ:bg4AC7!,;觢>#Xc >ŤQ]0ʕuzW6Ou"VT/KHL. dN:'CaZAꜼn9fnRy\LޔmS v',G$yݒ@n!jE m|7sErAS{V]٣1CE1yr_ZBKvCg?dᢁ->ǎV0Rs[ZoJ納R7}"Gq2%{0nދ/b»C*ԩoi=_Iz1tXY;SW|UMN35`no܅XN"{1y odĨ)\N-ѝ=A.1(ٽv?O_^{lբU$߰&t^M 'z ]9x;y|q>LEƣTKStkwr'@·;AI)>|t%)$$D ( z^++%%%kYTUuPUեI& ͯe2rsy$cX.[k/,ܿ!`eeڢ8:&JDEEz2dJwOuFNH>TR}o`<=S_R',~)^Mal@?A/֪q4|ԩbVk)l]-N;b88-fxg'ĕp!GFiv?s |k:]R7!{vYS_h2e9uXter L"i17eeYaIX~}I%IV%Ht$Y`Pn޼:88jՑ#Gf+ o^#56 ⴉFA#kRcVNC{OA 6WH_eS>h9| }^KYpo- {! w`Gq. .)Aȉ8VavUĿ|dUB6U?M))ĢV5AH[x,ԭ[ײ([9o72mj YR̲\x$\k`nъq[[Y B ZX7bA@$oN˲/TD _{3[[t h4 uAAAxDb>o2/2b,%’$XAAN$oov+fYeiՖrf    7Lf eC,ƀ@4 .] ePvmˢ\m.  ]<AAAxDbMy"),\r2)2Zjh4bAAAH0i㴭i[kImZHi,3@Ӓ$)=rAAAI׭_$iRUT@}*U9&&&ݰIIIf,pssK7g   ?$m۴AUUL&k9N˲̺?[*Z(Bmee!1~ZuAAAx^Xxvi[d&iWZWWWӕ=KbkY'AlIII\t2eXAA+ٲ@2'ji ¿O>7,C@׏p3COĿ.6o)z AlYrVbnAl1ӁC8pd͵gl8ʣ{C.0ӾÈuKտnK<ԃ?(W PdSxːn2%:8%;3Guwa޷̪N%6uo xلQN!aQHGY%Oec=Y: ՝JH2>Nc]|`ĪT>}LbcټItl9u).]úc4]71 5cJrTO QyQC=IoBgso` ɞwՠ_4=1^CGgD\^3* QA7pEɌ W w(()6Z {{{SV=/ߙ6azE#>#>~5lķQZw ̓8v/Kʛ~n?#S MA4-ne) U u 9P\ Va<5;*S~ :ɕju su1BU۷!*C&_]WqIQO\յAλק}U/tR r.!sa]$%3{W/OVc1{7v;< t.얡B\ӈUKs+GqL3D/?=TxzxG-y?\\\1)NhVA goqV-vQ1B,]\ruٍJe-ƓjՊJtN75C۶%e-Z}x"U@!.luGƮ`k6Hs0zТsZGġMnLJ }4V@?w*;ߨٴwbe(u^<pd(BA^+ 6M[v8Ж:]jU>|봥"Eꚮ̲[*ɧZ$@%SݏJdQ6X=i]qUVAȎ8%Ȳݓ~YFVU2.*gq,z@1̡O%:*ԯqvqBPrxeN"#0$HGۂ!߸ujF|:Эs-m ܼ_B)ԀmO<$ هrZ0%qu\&Gc>LDTD$[t 7Wl#TLX>[; }ԛI&2id<=nԨgNd&.MS^6_Ļ9!H3Õ- XIhx>RqvwKsԢ J,=((w0AN9%x도qxW0mB;F݉B̃gF )@!B'$MC Y,_4(ؼ])ΝĦmJv|26cA#7eBl?mRZJqrٸRP! *dJ2 GggҖt\pNXPKΔsj-5.u4T3w7reH~52<$dG!n&!Im̸2 v~yuڇ_bԉL՛ q*Dn_Rs6Ok(֤E r.C .p>*x!,xǢ{K~g9T/M|oYy{6n̨Q#[R AVv"@*J^e85왌-ll<_{ѓuiIF8G&#̦cz r3p{&_V||qۿjX(?J94&UL١pЄ^|9ϟ_BZ'ж}MSp{A8tA,\v-ÿbbb2g/&&r: Mrj ζyl5G!t(f uϋ x 2Mg1(O>όK:GU5;x8L)/6FHz͛a$*|nhMFSPk~.k# e+ԡL~=Dΰvu׬D#..nTއ?3}m2ol?!\5,bj#MZp11)owr,8뵙>y]:w׉ܲ?YCxw`1}GQmlI6 T IDATB RB)RE E" "&RENBIyH!Y&x͕̞ {93vaVߓa6)?l)mF0җ:P7r%8 Ӏ~Y;ۢIkYxߴ$Akj^% Dr6V~<p*M}HMIcy (Ba&(""r҈quRK\1Ia#ǹzuMy\qv?w<<ٽR8u}DZaYhЂeֻOoruv~#m_sbx) sd<,N!e>3O[36ܐUfx wBsoJi?k4 X6<ً@ϐ<2,y=CqhQ ?cû?֊1dQY_ _wZ=޵hԇЦ_w 8ݺIhhsm ҧBC +IkvTN|ƃ?^~hٴ7dU嬵0NM]<|W>y7ojAuKڮf˷ k͘)pO! OBeQ!Ʀ'!cԠqK͆W S.=Ӆ:.""7 #}f޽{h#..(_mzxx8L˲ܽSRR<O4}lm;0""byƈ_M=JbŰ,cǏS4,,sT0fPmt:2N' ۵ܶ,?_F .# ({jԨA`` x{{:ruEFFzu}$ @XVN>Zs ٳg]TB\KrKMM!..޵,TrrkIoeߺED ;abw>qADDDqs-Hëg3kҳ8/r18aN`xCu1 3Yw(BEo]s?L/wAᦏr ƿӐwF!]Ϙ|v!`nTNtv6_9mnSfo)'ueԸ`u&8*-ylc4-""""z 2Gu,?oߢcP);}{.=Er͹:4-,cu,|2{31ۜND/Xt-ا,jϛ˿`㇃(u<=H?f㦕L0oh$L]+}i{M[btǒEĊUxhC@jW-aL_ lX!9O,H^` ϝ[8ù IVizI?)FpĖcu:?&8>YOeؖZ9[LչoXoDLYҭ3v~沋uKɧ3i#[aoX}iڨ>4'D ׫>}/_lEUDY@־0ԥvtq)9|w{vt/ZƓʾY}h֬M5ID՛j +`F;ohV~̆W~9pݪѮ۝qԫT.0wԻ 8iP(QGO;WѢ/+zcܩ Umf+HAtO>eYiӉeXN rr>Q%32w+k&-ݩ}`[>>gW1ja+d~c~j3w?OL/'CX[n/ۅu,kkN [MlJ9OG rx<}/<ͬ!W$vf'H%x`"ZT͵3gbI+G28ٵ2XcOo9 mG@a?"mux!o8 .&8է~7,=g,m]`G^?$bxt x+E_9M*`'淽p QDDD &cɑ}sfc,^4zf#=s_c}q.M nE _m떴ev>:{QŜOWNo7>:U;߻|4 oF {md]/}n!F^飭&%Z>Hg%<ьv"#OoNmynu,FXkLoX +k= pNCs$ 6mW=z"6=!y`0p nY_,07+Ѩ~}|."""ӿ!}4/លKe@Y+J~> `in&=fA͙*w+094ԗ^VMU=mY72}=ֹ=nm,fWY]_~.un1sۋ VY<cɑڒƸe/eѱx}:r`ҟݿRknn&/xGku LX Bx#hzEW cIހ _6mPixb cڈg,`[%i4y".隍ZDQUkGH`,""""""h """"""R)H`,""ZUDDDUo~<$""k|}}ZkY1c4MWZ@SEDDDDDq9 yxFEDDDDD 0M00L3mu;}0  fژkz6溞+g!O2c( Lp_#QZ˨`SPT0v YkWRH`,""""""h """"""R["""@jj*$>!IDD$xSj̛SAXDD8p %KhhkHbTVյ;s x&uø:kʺ^t`,""'$(H+Z4 ="|K]KjD<^kYDDDDD䆤Mr;t-ܐKJZXDDDDDn| ?Ē"EDDDD䆧k_l?NgվhVvmSZz+4)^D{]% >v- z+uBb"ǏT\-W/ _,r-)c6>{q$7Kiw`d\""7Nlϴ+j19= )_&ѶUxUdP~Nڱ߲jO(L;s(G'HH_DD곉0~#>ǽHW_|´qd$ח\%4UB W9LtgFRT &i_DDD ߲BI*Tٵxb[s- ,ʒv /*Dt~n6:Byۛ>Ցoyl,z` zdݥAk0]hb^ώ1]pPݍj6>}_dp 1)>Tl:1O͹Ory>Սgw*b,S(]>z&b6OcuD;[{q$qXLɔ_|0Ӻh.OKdv,o4e lZ2Q>47?[ctK_;^9ȦPz+\zEn`+Yj%&d@-o_&eX VOo(r;$(%VC$$1;P1׳OXSNeGB$cZ7r|Mˏ"""(_dԨߩwMԨq\?HAeǝ!(L`; sNBU(>^x8~F5?<¨۷gIoej, f۹fON`Wxր;}鿗` AiQޣlM.>掐X҆//g֮=5UO+s+vfL 7hЍ.U11 ѐNp/"""RC)q-+jAZ53y"rUsgmr γ+DakQT3iNR!~?"X~1Ǩ$L%ža`YVο#>e0MٿrsWh8OdE#rYY91C(l"YqsaZ$[9`c"ȵHtr"r sGil'˸8M7鼝3 Y(L9bb $}'1m*̦Q-xb`_ٜTwΓΐG[L䋙tA1]z 3§< ҏ:ɉhdWYDDD (3xChcV ?Ks]ym~:;R҅qx9ߤ̀} gPzq< H:kwR=VLŝϾKx!3$Z_LZW'-?Пor4ʺCʹnUߝr">g&t'd""""WL8@Mg0Cȃ!]Ywpڷ.=#+Y) 6L?ڗA3[w|= ՑVw Iy<_䓧A&Ɍ֌4מrZDDD|FX pX~ϵ"[dkzL\@B-^Q^eqn]۩lk̓60>ﱫO5[MYOήǓYZ}%h8h* ],]AS?k6X"""" /#"fw{~D8Rc=o1N0=@DDD .|FXD.'^~N2 ؀q5L[% Ɯa """"q>۱ָZDDDDDD L^ iBkDDDDDDrq>37̍>DDDDDDq>#gn!"""""||jt!]DDrQe\kY13ysCD$/UR}A&\KժU\r)3V$37KiRz5ײ cgn!"""""󙼸Un}|&/gn}|&/FfsCDDDDD$/(3y?sCDDDDD$/(3y12}F""""""yA8ɋ?Fчd0M41 Ñu1 4q8zN ^m L^դ`E/}.W+>DDRTI6(?@jU])$WٹCrKVUTz(ED$'$(H+Z4xײ\c1g&WR*P\ZI8ɋO,Y%i# IDATݾ7Ժe+PFEDDDDơ`vݨko1%|P?`(3 d,"""""9LgE$؜iZX˵`cyS9Hsݙ}FDDDD|ƶ "}eƝwq]N8:? w2A@ڷ>odҞNfwkۍN8оI]U6=ybη$oWc\ce֣EDDD$߻n>J "JְathtMm'26g\ȨmiԨ)]1sG Weݜ\Zkd;: V>iR`XS6BZ!s/)nӧ')bx\Mwƛ˘9yhB,@ņw?˔Rxm9uLYӥn9tԦDN&^]GS5g}ȚQlNȳKM^C2&OoȎןafLgfM5X8jo·3^{H?W?w/Odz-Ġ 0'MaC|y3DNPI0ik}-3]F=Ѵ>'Nfr'VB<қTit#p Y:! ܋5c}~$RaS7Xʆ}8=C\143C+Yـ1Ҿ^$?%}*yݴ-}Y/ %MEGڋSq[2zO5?܃ճ#$B<ӡ:rΕqKNJޘ/7wjCCz&L)?aٗrXr(Vvb.$ 潉qyZvቩ87^ xT #2$v CMKRpT!M~Wsڵ?mZ/^%1d̴00qsz d9~ gƊy0t[:0pha!( vbS'9 לӛ$ϓ^K2wywdxAOЧN(6]2/[šyiDWOQ-g xlFBҷ쳜B_F`xd &!KQs[2HY; Bڌc̙7F>}Powo9*q|cyxxޮ@ћ2a F"Y(+|O߷gq_uy^dWЗ…%㈋KOYO9RZ}͙~xRLpJ(lx@#1@Wcy (Ba&UW,ה6a-=o 'q0*aϿlC*)b$[61Ut(aaaiKtj֥^SH6Dn[ħӿ ds0X[o3S#/jmLhiR;4E졟l 6&KD'))6V~<p*M}HMqy#4{~Ş?cKv|76.ĉ2U & ƾD~7hM ycYu_p4 I G DDDD.qb_D五~-7R|$>zm ҧBC +I98^b*OLʛ1zE1i<)MV8j]LeKq+9(D!r4C qZGYGEl,MʶlCXkz|G1o3\x:4 K牉0-g[:ж슬07Δ1-2#0~D)= yfWOr3F07/9j?$vt{T57_:0|BxWkƾܛJ&q'Q:hRUmpXkL9ׇ~R IxR-'UIy<_꺾Fѣ{F\\Q|y#::p$$$e{{{xiضgv`DDr۶m+}JeYض͑G)W,N3=WӉeY$\ŚӉeXN rr>1?\/݆ llWĵ,r9y$9_3 0s%&w-ej+{~KZwEnH_E]"""nӖW띻y\`p`&if; ֖nfGe\u%>paˡC)] mK.moi0,J.''&&c%'';CBBÇ~~~vHH]Z5{̘1F""""""R)H`,""""""h """"""R)H`,""""""CddkYDD$WEFFZk͵ ""RUR}A&\KժU\r)iRz5ײJ-""""""h """"""R)H`,""""""hz\5k{Me^|Kxf~ÊhӰ $$,6w&\`|y4w^ ol+<{?N\#"jLyV9c֯]K8tсuou /T8H|BkHZժ&^OOCϱ3ܑW"B=|KsOa[``DZWxf7:qXN/;_ٚBCρ? Q>q^{OcGO8O~SXM$^%^uF2F6C; hʙ/0]D%WGj]6L3# ;8 '{cm 2ڑ28 W}X1'U)_A/Y8x&oqjÔ^_c"r8HR%)$""k"#طիUumkH)7fM#j|sٴ};[Ha [NllcOp2vТ̕ZGqTGfˆPl|ͧ~3֯*Nڀw>x{7oc1is6|g džbwq|r JJj"YCe9ڡ#v-gmVJUAF1Խ|ڿiNS'5%>ĠE bsEZkL:gB<ͩ͟lW6/E0-l-; x>͋)reܪӡG-h}TuP4.fw,pen#śӥͦߓ A`Þt5S'8OY5ϲU[I_Թ;v#;S[pyc,Il^F&TJxe}k) 4cÅ10Bwe҈ƕ?椣9N3*រLJEDDDD`Ј5y<8 Pw4D"i,V{?ǜ.E./j8"3-e& iɔ$܋6_t {r#jO0(>sI<>MLOTίl06NGwk1/7rP̚B3S+G1u2f>w<7e 5<.s~Xh8O<2;2 ׌rkݕ-3]xtmjcI3VJ]Y[wNRqE//ዥL oaւ[ [>s y&.eR|׵W|k dcOdf1fȼ5 q-HwC}"^QVz,aÉ""""""(u,ݯvN|?/?~'z\ds곧i=`Gג'ON|r'y#υwgKiw`]Ss2n("""i*\ܨRvr[2M7O_H}1GfpKW1A9">AJ3v"eu%ˋ"f8w7u "rqnf>/<,]9=K8jIeT,G›X} 5}\ fE`;3 o [.0{r]Ds/ji 8EOG/>N,eva>'pC+&7jL6=`?؜tu/"R}l.OuoC hy(vɜlE`4oܘƭ{3bO{ѸQ#›K+#6|'T6r*i+g sp7iGGY;n Fyx8zbC|wY/+&ү}3GaTK{ukfN& o܂MacAthBxo܆ip8p8X}MϺcKH!\Ϋ:Ҵa>8يZɛ) iQ0wܼPܚ>OD4hڞ/}Ğ?( h&k؜Nast`lsDžݖFu3wGՉHc D})WaL\.nӧ')bx\Mwƛ˘9yhB,@ņw?˔Rxm9uLYӥn9tԦDN^]GS5g}ȚQlNȳKM^C2&OoȎןafLgfM5X8jo·3^{H?W?w/Odz-Ġ 0'MaC|y3DNPI0ik}-3/=|ƾGr8CpRAG?[(8_2jb5^nŬex fH GWi 0b,"A*?yu͝rNWg ʆ%k>* T.~۰yPK/jqÇ*t9}=+W{:{&touÏ^=LʔKٰ/g+xFyh%+"С?]׋d{t4~)^dr_Jj{}#I!oVふA8#o[HoѫY~Xb2 VG, 9#W]ewn3!HFIֶ9bIIpH$-(mXHubZ2y\DDDg~Q ʔ-"8;.M}{,?jU#BBɬԒbU IDATvU2s:;؝]>4~۶L VLI#|mV/m|S)"##]p/ZC]ril28eݯF52Yvېf/{y PcI[:rlޓE&_GӸd2w'?ջHH;dܵߎۘZҾ6f#Y`ϊ7rA[p ,䝍dasjJʙmݖ}sx_I+=8xREDD`1}kG>Ai&?tMqC8r2tMDx0aк WC<cPNer\ϋ)x6)V6=OadfX^\;U頡 ⟨~e@껋Yg[zcbV`P=tnhGnrԿ3+.ܠ&y?1i]L?J՘ynxy_0l:C"%pG޳7F<ʏI6~EWFOk 2x!ou(C؛8RZL$3GJAZufL{p,BXh~a,W 9+ĵN:Tjҋ#ڸF+`3G;͟!ץ16oFe̤S`:>i^=rgP?1lԨQۍD#55ը\h9M˲|+曕1M3 ۶KifmضiYmsA*Umw:X{Slw:3YtX%"W#Gqcoo>]`|`RGY[YQRd~ko9sطooxCXDDDDDz:X_`DDD;33j5k___j֬QxDDDif&fD9P><'O\d>OSQl65<լ'o:_lh$;` y0 I_~Tw\x0 9sg^." zR/[4U3HG ۔S4MH.ӻ']ZѨ~QM[ ˲ѽQy7~TݻuŲ,>Cḟu˷l 3[O2eIy3-pofњ je7ޭgpEʫ>ܗ_Y\5뗽miy그p귙N툈'cKl@nݽZ vW@޺"W'QiY%ÇRHeĽ1ژQ-3m`ߩ5bbm׋'f$Ҹ\- gtˋg2g;GGu3NU71cpOZ69u 6&f:7j9:,jf1T'¦k89Jf'ڪM[t?;NOuf4>IoNtd6 Z Ilæ 48ɞc+Ŷ#/,y㉞"fII O(]ڴYLKn5k:MWoڶSt,A~>TfPցk:,}6}Ǒ#ж=ݟAݘ=)xLW^EDDD<[r.ɔs7g]AX}:ͣ1Ե6i'Qo.닐gnթzo灉s0Ս>7dR3Hi+'#mʞL-ADXqz5+'"osCٔi pM ㍤L_G"l;)AEIf'7u oVeƣaIN?$k;<>z'JJb^lf+YQChM>Q{f@,}!dcr&,ju+Z6SSDDD[5.mSѠACnj>'tER10䇄V2E{սuK@F\?`;kѳ_}t 4Y' ڇL "VHY$FL,s`tlϒe{SO-^:V,aSE/UuV53A&ջ uN(oқakV||ҥj1L3lG_Mx8Z r.F5Q"Nla'[8n\ $%%0ZO1:߆lJ#YH᤯ ʖ-.tr+rpcشnճ"`<ޯ;׷6gL"л= 8@hhѼOGpV^֚ZѢ ]3#&Od\L:Kf#gyΙ,-OHOC&`q,IDf$<>αPJEEnx%<Iu )Y'HL:šhӪ-Zebfq* 8f́ұ}?){)k߾ gv\(iɸ&f_8ߚ5Kץ`ůi׺H=AR |͝?[W`R%KsӏML<=񌼰fH]+Q#p=(Ff\_~ậY&(؇o$Qw KxK|i_`#ϝ}4V40)^o^6)xģy>JjV/ "4U /ٰ}}(u2%,ԊY`T O?CS6C[noWUwh>ۣym;UkjGlqDDDDP0лW/LdghiһW/f+IkX ժPL',[4~۶L VLI#|&i".ߖ7"22u+];g5$E۬.G?{&sY*|oY#5,pf'ًõE>ů/c}?mx6&@`'YY6V.~: eޑAH]b2t9y<=?u;\"`&ض DޅakN""""guDV*w9s~"֣7s)ӕh3Ylv ͣzEDD.֟wn-x/K@@41M3wp`F6Ϻi׉=7>wgaٻ ]GEu4 ae'O2M3+ t[pf͚1c8^|+[3` /2g\y?in?9 DJ8,fl]V:K ח#zͦM).[ 4w^>-"W!' >t]19+c`ժVęQe+ """"礟EDDDDDPS0.DGGŪUV8:ڻ,"""""rI("IIGg%)wYDDDDD1ƅ@nYA4c 00ﲈEO`@wY0")Xٱc';wnhQwY0c4Mjժ]B@SEDDDDDPS0BMXDDDDDD 5c)EDDDDDPS0BMXDDDDDD 5c)| ""RxdggknӽDDD(F50MQ^MED ]vS|9JEDx7%Uw\ABDKKOW(J$--ͻ,Wj """"""R)H`,""""""j """"""R)H`,"(s9`y]efJ)˻EDDDD>Nac3l tD4 {%o'bpiNnXsNOMDHg?ד:>vkߊMci&lOsמolJ)""""`,"AX}:͢C(u-MIԋKXKV77w?_tSϘvqޝ8]NϜ#X]?~oI&mH.haQ=瓶8}76B w뾶b\)oO彉sgX_v|J$R U)B&`%dbJ `XEDDD\NDfn4hА[pω7;+GPT ?̆+!4LQ^n~DuCݒ>`P=O'XbZ׀p-݂.Mm֯aSB1~;q !56&C>Nv?u:!0QY!'Xao7ӻ_}}(Z_/e]Tlt]9a$[7;@rBIX5-wDZDDDD vw""7ì>0LR}Ŵ摓3x;.»3@^MSX;LV<2}=yXKZ:پ G Mɸg1L*V= "p{xMzn%<Ӷ\X)}8z %DޖXm]3>L?Mp9+c ?BҵܻGiiǴS)ϰɉft8Nb!<="*DnF)Q"x`xZnκ8*Fu0?ʾ/2hxNCvTs""""r.gtQ ʔ-"8;.=OoOSj$ٙdm𼘕ZҮVfN_S`~x އoi@)idy5+}m~kG>o.p4-WI$,-QgjV{vq&Re>5#i4 _সt9{:&"< h]es!VOǂ1 (]u ?Jz9L;Fp<ۤX> ؇cyqrT62+pׄz '@*5m3˳Km3/2'q"h篧FEDDD$}gԨQۍD#55ը\h9M˲|+曕1M3 ۶KifmضiYmsA*Umw:X{Slw:3YtX%"W#Gqcoo>]`|`RGY[Ļ|ԏ]ko@{={RȑӖhѢa3 #ղt 7ɓYifXpk߾}vPPn׬Y3f4ZDDDDDD 5>β h/8sjVs{ǁ9 s܎""""""(6FЖ-v|+⿯嫄dwvPAʟy]7  g3[Rl&Fo޴5\׏=3~,FTj8_3wэפ=cv/|8;РUzPsV wD7~9z{N؜}ՆFQ?vz _j !G4 7;dWs]ִk^_l$MlɺƵЊM3am`;8>k22LKlU_Wix6swL~>1?sKױ׸dC,~uu|_7˘ (j # 4M=k"iy"4ְ񸓃n%馆-ZůR=T)74dl_f{_/jI=WO,]DF*tE첃P1=/_I IDAT,Aj\V ?u©ljDJL)+NgͦdnG(%3d  )vҶL҉T I`tI$=Z.g$ hI+f#?oN<А>FhXDDDDD.B*nCn<+Si<2D7+bC"0o_?/޷d AcB!d!') 9q6#,>% 0^^xSFt<4O_K3.-"@`` *$"""@||<e )DM῟I5oo_wOEWNI&-27V IҦOِ`[|zt7O||EvmZ?ߗz~8O`GB1jUm *aQ0c:eSzuvݻDDD Fe + 14[vTkNX\!5bj4OuࠢD6F_jypXTw6!*p{yd*Ȅ?' cJd$?t?E+|p:FhXr1MZjzEDDD BA߻\!Zњ8^5:.A7qK ')Eׯ-J91V#""""""J-͉=TG·l[J%"""""W??yp/8Oc֜_|%"""""E bA0k溊H`,""""""j:XDf׮ݤ{7%P5j`(bv\rnK >>;wQf &3H!P,""r*IZZwY0c)EDDDDDq L._R:XDDDDDJJJ"-=41 4]ޏˆa0M0 L[<9|5e{iRlǗH!B@@ip8\8S!/-(ñgrTj)EDDDDDPS0BMXD 9s9`yHaoȵNac3l E)Q: ;>^u ?ԽAaDm\$8zcGч{V/""""\C|=#f)3rؓLMyw>oți]R|׀ݻ;/KDDDD.}kHCXl`S?H謍jٝi;@{NiKl^<1{'؜X6o?3k_^^gN؜s?ax\bcbh֪qۦ#fb}o%K[Z6Y& u'Y`sxUo^ߖo""""rv1kAX}:ͣ1I_Z^7EJ3J3ѭ:u1CO<0qs9G|yCBW0ߓL*?u6}a>zy)>`Ed$M iLN 7?>S>Uǩt #˨s˸|,N*n,\)))d>&ឥs|^6 i:Ş'>usÙ+>۵sS*2^XXD!lڍUmLJ0ba6,\ITۨYrǁ=սuK>TiuO'\pw֢[Х [ ڇ X]'-js}|;͎=k2mLLFq*װBӠ%9d=7I # Ñs+{yspνwp 9m?{.J*`,Çٹsի@ҥz\l>ô3IӞzGN΀GMSX;LV<2}=%7JGpV^֚WVim\>iL}O@z?;MHypTϑ5e1&Jצ\X> ,ˋ+J44g/ݟc^g.J.)3`qps|6^[Z ~q,m7%\DDDDJXÇsGoU?u|fNg/ K.eЀṯ\\F~C'3 7agqz<ls n2ۻ|f{pzܻܗWr+xOGU/F?kp;̼=˫W6J`'- """"rNJ--D[=w ǐL#rގ8%%%ӫC""""""W3c9  /\_naq9=p,\HnhӪEDDDDD R|K'ʔ)M )@Jqy0\[le˖9ÇӺUKM7Qd""""""W!1)AO<-[skƍѡ}{6iLHHyRRRXa#K-c_t:IHHp]z=-kSѸQCȥfYN,~d6#]|4Mð,Wu*4m pݻHن˜{׺}rR0|~޶مGyg }oז#G0YBN'׬ԩ ƎNJO?Wv,mᰱ1ܱ7%۶=Qc;g’ ƒk֭>}5j /Pj=DFFRTiԯO G׻O Ν;քzDDDDD2s/'66ps&e`bb`` mt>H x|Ϡ`,ݻG;vGQȹ -Jtܙ>{OժU7C5::9EG{,"W`` *$"""@||<+¶2-lLhm`M, L0Mp`ئ  lTkpi m3džTx!8w`ȑ^߯1q$>='6m(R_xbŊ2w|u\Z[D.իcNv$"""@`` 5jT._u ˉ+&i``baamC4`ئimh JW#caIgnӺ#G>|ĠAɨgرc ,0ꙋ?piRVMﲈv[[4θ&`cҵPӉIuVe}[L=>(S4sw}d xqvq\s^:33bŊy8._@@@cnjm^yugW $|5lf'qK0坡Q0.vŷ[Фqc7nzeT~' 6m={<դ\k`NW`{=]|`\͞3'w{lA g7ls-Q߿/q!.7_ߣ[f5羿^gW*q!u8ubUx\70ukul@RQ9BRÇ󞓈\ڵt&QF~+p_5~캷mFt(Rɹˡ-.((<0dgu$1RJw$"Ǯ])W""DDDO`]ԪYûړa]cCdq _hE:~xrΝI?Q'WDZJJJ\i """QRܽۻ|mrɶ/, KA ]NMMǣz+zwN8""""""u.ZT_#Ll |$1ѣJwsHk8gߡ`\HEFF.9rģ IDDDDD!ӫp ƅT.Ï-~!w:$"""""W ڸ3u wO(R7|3czW}Wjk\W\raXb,T4+1[r8D7mݻ9^=.={hCDDDDD.eќ͛Jwqn骧`\]~65bqXW/|+ڕ_e+M{ٹIZ 9t~}5k||O#7fMc/YCX .M/oa:Y˦T)(,N >PlY{5/}xE?e[^R U)rcΊ+30OcYnp9 ϑ|a9W^PfNv垎< 9ԩ >Lz^ob6/*LFF~ڵëHRi_"Nma꒴o[ 3c+;yEY lCj˲UwBGt.W:>mK[I;;{|D>Q2;%髯sChfn4hИ;Z 8>5ث!_YV#ANAhJ1[7;@rBIX5:GDDD`Ý{=êgla sudf+{>3ӽnK7;ѓ=׺ =zVRw1""""i&kV`,lh{aj;wH$1Z}зo_̙Üs6mA<.;ij.tŌ.Ʋlr)o8fnyi;iޜ7ש H723%~z#~;rJqwÅ3o%R+Ux,{X:ΦnzNAuTh""""@6Һ`l09Ӭi^8XXg0 GGN*v+R wP :XDK6t('SĻDDD 3lxs'# qd669[19Q0vX Ў<`/MҚW\ ~v2c B R݉)ta ٵy@v.9d`,"""""ҕ6 6 Z}r/]5cc.(_lD " E3n&_['`,""""""+]I:YyP028NynIͼ=Xd/Tq`,"""""E K!#'Ě0pLX1:c,"҅R)r 55.iee7l9jpuͺ%X5`Q8Ց;'c./0hA7%"""m`֬LK7,al|CBrV$9cqܱsyNsM!""FXDDߏxs2겫њ҂mg}ATvNHXDDDDDDZK4+dv`,"""""-\B:o6M:ضCH(nNXDDDDD+3.Vjؘ-@l6OdױZgʦ`,"""""҅@frZ s}9{Y -T6v8cYI,<xt>8ʄNolpƴpY]lEk YlG;r(J?]6D@hq}򋈈H+XZjs콌,K&֧#.nw7>׍a8̬9څw=fGpova-dmwc3Mawp6\]|܊I}p9q9=>_v[q!"""ӤJVu[^|+3҉owxH,Ko^p3sGsݲÊ6kO1=wq ׳pxuA$0;ˠDv7"&I~qƒ}N9w_8~O~~o%~-""""Y k9fiX ƸPlpXcⱂ,o8lz@aC '1x20/np;еDlpv | 1;s˞3O5x{K,+$"""aܫw.pN(ƽzɴX +&L>Vl8SZK;2L'׳2 dL.۱GϘ}fԒ OWqp~cqռ;zv-[rzegcםݮɓ0k٩RyElءi)f.͆nu}k-=Fk1 qyC`,uwa̹Ai?,FӤ rg$|>I>guS쟘G^GoS&詫շFpu{-v:r̋~׽`9{w"Ƹ箅?^G_ijA;C:I>}Ǔ[KϜ4xSffpg3$u?p忪Urݕ_e+/rv)䉿̢=nW^'o6ee97ܶH6]]ͺP ؠlsvN~`Kڒ^2 Js+~Rn}[4iX0/vۍ7X=,Sw*d |4lM*K3)>z/FF#F&{paQ{*<(֛NbX~3'Ijk~d"W&5Ayu߈-Q9^/߃!ǐ`y=z7x&J@/yo!pv)ģl8ءO?>~1lZ7J ᛗxLIBg>&U<ȿ}g7PsMYĝ0i/?Ƥ Ha|ij`^;EKA;fg *nti?bnC8wp=B<'.ykjEw[8݀A5ۺCx_4Ui ^Nꇿx!Kѯ4\.ݛ,.W^}zaeCr #WKϟ;sM75oQG`+j|uͱ'1oGγw'r}3g䈼(* *fH{Neܑ1bsss=Ch[!ccbOng?NgGE[x>%/s)w8Fn*ŦWޕgO0msxM #yks0cX{Nc~PUK倡[ y,aY*ν+Qٛʲ%Xm Ɵt%o&t:!w~l߳龿._BGf\""""˔6%`\΄`8~\:T'&k*t>~t:\|Zu}[E Xk*he9oT);1_?ZcfYO1&kl6}?d~՗V? Rl5_:y>xe &L#K{ @[9 0F 4ARwSXD:_9}Y6}xUGn1#>p)jytmʷ`vWpw9-OfEg1Zo͆3jDžcs^wW~V{j!s$K/sسY(>y9dUŘ"˚W˞DEkg{NtRUoËdef+@o=xA8:?N'`,"MΌ}6AwA]]<*<" ֺW3X ~#U9e"[ywc.*oa8,Zedelힽ]S`,"""""*B mBƅ8+Sw """"""G$9?ˆ24`,""""""nl; tWh9q-(tae̚5;,"""md֬Yś;F4fmd!3u/.6}:v4j ~8 1L8o_M"?7aC2y|1eJKDDD@yy9Æ 7wj-̕-a8m󌭵c"C} 8޺\0,>|xtQpSpr3|@AdT;MyŸ%[.ECnX5v8cXŷDDDDDDӚ[0u'Vdvi2!9sc`,"""""e2ƆenOGi9Zq EDDDDD "פTyMCL0.e!v˦J CrR0fšn6f pZS S3S[ہH?!8ËkEwiaTݸwc.)L9n V!fgF 0̣G{oeQ5>M~xbHR)r 55.iee7ljkKđkD^k`9Wp\k,X09Ʈ°[qץn;S0:rX).lP)u6t_Qq0zBZe <GWJyɵ9cEDDDD0ܪp&fMp.ۧm{ndvf\Og;[:'gsyf>myu1OΨϴOXEFH7AU7h` <^a߷؂3Ak)K^/l?8>1O kL[#SOXf5"""""ґ"/W0lvKNa-t&6n=LK;ck%A)nZ7M)hYDDDDD:ֲuY՝-%K⹓;ci0as>^[/sŹDDDDDs0DjJnk]pWn>,xw˦@I ̆%ݳ)/^Z}yM_j\4lK{ dH{rÎj ͇4g}Mam]lpem)K3C{d31ҳbޙq"""""ҁbal,Tj|_W1 #Q%ٹ Vx84U!"m.bp=go O.vEDDD:K6/aju;yYdG;^ޫR펜F ƒG}-#zl9ȓ ֔>kq493ñNfR'dIct8[Ǯ抻^cʢ%6fѣWF8oOX8|x|6tcYq1uSr syG`:x?vډeù:y5J>kᑤ׈C9l_ƤGp#陀dFJ[ \5pma,=2i*43uqk (M0< y [(dPXf~1/I_O_,X}"oзo%[\ˣ{J9K,[潞cΫc'S}UQcQY}?2٫=>gq;o㑷fH4p 籨}"+Ջ}sWzg -H,qSB6a֍;V#mĶ`,Xྩa /yMT5-߻8㆗fZIW,W^٩1~5z^z0w\,}&f^H}b3ZUгG1Cl:/`B\oY/A4S罽-\6N:h2^JNcATSkW7e9K1''"""t@Bn5l []ε\83ڸ@[k%voUw&xn$[ -I.ެJ]mFUgHlNGbf]%l'^C-$ƅ| IM{fNUs]m=,ZUVKWXs[F%>5әzkC^:q2Sfk"U~x.pmj{a($9?/1Gľ|Ɔg]Qóŷ֧qqx߰6۰nrޣŵJ7c~Os^cfI<0.;ekM#?f^˄};}eOtrG\|2kN=f)?p6[m3'^?*H+,Hp6w6_.c4_yS=Cg S/$ +jcޮɷ\~5_-ѹҎL ۽zi(aͱsӳc2 漗&Ғ <|τ[`B!cOE9>@uq6]-^kc ޾g^,8[z""""l\~VD Xwelۚ,[9%\8"4w{6|w|V"?M#~)3{v^ >Tyn/:b(oՃxkk0yxȊkB]68̹X%,Qa8ݹ,֦g z f_N;R02iu?.%"""""Zʧ.f ,פyoniŷDDDDD:9,.[r--]5Y7BpKt'7:7ciQq°lJ!C{$3&Χ8aX``g]W-·0eqf67{HQ^^ƬY߿_KDDDY(/+g g3c\l~"VMscE IDATi4i{b~=ynKY4p"dg`h$C{$bGVY6t('SĻDDD 3lxs1A \'f/<gh ǒΜ>-dZڕm"Y,m9| ż:t8a]~$-dd* KB#5Z!g_1|zf"\Q:'ŭ\@v-X| `ѮjpUS6(cAE9,HqZޝۄg}}u!"""""*|˵ a%8YcXlӬEXת ܲ[|ٵiNbZi+·)̮uUnWnٍA """"""̪ NqgsqÐiό^>!hi? ]T+(Oz*qK>_⤷2Ḳ-*SH{dedQtk&LNTmd*f})tQߨ%J;Է06ͩoW1oIoT%""""")@dէMcthM4_Z?ax}ړq4v"F)ܕOj/~IsU4'SՊcDDDDD=R6H9t]+tZz춣`*e['MUOn7U)n.}RM)--ayf͝KiYu{[k4Su2Mp̐4Nt.𡥔wm>ѯ<2mA$e#räZwurTxe:6d nDޚqn1d[C8:s&TMOc ƹ5ȹH VB]!ʏ;=, \Q5wnǢ?@y [wxldp\Յfmih\2`8X?otD0֜.dE&Sٍ|Wo>:۳( { ֹ"""""m.esKkDk7:ز>Onupv`Ex\~hzO~M{.k(YIӢ îk܌L °%6vfڣ> o’)`E 푤=%i>qjGSL_}K Lf%.-6w>qdG?9v|t`E=)˝Qk[/5HLk^:KP%6d*Apao3Uⰺ9` ]z' "=Ǒ-5JݥQBmfLp*7?7[ $c~*:rMCoou)aXcr6fݾa~ dj~JݮK Cw_ƴ)m)fL$0[ do؇1X< Kv<Åm{,7a1bQ7Tj.|C6#ñX)7SXeSې*""""""]PPuc<wTfH>c}7ڸF1pUbnZuvh0vkoH:mJA^X C6fctUa֍i]Vmvx1\ +ݠf6%3\9z/!=b,"""""$]{hͬK/emfs ~:NEDDDDDfQԥ #\Tl r&+=7ᕩ;,Sx3i8sEM˴t]g figZwbWζ/,G6,~c+z~3{lRT]k-}ߵ>~]."""""" 9ׂ1[k}| Zl۞1A k /s-xHy֮3NsBqx-fm>`CLTnP8. 06a䛘 u dZG^}5;Pxiic6ʭ( lN FۙqaoN |mY9cSV[EDDDD:T*Ŕ)SwI+ӭ[xWT*ŧ}Y+^k?\.)>/auUck f0m1BL;;[ ?eSL;$?HaNj_.iYg3o&;4~k V >^0+WccLbr^ъt6a,vZ9㪸.] UOA5^&f:0EfxeQ y.+l?eeY `ؠiLXW .8>//٫v,c6yV6۰7$iSWZVl&k B[w Xg_ovӍ/ ~08^ڵbZ8`׷#.bT2׿oSe˰ɰnF6GӪxl:0o,_Ψt?oHˍr<!Cמ{^{efvkA5g&w괻qqOXw-wf?6͛DZ'c##sasqq1o޼n? rp ,L8h6Uzu{ `L$BbAngL:bbuo'd?g]Hy4d,+I:.%lM5fJ_qQ8C;Fy\r f]S˴v(gj W~6Uq܆lWaho,ȓ+.KٳWd:{kU@Ūѷ J뙵fsި)w,s߮F=8c~HrNEPQ!4(xu:,+ɧFQQmA;?~]Hca%7ͯ>7bvn,oO9xU<.|K2aRhsO>W_ͦFezkrKnFӟrZx'eޝ6-*[-r @f}b 8|X6h7?r .$^2( YH%$$Db]+@eٙp!D"}ͶSd4oCqV&>lT MZ$lTwwc*&>KFYĢ/p)VʮcKr2]P!-7oQ׻/${d9[r 1C*~ɢza{Z}8rOYTSY/-d[uLy'}[ό^E`xFbjllēO!Hp٥wռ{w[v ϼo=}]?O8ߩΛOmp|:R> BrpU-HCc*:l}ݜ~c }4igퟻ38+\{ʯfH7h6eEX .кpj6-Akt'4Җ&ҾGS:oHS*HHLb/%}exW:"r,=Y `μ&~^$,`Kc i"ՒYu<4[a-KxdZ -S>u > &C:>$MYk+=ޛ'O+}1w"QKnT_⹍kV} X Ɉiޛ46R-$Zs5&}Fȣ++ytiK}gafoH0z>o|HAE ,$=ubuㄓN+.d2lL|=ܒ Xw. osN'S72Im,+_ްal&-aÆW_}>؆6ZԔʈ8Ƈx}B\d^ 7΃/Pyԍ<MeD.`i -iޟo޻-{[=+MâF>(*` kh +SGJ(//dݲ F곻S;WBvYv|&} }kжp77s'QQэr)D_>>ՋwI/X粡!398X1fY]17-Uec ш?ΦE#=.Ւ/DcpްxW)am* VkS gH$(<y 2 $ɚ `| )vG~?3[6VfuXCDDDd6ZGW_j9?_H4'Qֽ,}/ZBӝ2ICf.1W*9K[ YɟOi9r$_t!g}69Ys5] ea}R7I7=C?#65cѫ/G>6{зW"%̝WˏcDzرvLNܶ(,e!ܧR)KSdij*H&$%% /G"8/$<E ==yxRŞ-] %}?4{F<魤׿%s =(>3;wݛK.h6~iK0l᛼iCɯu7ary=9ΜOs-J5n={.䬳;ng{按+>uKwo4Sq6ӟ#.;o[/ܛcO9&Ne"Ώ *٣5'\O?ͳO?ͳO?/kX^Lr=#LHB%骿^KbLPvWE͞S%s~33[_iOVӫgVh]ȿM~_?y &綦4p \m67q/۔Q]mlyżz&a(I77 ]x'r*ƍٜvω~t?Xo23gwm/ZBᠡ _x}ɯ`8c-欻nkƕ>MbU5v;~M<?E̘CW\3Lx &lLP n:gܔDP^ϲA:H$0G$JH ' AO$$S o6,5+!c <lZK2/NC)][DDDdXcy?V]6VL9NkM31ގ6*r X Y琋9C9/cRf-%e|?\=w.c~7q'sh5x+\:=*+l4f:bm1#_{]r\ź D.?&@n]_ؓ5=Xu|+&P{x 3!9 AUׅ^$a5 p:D/L$8xD"I2$~qKpej`Oh$}{Z=ffI5XK=xחeٜs>$arCIHrr\Hn)v˂!;R ֌`lqIDATZC׿~%F@Wݥ_.ꂲҾC/_!c\ 3۹hcCwk`DDD4}koV<7?uW 5֟ f8sDhk??ofwUηη=vۋߑF_?z,uG8o~C|t{ow_a:0 jsW]3 r}d QG%O;=[n%ƃq]Rs9\0 }h_q/ÿW^"_qwŻk|w; Y0 }s<]=!2YtGUƼ*$wjuuk}'pjUZqg!Z 緿hzf5"""nӏ_,@[ꅬ>c !U{ݔKi<,9 #zeY\˹*WPjۥo|SV '''qcc!8cN,bE[s #>c~NOD/;|fODDvqxn,U[ȪG;!d,040KV;s6r|὏0b]mR0*x-}op>>IDDDDD׍xn^/^:p,+r;QOZq\6P,-rljƴGDDDD>u7bX,C糰;hY ցx / qiݱZ9qch/~iݹy8&""""ZFu6(zJuZ(k@{@՝6t˯ K+M]ϪWfOڨ(>O"+m͢&^y`-[>뎩A{U'''q+."#ܴ+:T^hKT&""""ZW&sf RkΰwT\ =G㦵8uU_LmЋġ܈>/GOV  <1߿oǏc{{ۖ <~)vwy/vΖ,`,m=&tYu~W `ww5˒kՁe9 Q 3-'|io~sLDDteg?O'v:+r;`+_Of^ul61.Xj,g}%p7?jֻd0~Q|!q|||g|nWq7-""""ݻx/ӧv:UW^yo:_AluT2T X;;;q?>z(J W RP ~\79̷moo8hu7K 6c]9j_Ͼ$.{_c9nB} fC|E]M-]s_ⅰ0sU DDDDDD ~/~dV,t Ӑz 6d ۗFo-Xbmcct>...f.K_jy""""""bװ9[9vӰ `x,~OYmMoZ1Z,~~|mHcn@jéK-9uZn/Q3R}ٶf$57U[cBR^.{}`0kQwwܙ/l>}iiQj疿_,/5=G_{,e􉈈^ !YA7kͱΪߔ&KCyzegggKMm`;̺&Ԁk.RRTn^*jr]癶1u`V难ytΝ;Ȳ1Ocٚ۱mrn1(q1ǥ&{,E}0lBׅOXFDDDDD7/R5Qu ҶuЫѲ:l8٧y*.s:%;zŸk[AYPlh{Xbi6 B& lH򎴛6eC yX]Ͳsqۿ k ƚs!Xust]%˘CK!6(}icK[cL?gq"""""mA͎-vmfC<=v׺̹X:J-GmwXRmdoפc^uu݆?iۚ6mu)4 [czN&W9*%c8b!Ջс/U/H]([6/7yNSm[KהQt͎KvIgCmfqz.fϡپuN}Z:\K0\: +0mMWB^=UV̕?̕{[7Ye.]]*Աs{۶5 |E.87jc^E&mr`콏q&ɬ xratL\9V#uQ%ccfuX}Lj='W}4.cvNkI[o2ێsnqEYmsXO콏eYF@tnyeXőq}l-՗sKYB<:, CSaK߾-UOՈh}RS5ǜ[ ^s8dSa:91MT*sL&r8ͤ!fK.[}`&%Ӌc\nqU6;.+{k:=_h۽kt]jzkOխau-5v[<^/>#DךPCkkp ?F-#61zX4;7ځʾo};fkmnۺ*Ps&59]ugx~~YNfvqWWYimh5 vaǦ˲2s4}^{U:f6vꩶSm'm=),zئust5 p<pqq=ٓs=ۀ2Gx]8U8Ml20-i,5`yz]Nxe!""""e}WmT6P&um.a[7͟n㋋^OY`ܕkC c} cZ@,󤯿,@R#i0ë<}>uI8=Zݸ뾴Ⱦ)~1R;.շm1RRcZ0^/zc1f+V V`{'<^ 빚Ԙ^Et]+@N1tK?}}GDDDDD}oBz-튯׵TWZ:{_e'I !Ģ(씕GŇn0`be{@YEJ6 s^[!Vj #2_Qɸ}\O|;V۷ƉJ m׫2v؎ٺcϭjWUeB(wbYW^`ww7ѣUdY6 ,;Ҷ5`pZ ac\I%Š~rXN5}^"""""wmM͑lv\Xjo躝cm[McmBEYEQeQF9LeY} k`ժ{7{[[[ɓ'BqzRx'@ rQl8s[6jr.cg,Ǭ{=^ \}I]պS㩚uR]k &j/a !#NNNʼn`fq~>&ʲ,b{C(9bSa5UWU<~ײ.wǴH4W=~JQZmsxjsATao۶֥6GnǛ2bYlnnr4;;;%;G?|}'O~Pl<ι,؈1b=E>ʲ!c\x|o{^EnE,:s.N&xK}c,bsn8L&g1^700(^}ގoVb@u8s>0$GQ?˲,K(|a)mBϋNQy \s{_E!?TxǓdEY0O>N裏^Ao6Ǯid(dY拢Y+KzpY] r/g (x2yx< !-bcKߌۋ?TaW~)Ǿ,K繓ko{ ӫL{>#˲@1eYpqaBXeժAG^9>:: BF>s_+•e,A(UB6xqq=2(b<n;+Kw'|:B!B!IĆ'6B!B!m cB!B!mcB!B!mcB!B!mZkI#??IB!BHKC5ur굆X94 B!BHk1pHPniApC'm'B!";;;.6!('^osZzPB[UUrB!Bi|>_ҠʄptN9!B!U+((x<l$m8 `f͚ŁpN qB!BZ;'݂x<?C "R !B!Pk(۶m۶64MSUU4MC4MIGkp3܊x-r)K)5Ƙb۶9B( R2!wB!rI[U1&"R-RJ3!)eHJu=$iᘂ!_bEQWxV`RB!Bqx=tˆGIO 6 #vm=+ KD+ŵ3ƢdB(.K,KRy0QB!B!əJbM)bK)m4MaLKKCUU***"kkkqb֬Y@B~k-}Syyy(**ba\ S޽%!B!2Bj"\4UEaP(i&'u8TbWUU1Mxee%s)bYi&tq]RJ~U6!B!44MԖ}eYe۶ri¶m ir޽ɪƭa[1,,VSS۶e`RJEQE~>r:Ƶ8 !B!5P9J>̶mf6B,Zyqjq^^~?,9mr1˲8۶ !gtİcks!`!BUjΠ+)HII鉫cH>!B!Zc<;ř @iY֬߈`UZ$d*`UUN]XXҠ||>&da0LJlwNXWF.Pe2p]qxwApx)qih[B!ru I\Ν:s8yqX~#^~uvޓZ۶EQ8nYR2EQ`Y֬Ec˲> c24׫JYk!3u>Z vhuz.gNZzt[B!r wz=RE =x7|EY1qq !8:Ld0  Xuu5 |:`K8LUU&ɺ$XԣvP "@F/K7Cqok]t>2a !B!$Mp17Xts̚;gͅi h:wPHzqއ]+RJ&!N?`Xuu5 Bqob`71YVY'Q%6"TkϹ +,g_{f4K))Bas/99`(++_|j|_yU!W:&cwcn@1ԓ1j0L4a$ܲubẫ/⍛60M /aͰuk]}9t\#1H)Y ۶#CYВ8!i`{Q!5 oT/6|f|πuY!/s~ygEC2!3jx1)x_ǤGAW; wm؄+&܌3fłKWU qm|^4ڛ*R1衉B!7#QbϛQ6747$67ِпoaxX f aT! ܿPLVcas펎9Ɉ2z4֏):-{*?{HIMCHIvIc!g? =/[۶ѻgl߱Y:v% aظiK*)exB3j;#O<~&J|'?zbђ剫B!sn|"21PоW\躆#aشek2$ovm= VIXcF34 7i(~'_$6Bi_j*pxW0ђh{vqeGހ#* .Yצ@9w/:^7)/OEuM-/R\ p}U]R_nM[l*ϼO=4 p&Nz>xzX;dG mCq嗠S()-ëՅmD9ERy!${'?GmE;qgakok#ra]T{}%.\bxb!:?7p`RQЯOO4&Ok*< !yp>C=6 p߆ WW-v  ʱH)#GbmLQ!ĥ,| =D=5†j)[ntꖋT_:6o\j:{5˯o^'qs̈́BhP0L-N\uhNh'\\{%~n>{;{ۍ8`OC"-͇{nU[{oށe+W}N&IH矍'TΛWa΂E~Ps pݨLJX~}pӄkϢh׮#EUqݭ dl ?_L}e ZۡC|>ע%EΝpע=1UՉ4ɚ0酗pǍa / N(KX~Cܲ>deKlP'>떤ogTHx<V[[8oѣn[ wCBHAǿكU6nCiSs C ]W :_s6U Xz w-)mp> ħa0 o^4'z?PxaԈ)2Ď0gO ?o֭s[8םH@TiصpܱǠ_/tJ0t@̚nC MpӄkzUv]VF_b5wlבxB~mi>.'>k u)/ΛSBꐼv߃%%ДAl^ NŘ1UUR9A(.S;rZ @ 9L"fiYS̿g !TVV!+3}ř,6RSJJJ۰LoI 3ڥÿ$nYIIixmoX)v;vn]:F׵pϣzSBJ=6 '?wzo>jk5v)mB`,, pBÏ+ ىՅq!@]`M6קIs3KN1u ƻRG8=qcќ[kKZ\0N% D ;[3SdIXߐ!Λ Ep7`&ߞBH ֮⧥'*뎆,H)Єr"_.QV^̌nh)ms<]zty}^V^ 6޿=MC]\> O>T-o-)_~iⴓOcy,7:W6!pmE;}bu<׻L|*iib톽bu&Nzi69]_/Ndr9 ֮k}e-㸦iP%:+ue vx{P2$o/xbUV*㓧k.]Be/e_ `ܘQhۍݑ]f\ in.̚3aBʘ8cpHR⧥ˑۭ5RJtꐃ=2͢;ѫGHjgnd?t';sp3\^x慗ѯw/Dۥa-t]4|+ۭ 1eOЅ.~>O測XU}<$V*|/7mF/cړ]_G[4NUn}-9ۮԖgvq`C+%Uh?2<)dݦhm+s/bE 1'B!ﵷG;p]3SPUU' W_7^z!%[ξ<؟)EXdY+5lj̙>*؏s_ă>k^Gضmؤ "7HxUxٿx\{e87'3fIǏiΘ=isoƯG!ԊUW%XUµ1)tMVL@8?pmcCY~>2|VXX~?+..湹Xq cLBhB(^)O5n 0d(@ʐWa`sYK!aWX_̪uB!qťOB!3x4p(|KNx|x5w0v;A(cU !jA59f0srr[ʜ-?L *IދH[flV6c\j%ʷ[ %>!6g䰣` u킓?z}}NB/l#p?I\fر<9}[quu }Yر3qIH؆6(HI!%mA:uv/^-ĺd\oBڤSN?hjq_B;|w>hرzZv_>n?qq507X)&`ؒ>V_9{k/ͺI"=ԳMB!Uc~Q98Ǎ>GVV&iWY9byd"1t->'vk/+c?oY&/M P t?(B!BAJe+WaUAh8S'6 B!BZycB!B!P0&B!ҦQ0&B!ҦQ0&B!Ҧɷ{&B!B!p֙KljbL!B!M*,B!BH:QŘB!BHFB!BHFB!BHvX|VXX~?byyy,++m0!)%R8eB!Biʲ,CUU,??U"B!B!C5+uң Z @UWWG׷,qm3X:!B!( 0!4Mcsf6z1d,Bx衇٨_/65%LB!B!m/U1g\18bg|gP!D B!B!IJc B M$_8~`ܨ6 |>&dm3 fZB$."UaP_Ykb~LL Q^x!O7 <Br۶eY1E9A5W]gL!BiE"9qEQ8 !agiJ|J~+ 55VbE /P~:q ??93 ~?"G!먩e9\.nBpM8n6gqP3t ŐfB!BH+( ,rQs۶m,K\.a|())PH@ un~0NMMPPPY~~>k(R\ GnsjjjbMb%ZQ[9NعB!BO j17 )F*EQd(iLUUYQQn4MD)))PUUnN͕Yfh0NZ)bzb~3Lk `c,u\.( \JpJb?m!B!&B(p۶sι i톪,UUPQQ!~nw^\\,srrDvvشipmAH;Hu]q\JMM PTUU)1Uq՚EJ"UƘSmk2ƘIe)11!³qB!B/1.1s(CP\&C$y^iRRJsrU!'jh8-PkjjVt]W^z*tߊ>+>WTT( !8<:ۙ3nǶm$B0Dž\JXrp-B!B!M9BhBh4M\.&E88KR!Jp\EQBeڶm mWJ)r xXQQze7WxqTbRr0T9m[& `"2(4MC1Eg,fYT IDATuYcOm늢RъD!B!ilVcRBB ,.5MaHUUӵs.4ͺ@;fs.CK۶zasn. `75X6Rl @u\*\ bA:s WEkB]JRERjGD!-tO9d!" >9B9EQm9&cfIC8ٌ1'J˲Brep RTDKι KEQD4M@b\*T4u˥!YD49L4yΌhLUU#)%J)5)sp3FuH+l^Ū^ƽꐎdt@Bȡa>]f}&*wżboSgg#-L+Oס^5g:SGlSXrce7[ BȯIJeAgօ(BH7jR"*ebm; @ @DBac&SUՠaR*"&7`\R\XX~?+..٧9眫i۶j]+\ "]:s_۶a6}_ _=&܃ [waҔ1] Ǭ\x.ߊH{;cЈ>tnE=ȭ`ڧv_O:$by©Ʒz'? #Eh{xX<3`L!f222IIIc @Qpyat~w.yDBuIۜڝ6UӠh:ug,,,dhJ帡`sssYqq1wݜsz^- jRJs*ٳv(& Ne! ^OƄbSsY8=)X;|Vѿv;bBKӯ/_ 7 Z /}Qǣ'7o%Ba$YJhl١`&,ĮmsYAs ennܺu+ J VX^^~?ba(a\ L!kPC/xC턐_^xw“><ǝ/ () !PxeX/~v7FnHVG.ƒ3k{+m0ny_c(gcpka`10{q0 cylόEXj@H[ja\wRݩo+ʂdgKD&edOO`P1p?i\_q3>-~<_>y>?܁j[۾/|. ɌlރEツξwo9FGӧ _>eb F^D z||݂L@ix:%KpL/?>)B!͢`d;N2z;+|d4Ms*ضm`i`0(= |M ~@ `@eeeضͼ^/ 1xx=޽{\u^dmɖlcwƹ !7bm "O;_лP  / @B"-? ǎ80% JW`#$qI88u`/. .b,[V}LJߑcE_?Q-HHۖ}VƬ˟߯'7Bdr߻XS/bN{yj8]ZҸv.55f6׻^5= _3|# uޓ?s}QM o%V6tN&0 >?> ~qdDr?$Ub n 9'  ! RzzXo۰ly DߺX>c4zO8<2"w+W`z'Y*2|p`OF6OۣדX31L.nmƴem~ D(?1|`RB8]1nLRm,%6ƒ0wgQF c't2(]S>.Lw`vбRB(. Gg 9HwÎ#liҫz&tﶱb;N9-od!r`E BB0 *\.nWlVEQxs 1`3W/:bO/v|>zmImsX;X Eؼg 6)O`񲅨N !WbmCQdf@A~Ѵsqd,gO#(zH4f 1o`Տ Q;5u-fbtʠ<Æ7NS;0/0}LLl*e8"it FvAhHu$}bF;`|9'^O40px©oO)=pcOӆ{=J<| p܈5?YoE`o_ -ҪNE!Κ3 ~^r -\JTUuGe B0FQ3)]tN$%0k,,݂vϮ ] vl[C4YTMkr0n 7W]-do{"E3ͱÕ]KT82Y `^2 怨(|05˱::u#9}3;$r,^fdJ0:;w특9bHdU)Py]|yC-C}pt> w;x;fULƺ3ZNM"B~k%a(--k !%r91Zr9,TWW@ P=cIRJ$Qb}f-rj; +phMm5FiK sr#>EOB! .#6,]o{s{I!B7v8V***!"5UcuHZ-DYY9rB AcLz0-#;sRn8UH8nP eK$PU^G(Pvo..pDݘfBȯKh†xowFWȌt90<7/VXl%j"̟)9x1Xt&v-mV/*'m+]1|x;3CZjfWS9 dK~ܗ|&lQƧtNJÐ#,c{g09Bv p>B!u2L>4J,\ #1def'v.23y0 9xNͤm30M3sSt8־qqnh uH0WbĀճ:u=2! cBޥ [m @hZT~ɫqv[_7!GĈՍ{ X E{1gS.ıcml#{+-،Q+Q<#xʡ4Pi5RkL^]ב󡢲2ipme' dfrC]چWw8;h'֭[5#=CvxB޺@Vz{ ;K`Y(*Fvec!8x> O<W=0?ؿ?Aď_,DqݭeO" u λn"^^.z_5^¥=obpbeH [|Rʗ /ҏ~I̋cGw9oo/FݮPP8 C* ,cErrV,# _aԥhpرU +6DDesie-**1vcL_\q÷bܙ1pu/c32Sp^ C}ƎE,m8)uf318g&j c5شe ?t=@|%89yCX֭?a՚(XsSQ/JR!Aq#h>ǝ,ݍw8Opq·X3޻KPԛC.N|- /^6iLpƜLZ5R_B⦛_G`iE2O߰oNI\'ކjCa0y <;=Kt9)u},W>&Ee0Sw=OŜ{}bR]Z_'+?`}%3]l`]QpV+aGߊn;^ÏFc>8Sʳp#2z~_#kp48V3e1w0c*US2gN}#9r2r5 +_< /5`A Qk77q:V?$ 49 >*^;߿X()] pcAԻ!7xPY* ?8w>ҍϟz+lNsOƂs0'pImW:||Dcמ}H7z@4=zqt>Xb)8jD!{OdJ|^#@k{B|q_̟1"Si5bл:W9Ox| L̠\pCŀ?ގ {qߍp-WaPjgψ{='A&B6UUK4hھ;~P]ӒN 8TNϡ:ִo,i%t th6|Bg9QXl IDATz5dd]Sj)Q2+,q1rjWw<7\>?[lS%HWUt쉮41^A>s1ntO(GdAc@sv [gk?F hOE'H~9ɻW^hOC%7ix c5AC<]>350m1YV < +zĬ!hѿˡGyc> 8oxӷwcWtxgìgnlw˲% *HOn ACXr{ݻM$9as瞉;333d5.>)_gΚ5S/ސ,C(ܼ!c4nT8^A׊#aaoH2&gYɜ0K,I<Ų\㜲v??|  ::D|B<7n^Ek $H56DĖMgpڝ"(w8G *ZwI 5! Ke$Y% p#I4ˉ⎫}}&}W8],+\ټk~-#eWH]ĕ_0h=My yK),2_Z_NC{ܟC)ę <lz!r ]F4 * BBxxDdI-Ӈ(/C憿?h`Q5iIZS*6am<ݏkI5^|ч0W%pۖ0kg*b?)ު!M({sӶM;\~yB9{:(9i5>`-MhS7N;@PfމْcU@U$e|D員wx!&ړ^茆i <>u7ɚ -X\ Aue>{YxxgE{y)xdYFUU$IJ~X(!uHp[4V8)L3KyٜSc/ꏌDGN@r|7!{RwX$I~>>2Mnx9PN3ʝK){Ƒdo0$ e:l yrn"' 1Cm&})kuS~HZl\|(Z!Uєd[MUGwIth;'WtjJa- Wㆳ$5vy{;yQ#."Ɨ<*n`{R,{5kϗVAFFBb" IZ++=666X[YeEÇK.]BBB`_ X[[k$I*zEQl46idK0eRoNVei CGoa2PX.[Nnq4ukײ,WNpp0T(_޲Xq1 dW\Ƙ&|  {vYh4HFtXaIJy~QJ<|qV[$׷e$I&)Nx`e9IUUcBBtmSP/92mԿ-ុ~(Jj `2R`EQRrsy؜A ɖ.HAAx^xb, i(Ts/,"iС;5.e_&AAL$Ƃ KB9UU  /&   Db,   Db,   Db,   Db,   Ѵx1   IͅE   F   F   F41>|t%)$$D,   BBBK.IÇ441AAA7Eqttt    %J*Z yשc{^<=-G7(uwח"u  `!Wq%x7PUT$ Jb>*[Gk=FO kܸq#uwe  rss eqr8EצZ(*B^_oL&&gJUU"##IJJ Rt:NNNHsbn)N޽{"1AA_NAJ|Cv8qGM|NR`J{eQxu&Ú`{򓄜a{ЄR/a9/u>+;9GBz@©B{ǟ3,rֲFEϫt^g]|ig3{5{lq ⧒ag̮}yVFgu,GMe)A(dcc#I䁴O?+R(*ZĘ,^DBаwE7. 8oݺE@@e RC7[?MMF?ƥG8_( y+2M|s?#|Tϲ IBzNMocDjRɞB5dn>z -'׆sSg&˧fLYYǟ5>Y Y?ٗӅ;`4w0j铏rʵLw..$8fqq(rm,sh_֞;[D UA%8+֞EW + uvˏQ]Wj؞cqjԉWN("KRka|(V;!gpVK.h5 kWƵ~c$kӼ/tq6Ti܀RڔOT WriXn)gj=;!j(Y!UlG[RSs#> ֏ SKc|=Pg)y.o7yn䵑S?|:} RJ%,=qNqAxˉ1huzml@U1Lw4:/NyEkd2hME֭[ɓGG ѭn!j=di;M^tė]JaDVr<(GiB*ȀQL&GZ eT|34Ih_{/,ZZ..a͜}e7D-il 71q\ګ4-9쟌tU |tf` ߠ5 3W;iǸm160}E ͸v\3\$guӛv\s\Kmv͚] 3q+ֈ< cG0iŒh܁ZC~fpVjyŦa>jJ@zLCC>z&_7þlN 뛧2n~nDkp l'_~^˻e2?.:ȍH#;oʾ5E4|]vLdc\% p&Op EI^ Ֆ_~F v!q:_w7b WX3n `kNҳeBu1^`jIе&nQ<[zcS2@1w,=-pZn/3pcE׻L[AXa^ 񟲂J=+Yik8q;QC_uBN'Dpg;Vz)?ͬY=GK/U:MeOɾok$:KPע0fz\|;;uBsfPi%s!f :+GoC,pً=]mLZpka&\t#{QY.|S" ~ƆsWhgQrIrJ3br抬ѐQKO fÂ\ "^qTU]م'%du%<+N 8N]^n!v;gԡ1$`vALS[[t2'li8kMul[أ{ۉ%RPc1@\FM9G6uksmʧ YuDҌ==JbumaQh$LK\!?N_"^ddު[jF]dmXETd":CT t. rb>fe+$=拱|XA,ׂ⩪*dEIx~6£S{̛#UgL,Ug4 M@-ewK8r+:Lo?g,ٶFY5f*=d 3غk?d:˿re)kmF#Xq#+RbJt]73i4ǯ/OUtYx.wyN?=q*Q{Wso˞fB.؉1_ŷ#md颧FZVTx]{#޼vD*Ƿ+vo/ĴAS9L> ϖY'I14=J5w=G{É~[v{QĜsBizvUmK>ȬIQi:Ŗ#?\LC5;ٷcݬ1veCt)ne_n/;q=-aTyn̜̦ _3/!6fϚq4{3ZxwYSe*6o\˰O. eoՈuعw>Mi()0 ߙ={6;f 5Kɢ l>)8NNya a{Hۈ#6bbU 3 \ûe7)i}HVa2.˷o4FP_&ު;Kfߎ5LЎҮxJ gtweJc~ΆdRi梮2ލP.[}G"іlN3̝y0a~ ytSwf4S\ͮ0mkuSXrDq(̼A qP;̑=KY{+eIDc9y|!]Xa1G~*jQvi̸D£q {olgf%\f)8hgZOʡ#X?:@m*.eZk&׏ᶱ ,ٿv6SOHnhGVnɞu#)c[eq]l5c Tj߅2l)T*oz:gpՀƱ$]:V.Ʒݚ`+γuJ!; mJ۲Wٺ+0>CZVKL/ko {ГfkDXKNyI{4NBȲ=%ڵ A޷ȌwsQ":LC[6j*uk!=TГR==AmV]#I©[t*ꀌs:Ttz@{0:SA'@Yo WFOŎ(Ɏ.2UJm߿q])Լ)*_{zϋz|Nq.mm .q:ޢ :w*2i3^d|UXrσ,3bA!zGƥBMJ8Q}sl$$Ԭţ{0=/N6Ijw`ϚgWj~GHJ9pòZI2n%箮Kms#6v3ulbز!Ns6\"ԁƙro6_$ۦ3!X'}+Y3WILqk(D5ΞF𳖐ؾ6IW\d>RƥJckKP*@dUF |KV/UHTT\nUSC ZjG^|&dަyAӜ)ӷE~(l^x,{7lX|Es_ 'H4TmI fCZoҵZKPɄO+R?Igf/\4/_}yAAAd8::&or8~ 9Yha8wa}x0f9`'.͘2R-"T pu1lACXaDyiuTd;\]:O>dgϓC<4qbPrdX glu"YBSعPeܯ,X?51wU%<҄g'k_r-(x 9yS~w4ÃKf{8 4IQ6u ry4ʞܿ[xťM=}<\UԿ3K ӺPE>8ڜ9܁Fn8զ׺px I8/ۑn{2I8r^2gJ2svuΚcu'=+1Qb4]5EJ>q{^쪶yGh2dRwPoP Aw7Y͋l5dYς ZFKIZ{?! nO %g C S BLTE2 9EcSXb= IV_X&N!.ѬuQ~y {],A N>$X_@%#b]fhU@r>0S6Gm^9mc.p$&'3De1Ymk^{ Ս+k5h0S|1泵eUY|1.̘쑍t宮h]t37aAd.MZRQBWpUb|8Jx"׍2|knE%1&#ܶNx籃׸tD 󶂌W>_ԣ\R A=e},J+3iqϵK803ټcId'|: y'o*&x >ӂd|߯ذb3lʙ\sZ2phx fv89i C5?vQ!*& rIRePczטBOۯ2ߏ_>/6$ɾaҶ gD2䄓Sr?wwo٭:7^ J)x8ϭg9+͋6CZss/^\#N2ZPUyhPT4P4?;ƃD߷B0!Hk3dvBS<#9uNOPjY"Pv1̷YɎ8<ε0[a2KӦ-Gf.WSYt@[\9gG@ aO˙9lףQII`eC41B||=._~DXS':cƧF2UkQz! ;X~e+ԭ ܈SAšig7 9$u 4.Ѡ nchY#C@µfK=XςwIPV^$iOju%]MÁr5Vc8gWmy䴍JР /tX(ܼC"g8*6J~3=nE&"[?G$>]nyzƈ秸=2&NDؙ.f ѼMCE< \ו| Karߦ [EH[f2{V/ ;B -Uٟfb|0b I5:ĩz%jCZygv%bljLc%/ߍ\ScRR6k0bVne(/si1^Y%rslcdTdI }kOOOJ( .G-8m2jQq/BIoqtu$;̤OaD$)l:'ٳ1uڗtFx`EkH!atz4(ՁBG13||ggi!g[3 Ȧ*u%`t?FqXy;m)}'VlIjAS|nMӑfiޔo?6%В=1tx~ڔ" t|_%7vgO_.diSQzNL qґp1IbҨzbJ:+I'kHz+l}*N%laqu_'F~ޡ0-nM]uN^37l|j.&{oʶF#[nIrVZnꀅ 6"9Ԡm)=ZO+eј㢘̣8ג=7]UG1t!O4ߞ{{/|= :)+ez&N¶J=o sߧρ1 {<+ic.f^׌d<5⤓jJ)S\iTLe_XţXc[2P%j&VLa8[Q%_)x:;g9[͓ZP Ý 뤔 >\t"EGGK BBBd^E꒒,v:ҤIaS2qs5^-zE;.e(Pl(9=m46X!'XIUopfOΌ'YY`0`0 IMI0$[.o&#gǠu!8}'w PҽL?&H: QP_>*!d~ß&_~O۔wL Bobъ|Aₚ o-LpV֭kYƷ Ik\Oh) |fY.<0NhŸ,! Z}-{|Xte  7Nf eŋ [*QAAA/=ƙロm{4M   h"1~XvNyFwKYYf1YtaIDb,  K'7H7;Ŋ,ײxjKYot9SAAy&ӲСCc@`` K.Y2]eQ6qAAAx^Jb|}|t}xyY!,I</nY$e{rS?AAA$«AUUEI;myZ.<'   cNv[Jo_AA7H UQ\\aaFː2(&-Â5EEeː  T"1~&|eQ {,",y ֹI֣`J(o;BBBU-jAJ$oOEQP%5ٻs+fJW;tDR,*& OÃ[nY K'7Hn*ZZN.   gn$BBBRlllJ3γOAAzmcmڠ*& EQEAf eYfݟ--ZtOʐ?-˺   hUb,<-iдիWO-ώ+ʞ% o$.]D2e,C  ϕlY wW5LߧpwWtI! Gy'q_!A_%hB悮> !   'zp|:43z8d&rc~C2J2$u7 -DV Ng[pkqw:NFkX7_%h9=:Mb}_Uo(2- /H0iR)J$ u^ ]>T ۔aI5.߆#",I'$: هrZCm.왎5>yȀ_`cc͏cǢ>aJƽ/A[s)$(w ~t,.sRl8EP Ɲ{yzj.)#)LT.oa{y(ݨ+[)C]ۃӋM0p vv8v?~߹\lgX&岇,wYӬ+Txtp:ڣHTWJw*,8<%ϥl!:_jo*lߜ5Vݔ餣 o6i+/r&DZXQ_*@o@֌ٴ%"˦KW|6rtFM̅p nE6 >-*_8kՙ?*~A=~;{aƎ˄$l<i;x+ji"cz71%s( arxܧa~oqVNǷ] m,9AF1Z]iM82w 3uA=Sb~iaZD%_u_7%CgDTA^DzeQ(w2})eHe7A{NLŒ?S@ ǒ  vգ:䉻~[fUs'FNԺgl(e0(kأZzç2_1  ]tP1ؑX}ĖIY/C9i/N=eVU/ǧY6v SFMS46L~@ׯ?פx4oތ4KHH_8991qR *FMqZ5ͧS6@Mit,KWſN$^Ob>0pbNNbD>^&lIw$ :OJߔKʮaa1cv1B9h߆d(Akv!F$X7}~T!9L70~u{dOkt;j/ ŎFĞOɳb"o.baFJGD8"EdƄ+TEIz7s7AAxehTUEQ?[h-冽=DGGOtN `HL?M=׃"~~ ?xD6ۨcceoHpтdM q?ӑ)ۄ uIZ ڄ :(V.`gseU?J*JSېv!a.ͫ(s'SM.ډvXYi Ӿ:ISTwo|ȁC0^.OvXy™=G+̀'1׽]v^CX\:N~vP!Q.iD^%йS8xe&AԙE[kQ*<=<} ...Ϙ'SU EZfDinŸ T+ (GOs.t.戌sTr~@PʁFjAIjEH %:ݛš GmےL->C*z 烺y#cW5]xl9S=hcj9bc#&{ÆXI\t;ol;A2s:/8ngroI~! bI-K;YwhKuZ*>LuR"EpuuMWfYC[-F}ZSf Q ْ)G%2(W\NʮQDDdGOddYI,#*S38rwKtȧk88!E(9Sh2'v nm`[RGQd $#mo\ٺa5#~]@Zֹ6y{`n^ςWj[ﶧr N}mC9-¸k.1Q&eh"*"-Mk+6D H YFMEm-ILǎe>ͤI4y2^|7j3'foZZʦ}_y/VIʖ,w$4R<)K89Pj %Tڈ [Ɂce; ݜG8w+fH6LDG!y3uO͋qcZH&OӍZ!te,/AyQlދ}ZPĮ}NbE6T;>ЋD 2!66)RJ89l\UU)T  c?Lg3viLRGN.8_',^jq(%g9J`~M}:Oj$F`ooN J\L\J#7$N6fFt;t:/aD&n8^/9?VN`tj5nkR"k|BlGg8cFcQ̽Uh?3׎`&z>ڷo,˼߽M7fԨ-)@Au;Gw\w mt2AwywLG6c|ӽɺ$#@J#LPב_fS1^XOJiSuk~/+cS>ܸ5, xɟNfrypvu\GV{&P }~hB?X`ϯKu-Ih>}o)W߂ `I pV]_LL 111ʳc9\m&9o5\g<6kRVrb w3uqssKEUP|K æ3QI|p'BRZsgF¥BJʣA*H[7&#FIs?~sX2P&tD IagX:kVII7*vC yOs۶m7g6}Zp݊w1l&KeXGD;9L .;OrDnnٻ(.ÿMo$;B@C R IDAT)EQQ& DT=RB "I'AzۙdCjg9w̲;gZ"NJnzel?6L'on ͆3e*޴55ld)#Ukڅ/Dtblϡ򌨸neLrH p1:Z9]ړ 79}:X vDqO,7 !/!1a?.ǖ[k!x_MBiiW\͢E3/ ƃ2 >_<_NJ7oiq߳Wt)m\SbEPe{4yo=8p#;v64=@|A[iw'^Jb[ hݻ-N{V:aX& RpgZZGVͮPuaс1#2fRꌰlSU =<#g3FOewjb^M,I1'Btlp/גEQv~;X[c nOQ9.L9R9}DFF*EUU+++Cttiebb`뎺3.t Ƀiܼu /O^AŠt]h4F#+WU˖͢K71;Fڵ9FPPǏB VV)/֝;wز%yaÆ yݻxx}`!7kjJk^*errnܸNuB<ÇP!sBǶK!B!+i:jPjl&4<˲ObھB!B"25eS!BkG IBB!9$B!B!r4JC$&pB!Bd9IsǏs}<$^rIIDFFE`B8zyX!r<;{;^+Q2~"kIbC _xEFFS<,OyH!)Uyr!I;T///Ey&92&B!r27w7cb"HqFboz嵶ɓ<,B!Y$MM͋h4[BP !B!0#UB!Bh !B!$1B!BIb,B!"GX!B!DBJ-B쒒8w75 !B!O޽{ǣ*js犢`PUPԔyd6n̟}3],888W77lmlRⴏF154 cJm-7Dy`B!B\ܰ`0&Ħ!9NS6nJMx'iaSOM### '/ J:a!B!'''Y&B!B!Fc!B!9$B!B!r4IB!Bh !xnI&Ѭ$&NT춄[yB!L$1B̢cmjQRɗ. 2$z16-1gbBHfga7*Ws4Z-_d:fA:z9֣yl4_4siػ wAJ ߲]zc&l+9fϊσBr{1Bςr3K# G!53]ej[$Mes4,neSRth PVLz {Sڼ{z|3jx el ΅S8MwcV1^Zw B0=+iyH8 uh\9?B!+Jxo[z:,0"`]y!^9>֣9f S}F/XSW1aD̦֟w.ҫuf\H iQQt.chع\Oro f:3r7<-` Jԡh2O1=ZΤoz,Vi3`WuC.mqv1kl䈪8KPՠMb܏uX7?b\!2΀owF숷]zi"wc%/j7w73yN·q)߁c?Yb;&HܥgX4gcsL~ )a<%D\$kgyU,Q y'ahɸ^̀21O(W8&,aH(\Cƿ÷r&| 6}3  i Z94w$߮Q$:ՠ gz3fGQZQw5-g|#_¸{-+ |UwGM:SpOf_wC!īG~r2C']/$Bd07Ɠײ{6 *11iتNx45;8K@5A~xwy]P23gn%XPq)TN_m;2ݟ%߳*m2m+ou~btzmmK ? Ł|-ݷmXO0$+cK/}9ofDe(g׾]A#Ys'eϱ`byϡS~Bj_N5$l `0hW60gԭOպ/0k-L?EApo>ijLQk qb1uznB1;Bz836lH ?Ж6}6Qbwz fSUlk(lUJcMˎqK,e@yY5c{f깧V+Q(ؗFE0B6+ ۳?V mQv"^ܮ+jCtj_ {żQêDgwVY6~18ķR~UPsA65%ƠlHyBťrM9Sm3*(%EЍMq;TՁmSn+OB /wf,C[k2ՉBJ hAO?KϽRV8~O4_@5m5jR$.Z1Z=MݏPT(a(VɃ V,!/FƠiZd4:QCӌě/.2V^1bl#2k_niܶ%1#ulEso2_/eMT89O6bYa?NEX{Joȯz;?qw9]'|RD|./9[X6%^=%` ^ ːͿUr;$c*8:9>GUQ0ٍY(7b J,w4:yG #z/N&[~8x=͍\JYUV:.{z3ni~iF]QUe{Ab슋jp$㺊:ApH, j^*F?<解89PBB5elu3 }'rG\+1wЛLFygCK-w/U'K`]!`V=̀!1I]" ΡS)1eۭ:QeB3"ի8Wf9kኡpNr$UG,I~c~ûSv>|N xAoH4*A)өyBd#v.Mbqu$N0z꥓ '[%CAyH82SoL,ယto %]'>MKSpuv2nfkK4Uɮ {;3Kyw{/o h;==[|[#jL~=N'sU?e] ~3A$i w 4cpڱ⸸vSL<\k:t1ܔDr)5kӨ^ V ƌa:'=r1,uoNy 6mL}P}'.ywNF Ւ w'4Cj6q ӍB!^}Jʔȑ#ӧO+JddRhQ%88X2DGGYY&&&Z6뺋:]uMK4 ]׹~E h4}4'4F#!я98,K8zuj2 He,ЂѣZ^E n#V)ItOUl:>JZ{Ÿ{P cuQ5}qV4:9txcݽ{Gޭ6hެy(ծ={Ty_9z>B:,B!^]{>>C3}-w{t>6 +KWU5ݣvq)2@Ǵ/\H11Y(ኢDj YZZ&$hoo%$$ݵ˗/뎎=CwP^d{G|}$BuiӼ,za|~?Ӯ;=G,gAO=f}̈́uaT=2 }MW6XcT:Jb!B!Hc̲6`^qƧtzhl4q+JZʾeS4KH×pyT!B!;rB!BMc!B!9$B!B!r4IB!Bh !B!$1B!{ 2 !Ν;8ۛLn$BK̙=޼H!4.]<,c !)mB!D CB!B4"""2g)1B!B($$hTUEUUM~n>\Q 2oT55m4?O`cmg B!B@ۣ*!9527%xژ)G%q؋"CB!Bh !B!$1B!BIb,B!"Go !@RRΝ'*:ڼH!4vx.zq*rX!Ν;O0/B!2͝;A9{2ޥ͋^{S+ʋ]S L}$1B!hIBd9//OΞ?oO8jy(S WOj6 !B!+Ig6yeffB!BW$'i=x9%9B!B$1VD#,8KK^gڼi9黮ڿ8PV\eG`'_r7L^[):I9{wg`ZÁ~/'ɲo'F!x\|K<Mb)ZID}|W<,D`o|^Cgs0{Xj[;` Σ~q͌z1.g˷;#GvN'bç_`yB)#FjFa+ h*tY @#&4׮ kع\Oro f:3r7<-`$?fzAD Zψ'1;nDЬ-Q-X/\ĦwOF0CiӮAҁ^f >B_Cw?/C#P=*eX>uAIк_2kՌ'y ZtJ>bmnoxo3{# .ݜ#_^t=$njak;z$X9picn)BuG)acZm[j>7Ʈ5H.X18;\my3:elVlS,;vШxl #h] :-ގc\ p)&_z.'PV^ Ū? p:y K7q1{bYOfBGIr]$K3 SiArfjLITqJ9_xEl>y8: ~iԍ;ٵz͂VBRj[q7_6o#p*]Rzu"/!, d/)xPEXa#[6mdVwV%1Rve?KgUd8#'Wߴ*K sb;{vqh IDATbBL0Ѧ$p`y.cK.6藺V&tC>gaPur̀fX;>/̓NU Ҵ76ƫlT7%Iv&Ӷ L|_^ĥaO9u&o1 Տ'+2nlA[oQ:'3vnCPܚy;E.#xC?Jc\0g-dT|x'ʓr>eo O]_K v^6AߠOf[>_ofDe(g׾]A#Ys'e#=BRz7ISB5˽F I@噄ȩ{D*pɕA!Ύ܏HIDJ^`e<8t눷crPG[H(%{\oP wM1ڬ0v*Xz֦:7?f(m fY{͟[DNX`_JZ~ I](lՑRoLkw}i'TT+ԡm~HҢ/r(n15UAW P(ՠ&\%<-tq [#lfՖ4p04{%QUGʵoI;m'dۙ*XSvT4mߤX1wSـbSs)mT&t X9YfM˓[bt"==_R TՖ~è7q:˚݀5e5^#1s-iۣyA)D:~G~t{vnTkŀk4u?CQ)B!^F2:Jv<\jTO%E+x'O}ݕ>rJI8TG Nh |+NnZ;WP< Q7l?H]ҽiZz4GfcK,j'zg7gƣ܈Q0( ҨZ8!ۏꎗ["gâqT\Y`P5 [̜bo݃oK^rSaQ) T=p3mߤBwH#r^-;1)9NfOXynԟOohyu 3aoC_{F+ $YKq6$Հvz0RHu1}ՠfQ!:YR`lttv{-&q63yݎ1]^!@xy{51c,H oз)Qj*pq $WE\O07-ፙP')t"Lc ^# OAf2j i3t7czjnssnHivVڧ̢Z.^5/:r?KotTU'mt?-e(NnU no~Ǩ*RV~T<j.\`1Dl_,\qI ^<Չo߸S9AapV 86NR|@/C$,Nتi1b\)5Spq͍uŎwe-U0.O)*1eȱ z,¸'1>+/dȸxv.[,CZv1:h\#qJ2yQ >ߕLp_ /Msҽ0]#!4$Xʼn+繑ylQfM]ٻp1'AܯlO*6R N5?{O楠WǏ]' 6v-iv5-lHYwIƥ<<|uRپp9gtH _9lEE9Z6'`|ţqBqlP<m;= @DJ[^b y-T? ={:yJ Kl ;]XVθXtttԧ^%.-M0ZwϝzBHq6c)n`"EoQ z-^{;'QPTսvG{ Ѫ7Wjy2N(ubJU?ǁٱ6xP]wơ(V}veޟĈٓ۱!AK)Y~j֔?ՙ* g(B=91MֹB)&T8` OÏ6|<;Zah4kWJ$"zj}ҳL PK;Z]RngԬбW4, QXpMWS 3yx,-,/T#i<>wP>io\9c m3_ЭOynF1?_էzd1|'4B6xxɐɥ(`eBW23rHJpp-ZT V ѪivvvV;Nut]GӒAk\q" c4S>F4MKF#!bF#54HlL +Yq1ԮeV>aʖ~3^mw[y2 B!B$1ftB!Bg"q6#iB!B<IM2c!B!x&rl&~$D TGvrQUΧ\mK[Q$&Zs׋VkP٧~ͻo1HJ̺z16URez9^\ ._0`0Fe(}[V%Z hSay"[dػ-U*|jc<A! C!ȩ,x>77> 1_<+'胬 t.B>bxi$qr`=_?o=Y'--@ VL[Ɉ_qw|ﺞIɫo 'Og2Feေl˪?HIzqyy|JQtb(ćS˷l{V2!F"?#q6B(iEbqܾF$ע4٠=8.{o6¯n=5gI@'bCj\ H:ɔv=vwjNڵnsKiY'իGf$ɹݣ#2vkIuk&Fnj;:akh[h[k M88g Q~KIS,օF~~5giJ;ʟrD'Uŀ͑@ OV OS~3- vqzkL'AMvL6ۀÑh íR*{bi<%}U5sdӳ%MZ}ƪ[F"6 W[9@Z׭N1[ m>ƭ-c;(wer$]랟c~umMńK\aG~䳎ZUty1$1`+FuAͪTق^dиcg*YGD{D|;) :|@5՘Np!6xG:SKS9iԹ|1:6ZZ'ZtfҪ9|Ү!U}}ޢ3]]I9Î/j]o,SpMpv=] kUJt%yoEHsܹ|X@EHzq,=Z,Ayh !&q6c>8NBtl;o_f1,>_cW.C:p0jiVkٵ{ I8g,:^}L=Qf9k>n>˨-;C)ՠ%άc-NhXiVl.)3wҀٽ;t=-VƊLl@S0+ܾg̰\ь]>6=XNvo_́m([%L[ncwVVL%͓*4EILZi[ɽyٲUi̹kvqP>B .غ3e=6 ApFOnXi+TNӀC#>2se|eHXu_?`ϒ޸lWS{#xl/XpL89OVd=6Ʒߌk7V3q;sq׏(3]vzd͝$ҕtv0}_->^򡣄@vqvN\?| թ`v6Ot)C{0q~Zw€W/hEYsFoܟryQ! 2 s$r$-VFe4=?m*Ga:AX.JɼK§}W*ZbO)x:7gЩgU-2O}ٻ/ qqv hNxq#Ԧu-'Tyu.$Wu\MӪ-bMi^ܐSKnvT .mx2z. n]7;;-8q;=hSUul攺t V~yJ! <qs=Zũkt2ګp$?Mhq(jҞ~S7q +Fp*13g=i c<IҒoTjvuLM{ݛ9TF+|u^?)Z FQ-ܜk9x:?p9n^.(ƁE><7JG+)а$+= (c!{$F\q|6[9BmIb, !+գ]t?p*{q:Y]7O͏n6܁b?v+R((] .~n< K ߣ,=8sy <Sh换z=~[ySe}<5?Rr2F_Gz !M$21}TGr;Pl_,aDݝѵq̯3ͻjXŸ3( XG(ƻ};L|AQӸ v=L]C&SoAA@'sWJmLu%3PH^ #~ӱp-'m'lbx$5u(ƺbG뀻:K>XzD @Á:`[ȏasؽ#Uy7ǵ+{ΦϱgrH&2n'K֚fs꥟Z!DN>BDʝ7(Q\5yp_)݉ƍnwpӧkwJ2)4׭z*j4/vp#V4o|PңCI@'_* ${tBvaf.gǗMٻ&ݖJ~ݲ-Iξl8WXůJ!)?:UŷE=S$zB8WN_微voODG%W(d$1QG :_70Z^{HBdW\ۅJQ̅m]DGDneLrH p11Ws# (y~eVubuHNݢRr3-,rX]'Zf ŧ/Jxc:ur5O?ŧӢ-0s>I !8_WŽNK]Z̷.a8;Y?6T^[ϲ6u*_g͏Jc2m-UT%lB܈w5?&aأ!#EKh5JQjUVkMKbojS=9?2$WNzW<>ɽ=<9~x/Ӟ\Hؒ5kB!eb_!^IiN¾0ow_4#fe8\ɋ;R+'B <3͢W bW-iZlS'4P{ 3ޛ͔fD:lXas2XY9R0ؠ_9}9B'.5cD7~Ʉ^&A+%7f Je5:Ĉ-3=|I_Qr% IDAT5f̔xH$bK XB6*Ex+p)vGyh-k#}C4xN0ѡ4+ &i37Tƻ7g||// YF.3s&17b4,cJ9W@׌ 34AVo)e)jtYWI[: Pg+oLm;1NMњmz,-=;f_)Xɟgg^Y!x:%ŨQ+JttRD %<<\4ƪmllɖQut]GKҨis-+d(d2iZd2(qdBu4cY; 'O<,+޽{f,C4i{j*SxzT7 t;Bц[_- ;h,֒mv1yBٳo C=vo?~ݰ`0*f`0(JqUU4RgK2+•W)Z~抢ϛm0;ϦD)օ4]_AIb|_h~^Ȧ3w5Ƨv.GԖqI qxXQ1d`8eK޺6ۿl`Vt6ۧeAh]l 'Cva+>'pe|:/Q) P5h Sk^.]L…j^$Bmr%*/g^$^"9MQL#\L-lC>̾#>Zq:Q!xo>2g vs#kbП{Ge%O?0Wf=0AC1{KЗ|Ľ$qh6_BC8:Mfm(d -S 6fN@p?wP/l>WRγf.L0<ѻ>^wpH_ JR,/111aIb vt*6]m+֞> ae>U솝f`ǛoEby1XTeg-r ~KPPͷ2wnrWo;p]ߩ ԧΞ]I@ѯ *8`cUC=4-Bi["$imV x- T{+5#}*DqPƩDN)hi!B!D!S_9:1$)q S vܰ}}S4LVwEO:D^Ǵ'V  *?buL:hH8ʄfLI+֒jǥ%*.y3,0I/ԻPRfl⛽ںCd<@&O\[jZ3lfYlv>cMG{-C"K!B#Hb1d˦ՍG.pw5(DTg D܍@-( *zF6CoYUGgs2f9ϥ?bW &dJ<@9=Nn@GX󨨖3ͤ ޟC([{w!B!JSbs~7s?۾ Q\(kAyx1{/o@Q jhW,;&\hխ0.pB<Za2Ҽ1x 0zKaϦсk'di̖=/̜&rdwH_a:6<ω8w6x`JRnSHB!BAF_=U0"ORT{o>iM弩,TF?h6l7a~¬ILߐ)0/(R1}xლ8NyQ'6ײ %2yl N3(yWT 5Et[}l2޼.6d:Ybeȏ-8lJg>TxFoQbimAOމ,9B!"G1P 0Spԑw4/H.y5:|κYoHwV\bOh)b9}[npפz~2,*3t箌_Ug_,eH*OR)})?u7KMMs:AOƮr/s4I%;oB!B8KŦ/WQW8?81[!B!XR89%^:#>PIfZ^Z/V;TGYbO{pU}mkd&jIz-=LS/=VmuKP,)y? r-gwi򪏸qߝ̉3Ԕ:ulsD[ !"gc!ĿKKXYEax7Ho 릜gj|9s9)`j'|#{|̔+z<|ώvH-ٝRBپUۏ=UdGh#:T;'zeQ]ywX qdFaΖ [Ert|g4̩9S=UCco&̉ hF87/}/}AWLaUOPg%;I%B&/ʸ_Dyke]LRhe^&ckQwn$|d>x=+Cm~|? l8Z'QdRw% S͵ sQ/?Gq[6nٽpB!c!lW yԦp1_#Ȫ \p`NNMT %R5(S"a7m]lXN=pc|:P Ww'B$&+Jt6աkqLsjqr7Fb(J. Lg'#`u:R^3]Z%z. iYgr8eiUUb&:.E c: ~nCqRg܌Uq(\"٦@"{ stT|#nߦ]k9j6RљOgv=+ӥ'.FPҰWkľHpo[fteog@!r)<[r1O !BN!fT|9BՓYC{'nW2݆XMcӒL2RK l~Rmqr~<i@Mh='V%'Ո'X)mQ{ƭ]ĢbIǾx˕y]7l nCj(9M~kU-bxeµ)yqI1N>HVr;2sªR0!@ j*4|??wk)֙/ټ=z0wcJgnkF \6BD-˖ DR:9T1-_χ[#'}5U}rwlNaWr^+[S%5\!%T:ZOagSb6|sH\?Fճ\Je(`"9YG{3b0F)`KJyCqrwcHHL{dNԾFa{eRԩ/@SiaQ|1$FrY?QдY}s{ɠ`ujW/\Yƒ$c'wOVqiǵ|W5@K %nDj!B< !iN¾0ow_4#fe8\ɋ;R+'B <3͢WPMZs67'ҧ\R ١%Mmfjd{2,(Y7 +vn9C"4++GJ0+Ǚ;/?G䲴fF/c]SiS{j#UvBXPun~ѕIr@ӑc\i_1oV_܌"Q¹?KE0aLző+O5f̔xH$bK XBOP !B7|b٨Q+JttRD %<<\4ƪmllɖQut]GKis-+d(d2iZ#^z7n΍j:oϰ`4B!BW$$''ӣ;9zEQо۶T+Wr*VZͲ˹v̛+ɱB!'2~9zWWW/\Q(_FH3j.Օ#G2IO# Ӹ nf<ߠG=oY{ݼ )9el1d{!B?Lc\W^eʕ(”ɓ0Ã/&}(,_+WWߣGTV*=K60DO!OՎ +)OSSdN&%f߷#yU=jzz]='3TCM[@<ŖK/ K X˞M<=71!{eīK4Qy<=Ȩv̺`iV boiA[P:|"CKIչB)#9y*פ7?dރ]#&NKTu; yah^ n?sh~CxO-Gy[ú\6x',evv\WB:?.3Uji8\{ u*H1;Xw1:tkZi,hוy-@l mhb tᅋץ3< ՁEm{="1YPk0]¦0Zz;:Ԣy06n6ϩ=ݰ͋Y((X3MJR7N>G$u Fg< *]Ҳ662&pl. Ӫ jGM({u/Cu\tfC݆e㤂!1 =:ΦǹP E'u9eG7q$ 7E^g1]Ⱥ08:6^4[ѯ *8`cUC=$Ef*<(r8!TG7}1Q8kV淝lPOgϮӤPlޠv:WkkQ]p1jW.oC OR юF.'u,&-΅WTkejS4wnIb,TvXBdQ`n+WR|9l]VJYP,ZUO"^f My|j^tQc%ޟ7MK2lJ-3 jOnBLq?_όb-9F<)ZOiÎC0n" oO:Ǜ^=i8a+W=`pRCq8n[jÃ(U]MɋSoC8@L^ KئGGo[2$d V4 7?Xg gG7ލ)r[I2KXzi_ޯB%|Z/ NM\{@?(K:NG.GlAHtP  =CakϢn̘k9r5G8߹GDQ&4eJڶZr"ZX-P'ޖjnٕ gJ҈ <:-J+II2P16mjjsLgU3Tj!1ajxyq\1FgkŪ@B2Ko>ݎ̃*eыaNzʬ:UE)ʾ>]q|E38R 6(jtã<ڎI 2uh7SC1Xہ_ϣmv%}GPoّ;dMttv oR)MtrHɼs=Nyp˲$ .fZ`#z[c_*q3h~Q%,Wuuh?j(;p6Gnx?ψ>sk":g׮m9>i˰==s?-QZ2_݉z)ű.W<g/*h@MpΟ;'G'@QlZOxMw+G-:J6| SB!tUUYj5G3/~cXz ҥsgb!^"1&ɭ@AGn| k[q=7| dJM(vqn8 MbYн>u08ĝҾloЧ~gm#{ք"^~@ooj7u!rwzk;+x=8s7A|݄xre9zΜe~c׮O {Om*EuXf(i:4|bnyi*4 4[@&(sr-[,•BMzb {$ZMol=Z͊ %2syn TE>_Xfz7E}ؚӇ`fvưJMεgB!r%ŨQ+JttRD %<<\4ƪmllɖQut]GKis-+d(d2iZ#^zc+WbJV^bܯ1/z{qGݻk׿lٺ<@ƍCO*USxŰ6tʾLr,_kO2NOo^BfΙt+mk~c [[[ jƿ d)WU5O!u`>ky]1 !B!?B$">?<DD7 !B!?B1owT|""gUo$B!ɈB2pAyX![]L:!#9 !5,dŎ[ ߌ5/B!62Lc!PI9PB!r"J-B!"GX!B!D&B!BMc!B!9$B!B!r4IB!Bh !B!$1B!BYB)))\tX"!Blmm(_*cI"t2 "yB!aawpʗ3//B,&6Vb!_/111aIb,B!"GX!B!D&B!BMc!B!9$B!B!r4IB!Bh !B!$1BG6ƽWpS3/{Ť´V {$ټD!B$1B(6_ժSռ|F~wȿ*ڑݽq}ٟdfQ#K HO zjTׅO_%!S}6r)NҿxRe?f aN<=Z3Wr.V7`/#A1I=͠`;T*_2  ܝIҍ5^6?;D2:zd.Q7\3 <'Mݎ觇*+ѵamy&(V]M+B!>BT귞ǏqV ||̴q[e< ˼Hǣڱa#~DvDS%u ?ccj}& Љ; $PJMCOs^S'vΊ_;:k=d8ӕ;zc[&Ri pvLY;7 Dޏ­~ 93oZp aK7l9Ft6l{1hZ=OϾ΄M{8r7fyN_oxO;!s'$?z !9$BbaGa'p'4h6&[G2*.n-[&hEy?z L#urL߰A;1aNǿqÖ#gr5ÿN| hnd;N® Fu~ KlAE Ԕuv?[݃|QGМ\jn~GVXbAMOwns<<AMS'1_6 zN2?e.gj[̬Ͷ*ӑZ%jOFupYRT=ޡIżX̽;2%&B7eVLG8׉x+FCCURN2SiEIZQ3 EԾ,cY,P)RI $&C7yuG -Z$(nVy~B!$BS -?0{E<&mdOnv,;~EI*<~άY΁Ek9 UmjwHW9 Y2yMW wI@DZu|۵\q-b'cB2;YߕDZ9#qs߯s˭$%l#(UWx]ZpŨMcϜkXoZ?@&3no+dޣZQ KʯEo[ӋE@2,מhۏY2'9xwM 0xa^;Ս:)XXZ>~N9íaB!}<BG gg˫ۢ-|o J")E[^X) ''l  0ݿ|Ѷ>uգnF )!aG W'MѨpn2M,ڏ%2%-N~7XZjDe낋 ª.?HKN8;>6 ihFdx$=^fYIq)1VmJ'>#ֶؼ෇ƾ3n^ IԫU9QH'Z~S?ĉ͟Sx: ARf9eBU,Q1`S #bB3YP}GŒhv2F"?^A)ئp_lɮۘX(ߜh;AL者gcua~݊\U!~C!)%yi7nG~A@T2G0A5Wթ"-OEPv/-(_>j茣/=7' cjp&ٶDQѮ/vLb8FOi詞7'cr7N'}+nvR ػ(㿙MRIHQ;*zEQRJSAWE E@+ v ҫ!!l$Hx|lv3 n6)STI_Ç^C5 jPyl;uضVd'k"DK}I?O6Cl\]s=[6+ʼֱx+:-%j>Lߣ4 Kf{XEb6KPb,Ƣ/fATT-f^vo}iX$·Z-b-s~Ɛ^Ѭa|]DDD 4}-"瘗/cҝ$^XF4+dǏ?q8)un \X#Ȭ }yaVnk+ؙni{ֳi_Vae/9aCZ(mdq'U/{_o؟ vv1=ͺ ԤL4:?T s`Fv;`VHkkyo~\mpaI?W$=vcIg'ʊ6s0 d~:ra#yK.IC_O?3ц?Nx%eT7ʻ3QΏ__Qd6fɋ1j7U2!^vzJ^OVDDD3bƺuFjՌQQQ4ӲbŊEfffFELӌm;ζ]tc6mcFZmع\ Ի^/envrw%--ޞwkҮMbg$&g7EtzUxQ+iؠAxڵ4m8X#߮ZEslyzgJLLsC4K sr_2g5; fX`x*KhvClY0 z2 ^Ol 66{QlRx{%6&&Xq!elB 'Ej\C6CE |qո8Lf_hy `;30:?ɪL Rztam4N›QF4jP&:S -%rԮU7aӦ*9 bcc]Vx3,Oe{֋{.lG7ݸ9}ώbm%D+JRk+8<&aŕխhԻ"ϼЎG-"ΑL^<菷扦H|5 JD+iRnbBEPgl~^| .GeEwGu3e]-cgpx{ EnTE:| : Na""""""V&ew3/@!V>&4A9=DDDDDSm;0v`68mDRv ~n.ճKDDDDD.7i,BDDDDD传""""""R)H`,""""""bYYYlܸiiU"""rNژ( cBlMTTU"""rݻ6RN*GBD;P,""r-ѣGË%)H`,""""""FJJ aUc,"""""R'.87WaߥZșZ"r^2"bԤ'W?ΞݩX2w'љ_2똴 gѫ3mwC<2I-^ ƋћѮM:\3W'cNk:Сk~3)6'}ԟ1:oON?|>smzx7LB>]C;v1aatqpN4t3r<""""3:ξX$`"Tr^&o͋yx/G->fYxylƔ:k4LZv Қ#xqsJXw>θJyޗ9?:cu8~-;m*GF,bhQ,eG7}:L1>f1 Fd)eHYDDDD9~sMb7Js cN9]ؿٯWӵ)tNe`,",~x-^++h |!a {b"vq@-&a Z[PyVvyᢝK.7iFBP#}ZcK"YnJb,^rk'pQtbig2s턷ZPתbT+, "f嶡 XFsKMA2e8AU.`8<8ðB{{PlYcÆ U&ʕ k!rEpiLW yLz>?:'7\7>S湛_7"f J%'bC9tb cKj+Vt"[z-Fo SqŚrY"Ο.E^=-Y2e2zGlO!zNzQU"""rp/Fz魓#G59ΛRޣ{w=9!"gE͏ٯ X9nf8zݷaT%G6rS %crל\z_9>FD&hrl]MQ:E+Iҥ]@x4q ^NߧЯ@ R^zga+]A4 TIaHБz_}uP 0w?ە  )Kٳ'S|qݺL}"#{↛˯2g\ |Ps2Jk /w1Zkx]8VFcxs|⻿ȗ};% IHyҵ_1zۃE>?Fǧ0F zM\QJzž>/O(ݑw Ii(-믻6"##VDDDDD Sّ#W^y$''PDVDDDDD S0:~8?͜3ۻwocO e̙\wtԉzBXr5?>[(_+TD$'a箝V^k4aCҹlN.tҁ""""""AX9p ~ի<-[GnՒ%JJNNf_2w<+^/cthߞʕ*1eT-+'ѲE󰳈fY^,۳gvsG40 0 rʝ}g*4m p׋4 9i{X1BۜK _~d߾}?a+Qݻu{߿Iʌtٲ1r$ |R."""""瀓,m㱱1|74ؾ"۶]uP@.,`,k֬ĉԮ]5jTk'$))reѬiST @bb"|܏ aÆ aGŽ;ËDDDDDCmcca/7,۰,Ml "HC8 #qCq6 -[PܳGp9`!իUO/ԨQ?x?_6mBE܊a}-^%"""g޽{ /mE`c:6024ce`&ئkؾO$qio6F6LXHMM{HJ 7p=="""""r.bsqqV>$睗&N¿"܈gXba-Όڿ@LL #}۶y"""""r.$vqz-g5k_p/wK0W? ƅ؆Yz5Zea-ά&NBoe"""""Rk lkUpP얟X`ڴw՜m¸q[l9w J\) y;y~+bX @ hղeXٱfZjE X w3)ض=NR8-yX>+ `޽4o<΄,O5k8+Xf"""""Rپl_|WE~u+R߭]nִ[l)ZZDDDDr ]Ǹڳ׹n1@]5oͷ08< 8xlٲ\z={ߓYYYlܸiiU"""rNg]?vm>N8̓BÁRJjN_\\>vYësʖ-؇ ~O"rnlܸ*R611JDDD΂{~F֩^u dXs,0N?S #GK(ݛ<:Ex^ɒ%eɁm97)Ce&aӦ󓯃7cm^ԳA l^cFѨQJII lŻjDDDDD`; pgT' lӔ:zD$"""""'5oq> ƅTRRR`{sߓGloXi. *+GW͹?+'gkg|^P0.ׯO|3wg՞;K8OzjEDDDDs \b,g(u1:?`+R6[q&v۹k6omx<"""""rNE%΍ 1x ƅXL97N`C7ۓ@(6õ }.v(bwH6CvٱcӦ@幼cǰ"gMʼhytJt9`] ҿ,Lo󊈈=N͓db#씧8P0.Ģxpdff2fgϘq` k!ͩ&s#JLˆOמ> odmI;~4h܄&:x{Ar瑌 -]hܰ;Sp9 v9'nJ& n~f|$ICӥMs6nF˞3~^׀-L6On='!ޭorͥuYϯ= ʶ*5/ ݻSXxq)SXSjլInZHgjLrkm|{:'>7@txiX[Z8ސYxwS/Gh*M}/=+?9ֻ=_<ŷ_-cqa'`I/W&†PWXjV~~ǧnqd^ [eXo{7yz^\3?r?O'=i@DHf# nBq i~i3[?i2zHw//ku@ttt4F440 ne ].]:Ҧ5 xK[ZgdKлSvmá "b+o6k8{tmێtwz.yNn9~x#?McXo9]|{;F<&5.| j??qT<M/9"""A?F aRO~c=.[Q#Fz0p ,\['<@^g#nݰV"R'U'>y KwjY$}xz,E˖(<`lo=>c{))9w)c(dz3|:ȣڋʼn?ŔxV~[-Oᶢ =y5gvm>eŒo?|qk,\i%ɑ c;jP$jV!yen曵Ԍ^c}{бcgz3EHPUo:V:*~uֳMntSrVEC>>Ɖ_Oۖ4nޑe`pB-A} vr ~ @n]HO?C楉$>۶y#?!"A6eҽ.?_> H_͜޵*fe+]嫹c JjŽ}%lBO˹MYr׵,/_ѓ=~OҪ?.-nbF 9li Y2Z5kI 81ۜH mZ_HΝyMm(Fteڷqb._]W$PtIk2~QE)(1(Z(#=k{?i-ΰ6]~'Y7)ޱo^I?RYߏ{F\ּVGzP`sh <+#9 /fDuҎa4EQ$#qt(C1K%zshtSojM[0#CWf4zcW!X`~Rgs\kE̼oc8o+'3;84/pӤg( \߬,FҾtp+fW{iP3DB&, M#~]U6S0wy'ָ}46lwM&Mӻ۷x|Q#GX|93gU1113ںZΈmA; nWTIR^[P9o/iPʗĬCisq2c/I^=(U*c }h'3~AR% z ; IDATerlx.A}߳ԉbۖ?ZT)ʁC>% ˌ":==WuJv*?.><] ;ԏ}t=Kvney qr8I{dQ"E܅"""ẹ&N?:{Fv׌8_(K6۵e֌0EU|j PF HLL`?p-[ڵy~]:w\rHANd=OәZzR{ycI;vK0UL8 xX.1v/aipgcb >G~:OH);ٸkCg^g892mͷysiX[XHJfԩXȴ-,ͣ[,""\?g߹\?!ì`Yv|ccQ*y O7UW\VJƍy\zU"yY+W'-{P?k* ]xjl ϕSVգ U|sM*暱H49һ{KvW&ggPɘI]yv\:/=? P;< gfEn9]OʦȌN23z<l/\ך?ҢƌMSP;nϘ/QE>aєR+"P28HbKx[?fgv8X.ju=/M"""9R[` NKP꿺^_=nÇ7֭[g8pHMM5Uf8p򤥥eE+V,2333 (bfmqmҥv,eYض͎;zx@bYVo/w{^x)!|v-ڴ/<سgK-㳥KY;22r^y6**ƍұC:oOr›H߿?//8fWawkҴIb9|j^EDDα+V=ԷVonXxL41=op0 <16MLé7 |xx#""|{=86FM7S54d!0`֬Y= 0T˲Ҁ㑑ǎ4M33&&&$$X[n섄N:>-yX\r&tḿٿ?$&$Px| """"".mZIνS;mM`# Sn66]`,0 J,Iɒ% ëEDDDD3cB,66{Yw^bcb‹3wsUp\v]ؙTH/\C1hHVV-֯M«DDD,vZC9/ض69c|>Q0)LӤn:"""R{]׽6 ƶ6%PjB-{Op_U|vaB.mV.EDDDDD 1_eى6!I9𝴀O2V0)t3,<&tѭv9V0)r !Wpx'ogMNeN^AXDDDDD `pg܄:#C'`؀\׻|+cB XCñö`uED cYO|wG@"""rv(aL"D{k;܆F([xƶ 0Q8tG.ED '֜1t^%"""gylq^lZ$*ؾSHms%g l #%  )6X """PJEt,N˨u,l l_Tv:C cwsge59EXDDDDD 6e @}aҾ}+pJs9mS0) ':p6&m'nc{>g(:::HDDDrW7XRb>g8XrmV.9;c9Cl{wLh v3_r2˾a`;@X_ۘ秅o>MxhqFhy J6ǐRoKCj}拈HM+;Ν팮Sg Vx~>c9ceٜ4^Y|_WfahXWDhjӑcXw\O޸"Vd/O _AtB>x?-=|w7L:e,z&gةye0>cӮ Q:^ce,5^EDDB6~m;~5 ŀRC\oN&e0JҦ{K|UR&b12PdOzҠAC5hHFxa6ƽN Uh<ↆ N7{MV$x=Z\\CO3){uiRk7ʭ ߊޭ+Y7ڈkN`q嬯އە% =1!7+uxߗ0C]n Y#}Z۬\YE*pA T5.*_ԙP[>I/#"""yKXN\'aI g ?ϱݗ׶[,{kwS?:}D5?.cȳ]i>9rsfHDS$ g"R/Sdf %K WxCăeXao)?;i]iD^q?kbf}qKO~:]uORbH*|.G)CqlLH,ZCɁQ*輇s^ۙ|eV dEd;mKzs;P)VOMaʓ1XSn|` 4K  zS~Wn7ۈQ<9=ƶ-l_1'cqq\|p\7< ׫.ÿo/nt9mf||U%,v7<)eKhpʶ_6s03 Q d$"""VHAX?ϺsH!eӯvC+w]\Cs ߂'vh;'B """"""Q`ش?wha7$;!ж׹ rhOED$G'N/grtm̗O&x-cp^P0)pB a=ā!.N;0j߹+S """"""Wrݟ~_-x_c K [Whc4FXDQâËEDD,Y5{‹;m׍ipaç]iF `N41.H8"vj1)jDc5y*9 jE‹ j`V };0ضm p5@'k.HP^lZp8ȹeh_=M!NV]h({s;{lkc[aA|SNu ;&kHt,pyd%<1{ cBLOkRzy0v=.SlCrR0l} 7?,۶C BNp% """"""R;/>$6vH.BXDDDDDP K}!nmqcaԠ_dPcq~ 26ނZVV7nhZZx11ŨS6Y(mlp+>q!)m0l@ Ź;q`,%(HeCj4B'؋Hq&*VH*9 xUqf@íw( t=ȶ 8Xۡ+0%OGT-AܟŦ+mR!ö?8r$븋H;P,""r-ĆM‹ $g-솱m0=خclK69ܧ ,' rJ"RRfِis"(: &"0#^vf>hfD]_m_us(ym c Öecκَ?*{ dzlvz9x̋KdPqz1lHjݜYK[¶i976A;.cUB1O}i^%ge ~ Ӝ\DI1NAzw,""""R`~W ۾/9l'%DDDDD$ؿB9O;ٛĹbMH / ƒM|[as,?Aeڤd8{Lh=DDDDD |_6uC"4l&mCwSRJl⢂O:s-"""""(w_hPj |\o~~QJl\,>s5v2;/Xۙҿ5KǗ]&O>G_oIgHa糭2`vΝ%<༬B}*sh&Pplމ6N.re>c]XruENp[$i5|Φ,Oា$tgzPwXssy_ٗC0zp;ʚ<%-&j_{FqYIw~gSM76!`Z@$%%JR% B7 %T`:>vHꤳt6|v3If>8''b5PǞ:=5v:[r2tŸlI'a/6@ʋn_@j[〣6īk1IퟸgE.&vqaEDDD+H#vz (hB a !6hz71Bo6X8wUgǝ^ 8+w?|;w?: u"n}in<3qs+ghat}EE;»SњŒ5a`n_ub cs1?)݆m~SNvX\ލ=mn} szd&L/_!1y1>5c2%P֗K=zCO ;8hHلM ,'6#ø$ 'o3x- o6@ k&.6Slo @b8/1o <&8;%$WSG?QbBiPG$\!`vƃmM@adPj*љi' ihǦ% it' u ')'-PX(Zyhm%Y]KbѰ2@"݌)?R ZumA7>i!E^:@9 LW+7 IDATmYX>,Av!7`Ic Z҅W;#yX iȝwI%n`Texѿz_^]we P{oW[%tIl̙<3:-D\`&mc/ """ϟc\ .ɭltQ(a&@G]m`L}Zԣ0-IcH Ǟw ʄo-̢#34_n/ >~Mu6đIeoOw>l~Y~JDDD^lu~8:`1 e_h`lBm!`Lg4^&4p3p\ V~^h獸Ƽ. vBߕJG\L(:m61qZ=4U.᳎- F 4$FWNciF[W=ƚrp۳~Zil_u"""WBTbsvQ(X#j.uhװ.y95`L 5>mvSC3@ D)9&[ӀV( 9F[k5 WQ6(>Ҥb͞,cZ!0tfl Q?P4*BFvԮuQZTU/0N"HJ |(98^%="""""Zɉh28ݒIf*w.hYzdas@q[:^Kqt5c*+cRSZKvd4v+yLD+F̝;&h̝;M+}%앳s|[\PXϯti0j҈ 70S@ `&d혬Pq@=v5RVoC!GV7g񛈈h455aQЍ\| * &5ۀh0^}^4Wj6XgdPrXޫ up L@nU/1N䷓kzćKCt]FDCEJM6◉h6H DžYtQl0aن`[ŭL@64`zQZc0&fxQZ/&Оϲ 5НΙ+XkD)7&!6:phUhl_3\eDخ3`0& IIcH' _GKXֻ_L `I’ F L䖆M)fѕ] """"E[4v0A_aV6+hBR2:vd]0אش5xc~fBoY3x,;np9՘;M-HSpfm||G6j*Ғ̟ܛ3e9dYoϠ7g i^;ZMDDDDD5d*BQio݌r 6> @t/cUjx M"]J7,:2%Ș8LD]eh3h`nSaNDkv2#ƶ_I-aj1 EPcTk71kA6cx;P;3dlb"jph Zn8_Bk RQvG40kA=5 VwNcւ셩GIo,*6Ֆ AKt\+pR{03@`ՕU9y x7hk[h-hkCCc_P"#Rr:mۍ廄@ԵcWGm-#74Y{1F $#x.FgF;>𛈈h464`FAH cQ@xkaߺIG#®hòC`\<,朋\C HR k($d`\CFKJɓ&e""""ZeP5Y@;k2X Z堡J^PcJ=6[;[/\9YEn)sjAqslvF~;9J-iG~}hrm `Bcc;T}Md_F@q ܼ|°F4kjڬFMZeQ ۵`.wjJ)Xܽ&jϛ#F`Z# |0dy/ODDDDh 2eV%Ξ(L53Bwڌ#oK[@.\ 8ɠ&ΛP?+0]K??]3+èF`tf-Ѣ!( dEOgA!s ޮ (ulѾYwio\>r[B^f:.m&̯U=rZȊFw5lMl58n|U Wa{5VЦTtDSWc bዷ;›~ΰ&nm{nA{:1qc\)@ҟ'?ZoQ>uC0v"""bq4LNkq{X1}1}b*J"0CÚ <ǎF# 61Sm.eg`M;0RtĸQ;*VZ"XEEbq3?ooys-dUL#69#1n ˇhy_䇇''6BĶ,^}2i  '|w{yQ`˽PfRR܁cw;]}Q@Q{Uf~owHc6 @@R$ e APD> ^MqQʆ,/l 0·Ob?1_#HaOK-^\ϟ\Í_q߼ kq ^rO\}Cgơ8_?=%Cpҁ^_ <|x#p!ᔣo:).<ÿu\rØԇ//O|> 3x1㖷+iP|#h ͇Ʋ"""Om^V2xvnvB(G/_N߼|M/~?=t/|9FeF֘q9x;yg;Ǝ.;_WtMqιV?R>-=}#?X5(_)ikG'ۢLa  R4uͨKAq[4bur+ڜ g֜aB/7ޞ.a-W19x1i믠C7^ychx0ѱɎؠyߣhgp[㓛ƳC^'KyW^]ԽwUGx3;UW ^h|NY8οߞ/_{[ Ρ8Ѽơ8喇qb3D-Kڿ^/-^@n&lǮ1~BDDDC+NGt^8v|q]㏾+^ͧupxs7FPC&HOz33/ !RJ֏2o>G2+[;!ש}@Z=3- fQ|^bush ( 2! 5 D6 tB4@f`&&$ A B& e)S;} St6L莥#(47=Ę-w^ƻ=@v3u|K3_xJ/Ɯ>:ldzi# G@Bi0y_E0V?Wm=#@6ovD:zy?Ow7GQ 1~캽Ͻ0چ\m/:@bܮjƂ*}MbƮ @ncx9+]ߕ ͎{-^SQWUW\ Hq{C|㢋qbL&b/O¨{ŝ}<\–hBvbB{ez<8;bå_gK/TGJoMw݁'/ıS'_gW?^{p ϒ{q<c#_^RG(LB@i\.D&':΢;^BwBoF#sJI(H!Q{o'/~18>g/m[_SE/ 4 X%hCcsr/aRkxNi۝_B1uɖcDرd̿}R8cl=}|,˼'N9l*N9l_TToW>Q0@BKEO>zO#e?l\w$""CtƏN= ˑH%}蝰&)-I9/v{ sNÝcN/k7iŽ2y2`m-'OAQ-^wkc7Ɨ >0wDQ67>z/.SrZ]5OaGߘ tyۄ▇C> vhh,}jƹySΫOk\/ө]巾 ௸{#~}ԂϽ ϷG?ƽ?}\2#=@ 5B YtueݓEwO=9d2!Y3: 5s*Za9R(87t *fʌ7r`*ĸ?͈avLJd,y &l:HM_x̗0yy۰PS#ǢaWsf"Uĵ=e?'^xayu"""tUW7?,SNEs\*(t,]5r F잉Q1J/ÒÄ q݋՛X.±ZO<7=Z%R[쇩x쐢L;7K@6cʡKdzDY]gށ[M@c#s6al5sϼzcϢ~qfcJ1vm?dwhIH]:?˴?'Lq_[)`Ԗo/wF)'m&D#6uG5|)d3!29LV77"}t IDATQdz3 6!XJ# &B)!+ H! i$]dCBǂhFj&?[\RxTYj/LG K:>*tfzno{=ێ6a/cP< ;`j@36Ut(@ux]ѿ{riKxֿGP7i&r(4,~/6.Ƕ'7Wh7oVYzVw@OF~z)d?I4t( PKaQM#zt le-MUѥ繺믇ٳfնf\rE8{ 9xYXouK/b #ahh:Ӵ Fǭބmn95r ca_B6\EKr7~\1cG! m2snkI2P3])!UhF6jd* fWHD e@2$`HH҆bS" ŢpLA3lu$5!1 ĥu&D3"O0uc$vڟ <kЀIo%Oz'f#R, 5#.ĩm>מ3Fes|a;;*K[?AGV~f+VK*78v: 2P*?Fy-F} 4t?]rB^s hmi%]@zކͷop`ϣmtl$*1f5~ s8ෛ܈n:XRƴ;cхf[\rEɌspE⦛oiӜ5KexvLvhUC_⩅_Qt-FҤޅX1kR;7э{.n%osF ph0a/1 ~wʵED!W D;Ka@kF|%@nF48 ̅* ?lG:&x'ljiAf(fw~2,%1vCO=?~Zî?/wu+)lqƓ-%on0fg\]R{1װϺ'>H]s36ƶ_\{98xR2>u"cw|+n8uzhF1zk@&y)}6T dst` A7>A`o A\2@ثP  SA1f(Mta9gwu6jm-ws ǁVZ?$Z [n| ۝k\ /F&57*8lKsiSwF }18-qń>Z"}矇?'xux!ٳq7c6a_muc} <H} Gp=H+NXl9Tn ɉ884+аڦbv;-מ}~;+/jѮ9/65Ѳf\օy&r!zQ)omBs^}9 3B ,ڐlp4kBۑf;, a H$D?') $ ˅f傲FZ9=4M)L]]z{ MEDDD^nzm̊<m1oq; \pkb5cvYװb}ƍ/<nէ[o]L??⾽.d @`Kht$ۯ23{}Jl*u_ >w8o1HXt֧SKyA8"CN< 7UsiˌB3 ) ҆]#|d(p/0GC-m{.{>3Ϛr'6F+6<#̿P\sM{E5XhB`>mDCȞ[Bp"&`=& hXJD"A"' ۱& NHB s6$FS̗i 8= ZLhC~ b[#"""pT(O"Hym87Hs0=\7H !Hs;^\KM  ր0C_x…AnJR7* k"zc䮋h_8_'N$LxDDDDB(Uo_"4S0! HGh$8 !G\{Ej` ywe!:]._Zqe8ðhѢNDDDDD@LL^wtY.c;\(]:{6J%DZov&x !d;}x!""""*$HR[h;B6 q[UMQ` T hT ;TYuonhQiBY^mL̙3N|.;o鿪DDDD44*J?B.`7 Z>EqA:~Rk…OPFMG1 h -u8hFe""""bZ?$P2@ Y[tΰJ}>6jb0nnnݥ0w޾1IJ վyD6gHY"DDD_t=͝MTy桹/HӘ7o.Z[>ycD,0l6˭\IW+N3gb@ ru J/PPܩ?6tSLV*zmܤlM2ֆnw}o'MMX{L"S&O;7QhnzW3sLk]4k*R*޷AVz+*6_pìYֶܯM{Tz$ l~`F 7~U)LU59r$62JWmGW\ }0)S . v66kL ݞODDDDD񚛛>d__˳o Q@6.KYox/`g6ڽQDDDDDD_4~C=گ[jϭSk+po߽)Ԅ0n """""psW_WfW[H\; 8MH%S}:dVtMm3ܗX8Ͻ r5_ե g?%D|c!Əoy󰠭 J?٫S JzOOwzsCz2H! ,<[6 3b)6D!٭ l_5[[7( ĮzL?Kq\0˶f;;;g """""jȱ®kBu'fg[em j0 Quq8 m5hK)ؘa@QBw'nr7kQŅU.( ~~ݝ>+Fa9˭g^}t3% vv?5?([A I) v>n_] L6 kxvenVq~1ځ2y5N@Pawmj>o9~\ ]B\4$vw>plr%!_k_Flsyukv˾JDDDDDT.o~6غݞmsǸvW5}@nB.].?&m,ݾ6nuօ6֗JDDDDDT.D! VY6ǝl q5?ozyO-n;+ B||ȵWrn_~uBu.?.mjQT&Dq~{r|T=nrj4,웡uQcPxݰkkZB/sZܼ\:~u?y\n*x ͖_>}ޗYwE H0fB 4`~7λro[. l{-wJ_PqyFDDDDD+2[mv~??V@\nZܚ ⶵqiݾ nW۳rm]~[eBaH$+V8W"DquãـΗ ٞݶ 2ǯ5^u׉oW~v5ffxDs-w.v뫒|b)VJitdزomw,lmCmh?۲`öDžj]Wۏ@|aխ-Gw߆A6.LDžf:}-Ojr9eRA7;-w0@m2P>[A0GoFQ`ֺ]λN~]G_DDDDD4}Rt5ܺSr#q}[[k[Y+R)L&5`FTJk*: n[y?Qvi?mywuþ67gV/pﷻ~_eϻ5%'wP\iފۦޗ'\Z>S٬׻~j Qeq5l l=i9@9v}}n춹'""""gJv\=n]7oyO_a٭ǭW_[sUF5Pܮ)N릦&twwT*3 WK)5a'D Lwl{pl a֥M@!ƶ.^nJqg"""""*W:~{r_51n(ϗ V>`Q9ƽ:LɤVժ f8lhsu@춹q#:~ {ۋ{q3Tj/."""""Z>˳?T^Oe>V ~PVru|~_#UU0nnn3gD": C-c٬=;oB7_̇ LG7 վww[z_*Јۿwk/>|Jzy]#N\[\=u2RJAG覦&N XUH)u./@æ˭}]noksG~nAm.-ݺuZzDDDDDreJ6umwkqrl-n_jJ)RJr9/e\;<̚5 mmm"Nt:ϟR꺺:t ~ ?}Xks6lǶKeujn˾JDDDDD4]~l}ײ; lGo~[[^QJ)r%J)=rH̙3ڪ[ZZ)S\P6p }I$(h:0|L">y/ǍGj]zK%!Dш:r_( q.wDDDDDvguy;cv-qn[\͟VIR* PaU.C"(cQC9$j%K4AT+KJX) Ծ)~8uښVݖθe8=~.j@i_5[wժYUWĵW[CΎK)Uww@kpBښ?8f$:JT&0OB\2e;) ~贡npUų,w߆ vvٯY:6~@q<~ݭѪ>}:`vKo'nn_r)qtJ.&\l6RSJ&Iϟ?_rئ91e=k,{el6*dCC RY)CҀu:d V57n=0prrf}[jҾ{w}ٯ6߸wq}v1\V-)e&fa}}}եa*P|~3Z\6d yEJPk-2a( qa5}v}UtEjsۈ?w_}rQe]m+Diu_4˝k+qkcޗuo"Ȅakll *Ʉ--- &)ST*={A]]vցRlV*D*6C+{ <].{δRK)uOOJ)s Ag=Cg͚%ܑA2 2LR2 CPJ|(Jp}=DDDDDD e)v>eJR* 0͆===akkkG(1JT>HO81\dFtuK644"dY;R, Na{h5 O:L&K)!f*.W{8;BرcEggt:-s\e+H$!7HܺIDATnj…:.Wsr7sĉEwwhoocǎdq9~&"""""/&7Ʊ#ƩTJ… ussJӺP 0[#뭷z{{ DDDDDDD ⺺: tZ7553gL(w V4Ǝn&:::ؠLDDDDDDԗt:I̙3Nuss cdۋ DDDDDDD}9s&B@nnn;[B8-bҢ` Gc2Q-{;):mdByJ>[.0}m`mU&[}""""""<[/ ' DDDDDDDDDDDDDD2IENDB`kraft-1.1/manual/images/en/context1.png000066400000000000000000000200051450127457600200710ustar00rootroot00000000000000PNG  IHDRr1 pHYs+IDATx^y\Te96/#. nnhݙY-~iݒvgyeZbwe.mvKk. . ÜE@*|m$++SOeee" fl@@"!b4[6YMy"z:/t / Truc4IJH\d_fD0n)gtn&,Όcx?\ѠRxx Ȃa<>\%Ú2ށ瞛ܹCt>~/ݷ++drH%'c_L rAoC!0܄z$&fjBacp)[SœiJa#f tY{lB2!0Hw4+[=/9) g&LN?`$2tʬiQU1ɋ (gȄ&lP}sD_ m}}^G@Ċoߝg(q!PJmoR=11Sճe:պnVf0sQz}>[+5X)M@]6ww^^ʞ6f)l]!,yYu{/BWѯ{Y<jNLY̼%:UJٳr#3oڷI`>?S",'v ~Z*hǟ2:ꑢ fY{`-0&LeGlX}8F6C .qq|-gjkfesf!Ŧkm 22n}v30%RO|;e"cmk[C8d̜INIm"2UjIawŮ W<9/{|?gw|S,;Uq򬶱l j>/{R OF9ܹx׬>d4@WYxYD4Rls^w̬WY7ZKr)3t*j%9dT!ppqw(-RPU7~q|vҍ Px> G[y\{mw)I)T,dɲ0M B<8eļ4E0fd]|yp[D'3 .@rkFϜcxuef9muZ 5oFc1 ~Ш0HcZ k1BKcPIB4D  ACB4D  ACB4D INUUf3\jN,|DII 'O .Bi߾=z#[UPC8s ͽ@Nn.G)5g6jT>UUIMM%+;N;MM&ceV7̎;ѣ;ͪ@dffڵkUlmmСgϞ%??-j?P/V]C@kQNG8x>{58 (MшŔU\ /It:2d:YFT@r[=tP2_zx uO^ 5͖XԊ+sss9yDտsyBY%@*Tٟ||c)f+:-L`H]HhGgBcCQg TU͍Ȼܹs9}~~hѢ,8::Il {'o:ub̎mN @"6e?8t#ORe(~Gp BQg $IBQ232TVFŋʕk%YOO?%wK c 2>}a+AWHv86)j \t4̊BiI YYW|[;;\]])++IprrN&Nة, $$"ʕ,Ԗأ G|(''Y=:5!IC&)) OOϪ"UطotڵAP}Na")9$lwemᐞvatqy*А2dY [[[ WFQTThٹ?L)%%lqsEB8+ cS$u (]lH?śqC&azG ooo8r$&&ₛ[GYǦEn΁,w4!(t 脫,ԡ7v]Q{{3>ب0[~N:+(BvVfEgϞma ؟sK,ӳgOH;y'ݼ9~;Ҽysˇ7PcPɪ@燯/TK4$Rhz\Hд!!h@"!!h@6P @E M܅N!!h@"!!h@"!!h48o\?jԟ}2ܵ/0 /WNxnyrĢ x` ǭՠ@'f4bMkx($=&69HIv<a/NhyeΙ9s Ռ8o]+ɟYNT /奉ф&|D7D‚1 +w(*#qXM@<8'{>|a{~)Πp>R,{޲ D0ШPm"f7ULl MW 5=1laO%^<â0ަD6^&ld.9ycH Y19_~5 Ǎ6ѨHDF2$ EWBjɆ/V' ^._ЈQ W)o5 *CogIr{gڝ&8v=#a=T r9x2CFzѝn Hycg,WM{ 2K2gVx#*HZE%En\Rw1P)00̱lFERu>>;,KxX9bJ3~eIt6v2H|_}ϞVd ?%P:~lfN39Ř 9y<uǼAVk۞ y|ύɑ[0/E":IzV;ʬam0"/fFHnԔl_$!n6=x~zֿ1B"!!h@"!!h@"!!h@7'Mr|K@P0Gw`ΕIn ԘlJ\|x#?..!AH]7i/lfg` n-W2.(i[ؘև?-Hv {r,-wfEGuTArU3ǷB0[ųP)dBot8v ٷeNSPv;pu(rMrJN9.aMC)ԋ\ۏG8t9Π;ٻ3q$8_7!{~}t:Pk*ʋxrMrfy>n!+6^HF +T2.)y!!*n' g;^|St瑨IjTƆ\ӨPMM`xa/<@'ȾDwMdg{4j<ņ%820w t 0wCtB )W.Чz=#D&Q[+fgo3sy܎o&FB }fDU@vtEΏq\/l .dٚ;x5IrK"*@"!!h@"!!h@"!!h@Vd2DEQ`!&ɲp:ĉ'Yb9+V,ɓ,ZeN9af_|:֭c櫯鉗'3_}uYv&1qiz=j$L Ÿ́`ܴHS> ӄ:TK~ϡ~oXּ֋b7,bx׼C >$6^p*ovpե~wJ뻊*-*F|SOm8\ă==^ox .O< "[Z%n}6 t{h6?ۃ6 g8^:30ߥLCqc\Jyf Ǣw>A:6⭙s)WG[j&U|e7O+_$#qu%YBQzW5j5lqsFAcKޠOhZi/*ZNR6iۭ^1RZZJI&3ר7N.]·G 0Ptg* c0x32{OBvq9'cfPUTO$.3$rֺ(#a}_Hg(^7i N#YY%=ʆф2OwQ;0KNLz_`jöB<8eļ4tcxrp.<Iď9\fG'{8аA ׿qH+j:IN*i!v&2HB4D  ACB4D  ACB4D  Ad6#%%Ν;T~ngGnn.ƍcܸqg(=Zz8[~ٿPdu RRRGף -M>m1Z@z)㪟X{t j(nD QTX^&zjs$EIξtMg{h|$db| zʲ)=_2fwcg(Qlqi}R *%٩:|&qyl(D^Z" qȌ:h.6Spr/N6wX/Z?FjI>N^p/!a]pS 9t)Qmqiݕ>=bS~.xq9RP"5ûko:۞&!*~Pì7ՁTL' ^gٿu?Ig[F;jlDvDGy_NlA} K@0y}+iEO ߫=a} "2^##@bC߇|I[Ym;ǒEY{}#(dNTfLr35=2^y֝]ײk\hg1 )mўHlh6!g:?/c %kY/P!?Ѝ`ʢx2M)sL==phskZ_ E +;o91b׼c'B)eǿY~IY=0at 'atKTfNC'ג\bˁryQN_3m1ebeywg!-`<^g5||teZհ>]Fޘ-?bCFVLiƗdMFA=mmR~ٺCrYܳ| _د&_._(~ T @3˗1U{5|+ɡ|ޫm8nqfƄC0؀m! S@MuSݾ-%e'6rE$co3$=g o[ƫ!)#';;9'8w7 *S Jc;Z-'UBnV.%>ѨUe%6QX ^^bH3.UI:dEA4@9[X["nR  wA<,"U[PYrS 7wjoVk]45Cb!uJt}"Y1H8>h;FP( s_o#z;|0"Z 尓7 ID/G]zԏ-^/Hng}5:wkc {Y~h[ þT|wSƭ+wthk5N?_1n}1cvz1550$uk'@%@'K2EKJ!'}2^H= ; ^I ~*OC&$DUnQͼ%wӣX^*V'"{$%.DN,@1, 2Voe$qT  8PXaCulY]/%\(<{,  BP"A(B!1NhB8]:S|MY2BQ"A(v.O_B֫*)j-7n\RF#hҶI 1DS +@PN9Wʁv5aPD,1a 7m/ @|_$˸A;Tc z3Wvknh" "ˮV|a]]f۞6NsU_Q=>μ2^gwM*m. ֮xTFjccQ)U ŤyhZDR2Kr\߲,DM, Hj]-WUF"?s>s6XB4{qR J~v"WAȾ~X*J|l 9}"oHYg-gGLٔ˳B+_Sqg<:l(C'}ȑ aìGvz /@ƾqN_w "xk|SO^>q[4 g37vzwa%r`;_g 7b3vNPOFuXe<;>}0ń^mj YbhV#rSBI#:UJ./qX?Z/Y{i7_#..fXŪhq胩r=/~M+ߢL2)ʔdfnl#\<%܌~{96e@ __ %;c/dY;gfiH,ϏhH܀X%w$|rE.Iϡ=)Zό' \?$O/¥z=P j4&%vϻ$.{- jy] _Ŋ31;w8ϗ+Ή dBzcE& ޑ͛9V~AߋIS~Ms(mvXKc#FrmtkcntH(BaS5Đݬ\ x'+Їn`Gܟ"H$&3|--Sɫ2!^6Czt!ec/Ɂ_KqZVoT:Fڹ((CVqA?q0jJ+-J(NςU)P n_+TBWAlȀ!X.XM蠓8UP& XtyHg Sk3Sl/s,em>JlKשhŒ&ғKvna{s+K| , +"Tq%r<1'P[.5F |#!dSՙ A~! 6L7f 8 [G黣B2ЮW.0-::1*KHx׈@4Ç/ elO[_~_.eY\1c*: 2C0w!>dd:^tZZ˔FhDZ Xb(=or| W# қ!;3yzbf=C$ǎSz9" B.n,D!L(ۆFiE53ѿK"F}Rk͐tC.xP]κsêj=I}y-7Oɟn>@7il  =&H6S%LmA(B!E !(PAB BP"A(B!.CKx 9 7Ҳ$8l%g)x_BJx=drS8OW5'珣әLB g+|\p1m|Zs~-b΂Ul?r{0&o< Sqx- Mt"MnŝcTx"r)P !eDP5RO^)ʲj)| ?Mls? W\ fŞd}&/1s!]Me=|l}!%?L} Ys`w쵇62 ^҇$odY]^tid4"]r|Ul5m|1Ys>{%KTķϝk5-oa A)X:%MUI|V_ˋta/{ΥѻWK̸c:PyWVAMj8ͮ ,~Y2&W7iQnA|l3.Mkݯ}%Y&̏ƣ_=gi!k)SRv2sv*zL:OO/_|͖ 2^WHg?`'dnZ?6ax(W/n1hЄZ:Ie%٠lbW֜mUX SFqeﻒM~)5s?pCk =;P_ہ;F$.;ҬOn%*nZ/,ThA׈.K#' -"Ʀ/!dS42s\`Hyҁ3$QCeP!Bld EFCGlLyNMVD**3Yyy_3E.E8E%*zBA$d x~'MG " 9=b,CR@dk!1ċ*"`C" ˜f"Y %vO2|HTFFU<[  Wv3m϶> {9ID宇؛|Kmj}=)/iނ$jeJ?еU] ĘMEK@p+kCD$ &p{RuPGkikAPU eZ2)\4//\S_HHp|mg;S #Csi m͂o!-Bh{dlMғp1Įhyl)n+zoIjBSSm~5G$@~1?#=]ғV=hItb]ɣVFoNeǾL*[ʖU^{[s4YlCv~uZԏ8?BQ5eC#;{"w}ԜAiްzx.sjGtg? 8.ĺwqZDc5sz;6i^N9puQE0`jrZ:ւ5"dQIzN Ȓ>*pQ S.QB BEx0\QXP(Dž6~i$YnH 񗦿sؽ2MIENDB`kraft-1.1/manual/images/en/create_new_doc.png000066400000000000000000001055661450127457600213050ustar00rootroot00000000000000PNG  IHDR|s+1CI pHYs+ IDATx^wXn "JSPn.{^޻b6@P@@zF'BqNfggf3aa6KU`LAA_C$!H%BQKQaIkE|^AA~xFAA~:IJ8&AAߍF32R|Vd)˧6ZYIq   d,e&@Q!R a\$A`q&=RS)”D,"L0+PTf |nAApFO$BNk+v(-;QAAJ.! UcÁ"")(41vŅB  ?t)Pa-2Ea8䄒$jjF?EA,/Kbr^p$Fv8QD{EUA?59}eٕxB> h:cr2T(kWBJ>~ Kxp:dQlrzI拜2~yq2 E.#o;.?' `lSA~d)/+&Ԟ;q~}HD~ßa;Hol73NtS5?I3oPXiYѯ ۰/<}p{gKցno]ޕqŸ?W`!Isꕤ䍛6D"`˗.155LHj8Xa&E3X*jq-,>")IV?7DKKsmN:sv--M|ȟSi?j*??i3~UQ][[c4w;K걭kj$gJ(B" ^*|yACv勺ϲu܇7#z\E[4.`,VvBHXB~#.~DRRR+իV]u99q# fZR H *~ &PTyYiyYrK]T^#UTjHMD,OxnS|=v4;A/购oTLD +xؙiJGtkD/IyybK&t<2L҃o=FH,H~}إ5xhQV ~X&zԎԽ0]T(~ÓGRzG#-4ieyN>̱[3vٲY$(vypAu3OFIB陇kiNzx2\Hz-P}Vh{ }PqȌ1.VawmK;l_+,Q&H '\m/|%i=hpWs-(=鳁 дlހ ř:C1˥n=`ӢI^tk q𮭴JS^sC> Эk^K3X /e\9u|%7۸;`JfN1~sr='u}vS,٦=i7X*NvZܷعvFFW\5BD"BI;牲J5 Ees J %F\XOhga.I0 !k#[ ]vRtIn9^{2P%ܘǟMaz 6}v&ܾ;YT &,~wӬgd!zB q66Lr캅C6>ոZyEo4kGՀekz.L{͙i kYtSxks;YB Ҷ%-*ҵ0W{P{S?uͻBUq䯍Ӷ)U?^Zg6= .%neYޥ vÿ76nߒݑ~O.Z;X7>)RQiCXv,Y~+OIy,8ϻS1_F.{6=[7/2ا/j_1ʹ?ҪeUŬOmVw|tcXiXB?\^"]fm^^|Fhബ&)/W0dN8!D2eCs$R1Ȼyw!#pU /N>M)n]9wTyƓ1:̋HI)DFeiZee@wZ)E$2FC~-%*Hs4j/??#"*M~ެK˄Hol;D}miFfvnSmhܲYbd, Sw0A'(tjXvqy0Yg'{7>@gwtv2{}v)!)fWPa3(4)<&_Y`R1*:Z @wC9RtuUj5/4;A%mL#$HʧgbX"w5$JZ+`e0eN8eZD89:%|"QPbPsn ;OhpTgN8+ R9Ы'I:O<QԱ]|̥ I(UBLގm4It$jReBQyeHp hp>8E(bJ[(u(!VcHf2ڷt\XyTw\I6&rU#p5u5(* q/:&>rQ-5je *oH,/.$ a" ʟȩv]zduC?4 Ѻǣj<5 \fc UMfP <v*CC̬,000Xz՚5B|iTUPkQ20kk`;+e;wc*SsdA8?6;ܡK;ɵov(>#{a;c-c ܠ-eU,,(Ov:Ô&,K^*(btyd|j_$oeS cپ$lOVyvg[ ??U%,H83Gƭ8QXqӌ~&-9Q@Z(" H$I 0 F l;;*VhҊ+Ulӈgr@s3oa ϔ 3+)իzðkW.˧/l\ZbyE]fի VX6BӨ))Fð_`QpH@(!! ,C(Dë}cݜP`q[ҭdaPv 0is[UEVHlԩy+.(FV;PSUP5lլJ*)JMSqpn(!d曗 Up%m4qܧ]?d ?{)NLVi**,V32}Ut8[ȇT7/M}tРӏh"5-muY.5-jLyK3p!qz-m_߽{OQ=KBdU]?DGNR_ݞ+ʺ$~n:‰ϷN\0mĶ~EeOC>Cq਋8=No{ߛҊK<MAkڹ[gc'7/4ښTIڛG_|LUwhŔYvACjW&q؅w !a{[FAW.sb:4 7Y%:*V'#Œ/\; jl_$8`Rϝt'J quC{WۢvA|rtvT@3n}!*VA %IFOi8R# yq>X:^FrL4dq05{.2ܬ)R pޛ.,w/ŊiUգ4=΍ⲋpv33{ ]w\BOyIozKi->-pȏ":EG~Mo~j1Yn?~%_,m:wٵv=zA?PgL\ /xucGդVX7߹w\3بX"A-r^ @$ ^č`I sB|*:\жeU73K"ݎ4Ӓ x~ΆiߖX߽xt\iS(Q|U=Ig\aM%X"JsFGRf$,ỤV%}2~HϸIS*e[ yv6e'EGEŇf^m={!OlrKC> @SYȭA@4T(05:hV1s卯%CЃo<:vIpCdTaƗ LYE*GEE15\yO=@tc!Z,,۔GE J(0ycU ,suiJƌA?o pDVt4Ҳg֊9o~rԷuwUx]fyFtoC+4펞^F w!]kL?j][c>I-{vGѽ/zȳlJS266kF I!ne[܂iͯ%qW^܄ku4.0( ^"A73o`ftȯY0@w]`2ꆽ!۹{K3?}ETT2ޡq%@ױu0~x _𻂮Dʰ0W^><Ű <rsD޼ͭMo1i&]FZk94c3S,L˒+W)LӜc75uwr{8an/$ZV*:n#=+jx[IO (L˼ccO%I~R͕ ^^"sdHʯݒ!<9me'&+ٿ;ʹ3M壒qسln˷hfX4/1/;x׷z n_ wIWcO}彸fvϺvAŁ%Nwuz+Nڶ"ފ*0}G'1`FmWT9%s3s psNRe!iP@kEZiӜհO>>>ރ>QdaZj%2#S>IyNclSط"H$ Xۚ, */+ a$`JW9yӀG( #Ќ1wE S˫Jv]u,,tq@ \cͱM#l@&\߻dTse K#ȼǫVtP7H<-9_'#"sHz{+h̪ y qCF ) gX׬qV,Jt[F rrI,ry PTڶ5 (i\DTq7F*`T7EOi$`ZUR\J` åp#C44JOȤTG`Ui8`L gXE$ TAVN @IU-K(U WFm@T͖nӰǬ7]1γFfZ4yM`Id@WD}ԣʓb\*ׯ9;v7=s>\2c@!w,;A`܉g@\ 9gA4nM׳ǣK? IRZ'g' FPXI؛we cZ)weM@FV')%(xӉ.Sd WU0:&? ðp(R@3tz75X֪!6}viC!yO]ޭ Avz[)SuREo϶Z۽E 8+S ҄~L*ި ^JT m^Ѝ쒏gWc>zgѶ^U0F;j}g39$`Vv U4J\"NxhLͰE#4٥+qnw o8q9 Fxk萿cLֶMm<,Kyh`):⌷]M'5tS)jM/Oz(0fӝ%qih30?\;=Tϵ'԰q53Vŋ2"(eZ>oS_% gOp0R!DYq1\>8X]8( FasWԂfn;mE;/7݇7o[S4QʍwrjuJ*ݾ6KFxzA"BUwCWգb.{yUu h)C'N} mGj#s]T6kڌ\qU+LVV4(AWb.\6ZK'y$03xÀw&Y9Ngl62O4- O\q+,ՙ6Z62\r ,?c[A@7I]ۼy>:8@k_ukԭ, ۊu0JZYܵ0헺h#)MX~ɽsBo/$aʖ#9eACioވ6Tm=mZN g(qu3q٘V68Ќ *h`pԶװ9;.\;<^10b5_[3a+0Uͻ YtԆU(Ywz]Z)iL-hx!Fͤ3Y6$ݗk8kc Ǚ,-l"LKL].~n~=L8,&ٺv^cWu~kfw?wI l]S[1 &he;}NZ,ժMKF<\#f5Vg1h /[}lـ9}[)qcǙW~ A?3i_= z. AE s S/k˷5 ۮ=.fȿ*LN[% HzA?xA[G+ussPSIډ$`*v:Ad(" )VRH[Sf\  ȿok2r%$CEy^C s2l;b 1("f33'#A  HAAAA  DPEA&. 4tA  M]Ai"(" HAAAA  DPEA&. 4tA  M]Ai"Mtůy 9Kȧw#\*_o_/YTAn~M}RK̸.^72XŁQ]c׭ *ٰSi!-}{zOڸVvr'_ DޛFvqv=h<||:w"Cr8HiG )u=.P`i(lÿZ?ʟ4c1H&mwjp83*ߤCnظ>}^B$?8r=v#Wzc~_wX~Acɀ ?Rǯ5QSwsDvfe{d2T)3LO 70w1UehjT}wjsJC,jZcS}MzCCًkҜ,UY<]q8݈2\ͤy,){_f=\wgYh@DpeXԾaXԫ?攱|qJKY3..7b7pμ~;,׶hx[VcV ^t׼RREk'ؔn_i K ŝ&vu9 ~W :CkH'W|ʻ"cש]uMurp TX couW!g;yn o1 7^%[j1Jvyb!Msڒg[}oQsn>{n)kQ~iLR}_k0W[չ;&ͰB\~آ%#:bŝM-f.8k (TؓS`Hf=;H`,O)j;D[a([խ2\|]c7iUC*mwE]aڕ>w'[J15Lz0ۅo7[{Ua.>{}7_0͜ѢZ8vn,PWm=Qlh$;KS<35{7ջDžZ# qݯ´u6jya Դpۃ)0.uV|XRHX]5z|)I{?pmk}Ҿ{DCCW?}:{3By[ E{κ+'>Z~x{@'ϥ#|!?xy},:/>]a=l2_6Cۍ޶&Di;ٵiHg@g5\?YnS}x_Ύwv645&p̵w_̯(0?x\ ?x[C mͭ>I yqf9vu#K$r7veqxCs ]on7J:_({`1 2.r0F xQlG"A5=LYQa{^ g:\<-\|yb~'I< +d^[oL;g?s̷;Y!uE?ЮSodoNuz0Z oH|>د]{5OEy';of,WO{£ {' yϷ+ʌo{̼-qޙR_hi7By̠m~6~Յn?vH H=?ûGyB7h]K[l—Fhsy"~vɉ]KxqF{=&G ʍ X0XO(w5iﳸ\ncm|r%k}y;|.y?D kt\wݭuK3qDL<+rޅ%p]fHw| ?xm/煏BQY־;?EavnV<Baq}v HT.6 k[&^e _x{t۲GºBFWF^Bytt2"/ 4(Ӊ\?51Ρ˒\C?qB7G&;>ξ˕O,צCߵ3gw(Azƻ21F_/S:Oq1bјlz,Y LugCZ.xy|?:(zh[ T-t$SX YzoZNg7&L~-8(9zѠ]ѩ$;[@4#pLe߾^~%hY80tvo]G ݦ60D;IKXK>S_woKHOޞfvļ wbƁix?i4:iQQ;ph{aO?01 Ô:2mze4trh).kpU Bs6E_K[{M5Q ˦fo>?㗇(I9٥Tf$|8  1ͼX* uunJ$?O>4(9dۇ,(UROXkj/$|!h40(qeuuʿƮ Ӏ$IY7 !%$˫ԵԿQ$n4zu:tAq4RLIm1QQK[PT@uOY곳|\@p /LǕ55ZUc(_3K0+%\{Gw,đwK|(II1n6Uk@zL`8 ت.8FQD6` y| uQJѬO1(_zw@R[ð*=1٤˂\ЌvVJu[۝Ʃhs&hjU&c:"1QedwTGd>/926x`E<mS:T_{ٕv:6kkC持9EUbX՝|?H>V Mt*HO1p-]-I,X S:80)U+8E_=%LCKpq:$I;կJtus9ソA/Mr 77xW:)PgZ LK_Պr(oZ'/UlsǼ+bW}̀rTKf^WBd^nh8ijjj'Y1o& DdhڽW__h#{fVe=mzѮ0˲h+h2WB 1l*DevݻkeGL93fLlնի1twߗ1*4rotcQs E"uL^  ,e0* nN k}4\Nm*&΍oUEV2gi-RQrniP02j+Kv[=#(_@ (p8L\]K`U[n7j7ծ|RM'w~z'βʵC eiN%Xl浝5Z_{}݂E{\P*Wj7fVohj*GE#Tia5Ԅ9yҊt \2Mv\1X&SU TB5S=2:weL}-,%y"ڴ5cvXPf) @d~͕]ĵtN|qR! @q2K(Z= /.( 9KZ5S\#ReBaE3E Ygfv|0pc7_K˓Uĭlo'M2R>GdJ@^H>׏Cىa\10=&ֲ \'| 5Bv|B!U١7Bt=ZU-3޸IH!;}Vn4;O84 _&q_Ƭ!UZZ@B~WQ^ϱE_ްj̞(o uө߹;/xյkwt=Cjg0(vu>:}+)?MwwF/ˍ)uQt \[6M\dIf1W.Gvo+ԨF~wWTI⭋/(o['fQ 9~)̳ިa\k+Y̋QD04ZiƒJ$@ۭJvn] N\- ,Iʐ}U+hDBĨ\հ*! \ۭoě{d;:?g-cѮ[ڋ7) ".h!z;o/g/|@8pS+.(43P)?UONCDOPH!;gA9wDoWǮ^_iپȅьm\kjn.ʮZm0B.z30n6f c=9X}?Ux3&x aq^h?f܌WFqf|X5#:Towhkߙ!;ka Xѧt._-~sG>5p3EY,Q'X>vX.#(h[imO.89Xl;1mN:WYHVBaUt:gq:M:0 ]>j􄕏zuR׍5np N5;cʲ߽.jV2n2aiǙ1{H>e0`*wM}̯-1l`QnQT'Li)AFrqq=~XvIKSꬋ`{GTmgNՠ0~3(zb@77w1 }Xc5{݊i->J.}Vנ*K~qg-gƊ,٣- LЪv$)өV3X]fm`Vof_SmQ1`Z߶CԦ.y?}.uz z?G;2!߭^M5(Jx>6}OLT#,&B;9jmRQ-.Zp{}]8Ϟ}E/ 9b7Ķku{ę(tZ DD=dH3q9m|҈ZZ;ŦeYA߇[2f{hpcV   tA  M]Ai"(" HAAAA  DPEA&. 4tA  M]Ai"(F/OB&5es|: }=蒢 IDAT;;uswwsJ4||:OnRO{uqx!YZ$ ^5tJCz ?NBJ>ȄÝ#7  A*oҌiw_}m:>?ueƿ~!URv5z ?Ny R)0tA5M[woHg(98U$<틮&D>JYgcaY7>}&Y8»ǀ TiԾ!>1kϾSpj{>OX$N,vwKQ_^p+暑]]<,$bOs"V>aNv#M~ U{k$?n=G,8*[d{d‡ʠF|9UneLr˽Ec% Lps8s߳ZKgg 9`–{ TQ-Sytus_#O^w7#Ĥ&)Vr.n^VFYRA|/ BߥZmȩ$`tfIBJ3e+>λ܁Dҙk^wpf497/79:zׂvqS> ݾ6Ukn;ubڕ=}fʲ=/tVÚ"c6w)j&?]ĴvxOX~?C{' yEK>9٣f+n9:i@]1OӻiPij׭ _ͣ%2=&PEo?2Ĭ٫.<>eg1'ovqyO{+,9a|ae m\0#k\ch[vǎ oC=Ŷȼf+#Mj5SdhJ,z߆ ?w^1A!Cma Cz1ڼ[d;k3S2_ͽ ~Ŵio#g{cZ[!6t8:dg H2i@бt`w^\jĂZ,p7qӯA,~;K1kiW,Z)@װ5ډ0oMg?t@)𙸻oVA [G3[W(1) U1K|,[IiG<#:b˾}m_J>R8i\V Xi&vc2=Uh,"KIf H~Lc)!O@|}P#On3?{WkV'TV, !_H^9q SQcWMI@azJRNv)ZF͕`ͤ%cne6VǗjY} {JQh O qQd,']^`hb|ny\JDYUt oa gb͓ɢLۓztNeM".uSPs`lڍ\nNjk&NCN&FV𫚧#c(@$^s"ۈ^~S|lGeX"RS0زm˫v@ FI&OyeD^Py\#OqOUiWQVG.1F鯟GHy{l-#>mЦ}~UfU>}OgقΞmGy;[b?'ۿOa|[nH, 7ƪnn_< Cv۳ЧP4vnB~xuwCܾTU}oϡPZ!t+>j)0 &]5A B@MjP. t &x"Ui#>zZP0zjM!tKЇ+/gnnZPիUŪu`xIKKCBQYXXH$ -uxPni 7xK! /L:H\oj҆2'xz@|Zqݼ<<+>^8G ϶Á*y=]>6"h˭%iՄOVS i6phuW}oP>^ٵv[gڦUuۧc9"?\o-z6vDOaHܵvySX(ȽC)>bww;ݻ{Z_/W7?\ I;y{tlHzsQ#˚gt?ۻI9oX@[(2jw$]N_Y;vv@d?:6xa`Vk&?dy饙wpF-ƝHV] IѣoӻV\O2O^;&-V]fԽ7gWZF6~wC u7o"xpœ},[:xx\@ޯ>k%zo!ö:g)<Lu2`;_BDÇ [lYhhhХ˖ 6L DC}YjT(Lj= [wkŜ>~+NMu0R[eXTZFHQc"ǎ>E SݩETG _l^^v4r+'"6ܻ1֮Gh%k{ĠG2"Sq3e4jfkIu>-Be7uòzu:~qVlg˧$2Fy_3y ޜ ӭiZw/('""AqjDZ*/nݺGʝ=jTݺuN P2骐&$C+ufM-LeOxEB\a՜|;c "a8̃eYyba["""^!ԒDꚘhge+`9EGtl{Ҕ;CjsdGD~jhe>NLIMxiOr-P |Pl D7u%OLH5y'>{D7Ay{i֫erĘ/'G~666F/]l("ZlQ666K[+4J>.$x\m Abd 1BS]50KSO,<C%%d]%%"") t޽iD  EhhDUOstxtX"Fkjii[^ïj1#X ˬp]ʕr(΅[zCkk[:80(w6ߖMQg͚MDӦMk>.M1Y 2ՀѨ]ĥ­UmҬ* ٺN̘o8ְ\YwD|cAOâ_5un՞A/S8".#&YD!]LFlh{.[ζȽuÜqpӣ{FˈKyɵȶuԣ:>]כ-\ZP]JXVJVia\iY3Fnbν3M-sZcDĚ{w=ιʈiƻrLa٘C.km22d֤Jg7ֿmȡ뤵ZmoɇdȬJ}7~>Օ|-ٯm u;H1:el:[\3bcC7@r~}\*Nczou],n_'xBBBTKҥKeʔQi"=\*)blܮO9=Od/RÇo8m[Ŕ3D P$xBWX>kOQ-%B-!P`A7s?tK! /L6[oP.`xDQQF|wҦvZO>}<\`bUU+M͂B100Svjjj@45btv3n)$q(p# t &]5A B@MF.I$tuujT8%o [ڼxB "#ž?imZP<8/mRҐdiiZ Pl]5A B@M3w{UK3.tݻ?iI'#w@!ܻw%O4A|ODʠmРIΟ. B i6++TK܉,ArojoߴW!6}]e(yt:\Z_6D*dh Z )3ۯkƍm{q?'R3gHG{;Ǝݧ}wCZ׮U˦W9V_Z1cM}/ ~'SK۶q[gI?\/6iвaiQ l԰}.=(BIZdet$=kO ]""#\vڹOncp}ߘaZrm犓rb"oUkW_t^7DꎌYBiۙ{/\~|K'nzYj40C"PaT>Qn)qOo:͛GۄΛ=\AEc\vEtD{A׭T+YX~m.eݩ82/ͣUK_ewJ2/ձ{C]~dUu#G|rؖSv?k=x8p-\=;ooӻV\O2O^{(ϽAOt kMylʖ)V~q'gz9ǣ9""G2.;x; է==0MOui"M3#V=v*rחm!hv;c&ڊc=>urߌL#ƠrF ҕZ|44/>#ήuӦf)NesCc'q8Rט/ҥ3jc$8I>Է{jV:r rbOӠqo_ӵj| רxCA(Jn eR3g( VlɯsL?:u6e;KmafZsCPk!F ;T1Nu&Q'\<~Ͳ{y!#0nN-ENaνkkP!}DюBDIm;smfef 8#ס8٣{]} #5j2pgট͛97ocCy#vUA8t1uF*ODv"bH`j߯[>Nl|ҍʌB!.]!f2"%$i[ħK2tאiK$PbDFFZ\B\Yqi"!.ٰjNyrCc#a8+X9'..6Nu.""RA-IODI !G^߽yx@'Y8*Rbb?^\ 'e4V"{u7j +.v EjĽ#&w=▦yW`onX"b"̧zn%""^.ؤMd]e MMII;K( M+>.$x\m Abd 1BS]50KSO7 KD ;u Gw'uD <^O}?sʳWmlf.=IDyi[^ïj{ye0jM<ʪ %+׸[Wu?4;Ĭcljj2VG6u3(R".16^N$ ".!:VaP0oquV_klB_PZŨ$T[LDWoT1bGXpRʒ/c8,"k٦L^еBy㈈ɦ:ŏؿ .=}ޭ9dQǧ$*K ;I[&ڤYUu8q1/&pa]4m IDATZ/>Hǂ{wqXSM_Y2#2bŸEdĆ̻g"j6 xKZfB%|]"ұՒ=wEIXc W8pՙXliR ĚPbN 2H̺5ts#v䜉mGo8iXAb~h{u?/WmQ wdǂΞjZޣ٘C.km22d֤J/o]ӝoQb^u]|I9C@ 懏'- ӪU+"]@#.,,jhh B8d߼JKG! B"Pȥ‡{tmfׅ$BmFѫ=(VnPYLF?py8N&eddH霌oeS^$ Bu^}1qvT+B} !8$., P#bH$T[WNCy.tP:]*0 gZZZEB@MjPOJvK7[trȟXk+TKM>R?G.~^eonӯȈcvQe>?0ן$摍O>2Qߝ1 ]]ZϽ.|MNKU'4ӻۺ:P_^Y>ֿ!Y)YWSk{VVcdg K]s߅Qɰ<,x'ƻw]\́NvGdÛ񶠣ׯ#}5Ox}AqIkl6Nv|+{IS8܄:~>)>*S 5U+k"]Fúz@(<[ (V6yGOvY ɽ[,4)Wj\j2D\̹ל>V~so淵;}d[Y[u/JspjW)k`ߚaڻ0ձ?vhԾE1;JO>2iܶ{7whlxH_oO}>-mwmٹ8""٧]3V}"OfT^^ndҳÒvYWwjެGq'+Oiιeq ڼS'D$ :p mhĥ]҈O >ks;{;.=T}(T׊OcBw/Gg#W_H_;[S;G~ _}=VPƣ]~iޱEi_|6"N.W]=b,iԸmamj±xK͛Nx~>\9zv㱔;uvttkު_缋 :{yo ֓S)(i^ܺ)7.?ֻ Wx">@]UѶ }|<ܽt;aAsމ>5oeD\M{xyzì){eo]}=:Me#y2bI૬_8͉#zvsos zvx8{Ͻ&ol߭[ g({!4wKum M] k{ǚ \V2[ nc7N][ڽogS=zzzz,կU<קߦ" '۽X8zDCa~p_k]'*3巏>'iZ?C9zک-?,_}OeC+; B6$m]?늦ʮ@^rjmE#8"Ƭ^sk$F%ZՌ!ƚNp$GD$`7#84婽6|9`b嫋ֆQƝ#g?i<ȥ/v}h+Z-;FTi>l୊mY HhQw̦g^></1yS7Opѫ栠=/8 .[ԧs'5}y픔3?_vK!{VE}8xM+Wo}wc2n_ϝ%j/wXV5y|A:QK۹t~zZOw j W^+:e{:<}9cwcMiY-Tܞ.DDOoy~e_?~ѳv 7q+DĘTcAuAjS׼krj#lugO]~.=[k[rI>s|w{8f#gm7zϱLwbgOXss+ⵌAT1PuJ۾Kz5wlvI[;VkȩV\TVlտ]4-]r%7j9vVcIôA. U6h~ɸv4XzP,+׵] Wk%}:n!Y֫+r\X ]:79w6;HX֩1͚XG*s1rݳF>,y^6b4~(\k%L:wRü*h1>fNH剈]űv޶&aܼ,""#yh`P_ H }H;.'>qQ, bM6o͒Y3kYL3Kͫwhb;UˉկTYyS5[__Z17j4m1];7qµdwl:7)Hh۱{}CN巿=LۙiqjrHܩ cɧ!2ձ+V>|Rz"u'VGoUoڈ ;Ѻϓ1:= Hr)~m+-zT=}7ϺpG/ tXHաΗ |,t//dȸiOӁ!z}k-1vG/bDO82ȩ]佨 eRK=*Xc3Mg4,t'"RdfͲ[J8mBVx>.9:F˿ .SPVyRAD\ltly\R($ryZT\߽.(⤜n[ GӑSaÿ7ߥ1&G\"kdfru+r&-'"VHyư,ˊ o~+ yR$U3NuL8.U)p׿~g ;,,?^ٺv癧rV%qBfh:޶v]?agE m8|]>9Z|zAQBu6H|;A-}J,8:U|75+Y]c"[q񙷗voxY&.'"b ~c691 ̲50=KIp杧C3Y!verɹ$yc801,\OK(oU%buMLf,lc8iց>WH$_Od*NyY#6 &mE#=;/Wꛚ ?F<"#L|XzZczecٰFzn-}CEySmIo,]XYy k`PyIr,߽VVG6u :""y4}nahY ZzV#ߖB+iaч?8̲Gcj׼|rw"2iN#"-5a^*kZjcTx4 \{r~Y [1WihW;4e rƳrM̽c: M uO=t2'O9wfKO4cb9}#565H3b>MMt);[Lݰuֿ׏5<0Ykb?#ħ&~J5oа̫3ެRr:0FwPncЙgVuT՗^d^ۻn76nj­Ƨ2Ljؔ1>8mV*XC1[~lþTq7o`ںuD=S0^Ngƿx*)&2FIUHP۷ڍ +CޥsDEI^6Ak6߈䉗' };`b+b/E>uݝ[Cħ'ej1/yq/m QA\JO*Z533.͐٠;k"j(䮠ws &]5A B@MjP. t &]5)c 㸨hLZQJ,/V\. KKYUrBZGH[TzZ#_](hjE)0X,V#z|X|9ss ՊR****Exjm|axF&iii?ɗP.W{KIMEB^Pkx`ԯW6;y"BDhhPSY[C6Oǯmǯ(\8پۑrQy'ytTwN3WnI瞋KkVӱfy)gΔfr|vMǞmh'.)p :\t1-fLX5v""ooēIi2>#w`IvyV}xģHf9_&ORS2[wcsW L?rs/RF5NVۜuqM,%e{ቚe6iR#'M*25aWg̡aڋQR"ņ0eܴ~ 3ѧ.szwU+qK庾)D̛ ;y.%""N;JdDskzi*W ʌ|pS/z-oXH]}=JWTozdeeq/2&Fr<+`9 qIV&Ok%J>^&PyzIeq'RsքE_)1&e:2#?\ҺV1"r#yݴзTaKǗ_H3D* UlX[՝glgnr?CY!mPx >:C'wdZ7 ZzBəU.'LĹK?w:TSN1Wد/N#ih{wN}iɢ) ܛ~1YH']fVll(z܃\?˗F%TDX-K:֯df/g$DD t8x.#::QAWRS{H:D>I_3s}jSO{Ʀ<1zi$h[u USVز 5yCHXtjffZ‡^')kV58K Ь\wdeƾ|i[I&~6뚭AO "b ΐ'ݽ𞈈hMԵ2`ȼR7b44"SK q:OēЬMf_JIzu,s#0YރǯčpWߢ/OD$;kxA^ ʖjJ)[+&횱U{]Bu<|?o~'f>0n& SC|oVɈ-nIffeh"6rt'gZ-xn+*]`Tk:/~Ŭ$ت*=<+]1Vup\Ux⥉ji#*Sjѕ+W\7W--_PJ|[#$$ITt钵usq?bw~<_k>Aɡα-;)"tR۫S6CR Ew [X)&#tv) OR ٮB) ?!]+[](VffkikVR陙BHeaaZQJEEEbl"(**ih[#_](3SظTՊRJK%jj査ի,#K7==qŊ jڵj=ypՊRJ_,jUPk E0LOD),{_z Aڵ@@"hJ7FnhO B@MjP. t &,)T[8T[dL*Dz5M$db$)Ilr|L$M Ijr|R9ayeQrT=H~`IENDB`kraft-1.1/manual/images/en/documentype.png000066400000000000000000003206771450127457600207020ustar00rootroot00000000000000PNG  IHDR& pHYs+ IDATxwxUnzO$@WD@@PDDDTEPP+XP "]: J{MOH;BB>ffgds(KֽǬ+,:#B!B<)L&1ݼ)%qzZ ƔY ;F!B!QUVXذaVر !B!YHNJ$%%>Q$IB!B5 [[KQ1ؙPm(l$9CB llRB!B!D5ޛlJIHn1X;(j(BM3bAe!B!>]Qs[iNIdwRObɱ[,+bAuAGB!B0bHaaJPK2]q`JPb5b^B!BGO.rΕ#/Zj@l#诛8I"=h( 1B!Bteb!I çVjak%1CqZmJIdJAg6=ppd@^?K,瞥KG_L|^~mfsaV WU;I!ȢBX[YqW\s_唔D\cSObcѓ &DbPXPU/{y[sF;dY!D^8;3OO֯+qq9vsw o/<۝nEb4nL<9z$nɉ?bn}/Ēb2ѼS>v_!v;q*_gmeGcF1el]:cF)l{L[bkJ89#tboqw]!N$Y!NN̜:o锯 u P7!aDDd2~ {x$ x,c?,_3eƌz3K$O>^"2X(Rۄiرn%Z$TڂV:F[[wp)zb{)|k"$yيUқ,"O^|94=0n2yynx{yr),9Vzɔر{cFyޏ0.^O/b{ ޣZQ=߈;7%}ihw?oco̒$ !bN?4Mq}2E>4KWRF5>z+׮.|4q*.\N|:=<Ğa6|^=|Jϲ}zSCMrr2C^H)u/Џ~l|TR#l6wЧ'?-%UUsV$$wG~$%'cgk~&ʔfԉ;󵶲b ygDŽ2 !xAzesy?Ǹqı2}¤/g~=Gk$9N!*˱ L&S$ !_..΄ݮU st]؉S0m[5x9w"G$.>oO<eƬ}-qqL,u}X1ʹoݒORR2inߣkgWu7m$&%:opM._ƭ(-rq !xt'cF1~rNnDn΃%z 1FI1QGUtPu V vy력&Պβc2s$Y!=Exp,B)q{;J&3<>͕˿sy3 (n6%ܠ3K~9&ߴfe&tl{{;t\].ђ9i2}@$*W~2wk=DRmh`XYPrNF5cְ@r-Lf)m\̇ͩ3|B!X'NMcK(Z#2bE YUQQxq 0n'fU]mwߊ9| "2*)w9{.ݞx%ޫT[>4a_\t&!KOZs 8e:)wi*Vz 읜ptκ7V)%!,KH>SI>S=Kq}qA*zd˰yw&≷r:&(S[[<<)_ v]T(WEQ] ar?wn svϲ> 05k`4ܾ˟?g@ޥKso3-r|  5{d2q=Y!?Nb'ی/_S/sxFz3VW\)O֣EQZ3.l*za׽>O7߹ !@Xx>}8:8mt*NEKyogfqr }e?̝df[HIIX?" [4%11=QrŻsq_N1f=׮߸g<@J9lHFVfe "ns]pٯ  }4{!ђ_7~Xk}J* UjK`q)},]zo!Qeccê 0cb ;!Bťr.~Pɑ@ǃ !OreJS7`4Ч'7nH,B<"\z6Du kgIB<G ; !B<|Ml ?fGRJzB!B|qFTU5?ZrhѾ+][U]B( 2d97ښVnNB!G<w)0ضmK,)0DA-$_Ȏ`}a)9t2| CLNeB!?K`޼y9߿?lܹs̚5,KHK'FٲXvH"vz6FiX5k,B! I`ڵٖߟŋԩCϞ=,;{,ϟr~|Q@ >j.*Krݱ탆,B!2D9Ο?mC9vn9w$ʏ4#(V̐ۧ狃:c \$At~QԻ37BBt$q)]\p)DwŴ"BINweB*wO\l֙b (p hEl\Bגbװsv~BRL1)*.[䠓LdRfHTqr'˫rd>B0RQtɹBƃRܝ wپ4! : /4K\)wK v\"=O6K=gAucilu7\Z.`lHE 9V ^{O8̚ 4շ4n|Hm/8|=(6Wl@/rxvb8u Wn3AęSOiخ'=C"72~ۼcWS߇((F{N&-iu5BQ$QH-F}eJH \9KUz -g>ι] s<ŏG|ts,G71>53pGw6ج%к9G7]l>x~1xVBX8s1qy|ض(ߢzAପuSpeξ\K#'Guy&8+'2&s_g$g:m]O&^~7dpGOoVL R\2 niS\) oMb; x?.`Ӫht{HB! $ARR&(((7TXU_TVӧ̀N򩣜1w?PXsp5sA}=j/ޙ̦JzO'|~r]հ#E%Erm=o3]q?s:!Ӗ蚞?=+&2ۇW%{5[zzu6|1 >GoI#:-ST](aѻ`rt\sNB:wcUtjtGuh_t"a/|ڎU g磘i[UU@Җh0T|OC-u_L͚$+iiZ}|6'B'r g,\|ӳ-PGf 9]GZJPOGZMnDhॢg3dձ]xۛ|a0,NL]ԞoHK9tLOU*wWI$sQ!Y; Ux!~#uJ8to}+$ 8Ѭb1γe|&fģlW_Ԓ\&\̩DՇ2[]J%|l=&bMęe߲t9SlJ jWRnFSYz4Z珿hө8=\EO-{0ZpnohJ]I'cQި*k!yҔ;/֦# l#9t MW.ՎDZ>ɥ2cJNhFy,ӂ5SQ `$YťN"+\aϘ81ha;/ުU!NHI1P}>щE1DŽxu9*nB!xdWVZ̙3'ߓ\xCҡC"""1EAR(v{LKt?VO|F >G}SՉ7J֩f} i`ɔo>ֵ)_8%+Ԣy=g_ >A䅳*w`d:Ғ_{2x8]Uzn+ϛ_Ϫc鉗~~)᠂jW>,%Ҏ'dxν֊ 5LcT+ᆣŪc'P'}v-=բm!{+$f~FNNft'm9Vye:ZZ]Fxn,7ٶDjG7xwe—oҡ֊K9ھ1a psN@O'>؊R S-**Ξޔ/eEUK&BCO?Mhhhݴk׎B9/ F3O0teGª^=l\eZA:uh:sъHÇURe{j1;U*TȘZAZ1&UqDU 1i7FZ֪XUUCkB/XujgfΟ@N)Vtl7jf׉7ZumkZXZ?ezĮ3ʮ ѩz3*};ZU/:fF%# =՞Q&!85 ѨT\F q!kiJ'ok3NeDQ!a|N~HNN ɓ':t(˗//8Ŀx;SlUr+/l*WRkshQ\֠(ׯc8j\q>3*>%>֙ii=&^ѻb֋=u84"nLJ s͡A6@cVi2жVjEw^bZwY-Џˮ @ XlPRǍk7 @\IHAk5ID%ѯ->Jz Ԭ3Aƥqf]!B%mҥCv}[~;9cNmD9>> s9XfI@" ̤>H_0fxgjM[o `X#!B(}KJJb…ٖjՊ'Olqqqlذ77lǞ?~er'n'ʞ(*jhZ֒gE?% OO-N..㟳c.ɸ>bVT܉i=6 Gص,1V:оTgfXr}OhVlN mŕ/`寳ݻ>߇sq sF؍7 },B! Rz>]_5UT)ҩS'F +㊂g;3q[F솻q:F.9dzzD᷻qusAAvEwDn"._3bBjR;VIg(׉1D n߹+jvh1Yv:qјlzaaqo\pT@uqY@ :o-EﻉöD#׈>orhZVD%f IDATK1h:fkө<]B!x|c:i餜o8^vm[Nmᯓ|,WrM<3m(Q^(g~&?LԿx%i Xo_ceqw*iׄB!$M8Ј9 >bC@zCy^ЊO]l֑;XjY},Zyy4YԮUOQ/}n+2F#. H 'w\ɐ+dNUAVmR*>MP:Or~|bnO!q&gfu1=&t*EtCZSJ!/;>PkБV<3:6ؙzc^C֡Ynjƛ=2?<-GΆzy*q9XuvThK!)1qB!oOPA!z!q4I,$E|,G 2Uݚ2b̳Je@ׅXyӂ'p{jR̭KXB6?ʚJ={ }h&\mX1vHwAYW)\=A8W&Һ5*v̄N9C:c"6n"c؃~V_hh^9G~hP${++gw.ܬU_S>]PIM-2ך kQbp"}*|k W7E1Fݑ&[pe-5GT4.9?&݊Mu=]1^qUn|ymQ.V qvcI̝g~LQ'YlhV:{he"6,;Ɍgtɜi%B$Q0hAl4w}SDZ>CwVr%EG7r`X~f쀊m;xo%vέkMgÉ=h U U/g?g- Ј'm^y[4ujkߌSdȖ ͔).9:ZI~Zb]vmWo-HzJWH(gXr}g\I*gBQZ EuR7zLVw!Qpn6s?Gug5G1Rl=k3FO w عJ2s)lr=siP~glt.cnSX7io<}1`eۺ]e.ixmU{{sp={NbZeYD7gK)zWmSZF#V٧ξ*Ne'})#w-!B<ң,D!S-N,SƷ5Jߣπg˷Y—-Φ=8s=d;woWo@{l 8\Xtdztݺr5Bmq,K-ԣMԬzkwq5BMX9y]un8:.Ǯʮ3|)a9r Q+\Q\56iM-~1M-𨹄7b5\ZN(4Vо:f\-B *%zNcF3,u+O_%,Aœ5Сz5j5+5;p&[0:UJ5Ң}G|Nug%غa+~rZblqtL:4mםg;CXB!xHnjnj O/>t0[({~Wze٪U۷oךg>n?Wna!DQ^O>ޝ8'x_xz9eL6շ4@:Ғ*B')SZ!GZ6O@vc7B!$BI/r(9c}qV}-^~#E%OB!3}Z K_XO_VDB!|{ʃŋeٹs )!Jj:~8 Ξ݊g G 7iB!O(A۶mYdIef͢N:bggWH !`L[5b}ϘB!a(СC%ٳ"B!BQP"/5jċ/Xa!B!x$QΣ9sP^C!B!DD9ٲe B!B$}psscƍ,X*Uv8B!B! LuTUeРA 8s9L&gB!BC( +WrʅB!B|$B!B!D&(#1rlˬʱB!q!r>XbwڕmYn1 !B!șQGUVB \x1_|#FPR% C711]vhѢlwB!BǙ$HQFСC,d„ =;;;^~\!B!xIu>3 X5jj#Fd!B!x(ӧC?gfڴi(Џ/B!:I 3˗/g:: 82!x)=^^v8$QHPt"Fm ;!(T)VX+88KW.3Y",,reK B  IZGDph(F($ !D*Fe kB)!IB#GGJ(APppaAe!I,=Z%IB`@BBBaAe!B!"IB!BL$QB!B!2YB1?yׯPT)jը(_}Bܛ( Jشv|,em#xs~IόfRBWX4;v7^^}N,Ka' .Ϋ\Ja" $PdIlldɒ$pO<4I9BG4:1G,I,ģ.q?{(㸋=ⳭVBI! W(R#"EYǯE[u {nZe>6n [˘30c߁xU2Y$ux{16$q73c^~3.E`rLҧFK~# T1zVŨsm,~]ˡIXiH_`®/lw<;ŭM#9,Z$k6W_hzvΙ709Fgq[㻋V&%تmƟxW}䗿o1i#ke&KI@S R# 2q8c m(mx_%M>R))֕oQb:D$5eKdAYN^-^@1xPQQxzzf[nkk˵k !"Q8ܪy!ݺl'-kGٲh&cQqݹg^c6H(ζ\q ǀ2tq+ɤ*wlOݨ|a-Yo,嫕;Veǖk:fɌ?fe0 , ]Iߡaԏ \>O`w}t:M}'fw_iu$쾩I[>ko]+Fߕ\cЉ;!yǝ|1!f0{QO}+~Վhr5r͓>+O^{6=+?1mN}33$8f3N~`obL}м~m{\!4 UGUU4Mz)Б7бMKw{OoOoΦ^k]E ;L"Ѹd0Fn 6cق&pa/va3`w neo,ޭz?%K#RFmhE oQ=?՞iҸ9ͯW5,'gӣ'qLXK=?eߥ[uʼn8}|NV-ihLȸwkant:mK.10ki"o~}-ޥ}fCNWD- ot)+m.Z\gڴa8[ahߪ%mz&:Y Z'Bhۛ7[xOoڽ%zܞ8(?I[?7mS^aѿB߸t}Z" kE˧Q`v!KS4Csi]2Gۖ#p1,k9|?%Qw?8`U}zQ!%صt1yVePGvJ+~ЮdtO;FGo9d42;6Kr(8TmE`B3%ŽmEgTTks0!yB! }lشˏ s sZ)Jm`ayQ'=/_eU|Z(-J^o j1Z!AΛA wl޵?mX>Xq (/9/Vm= _}uֳ:_g2/Ok|{ew¾)mbv[|pV cعx go=\m6߶`⡸mOׅi \× C;8Qp~T^j5kQf]'߁Ȟuɭ| |kHؗOb١<'?/*m_6()\ؼaf@ݙؾ "*.]Ucэ5LZͮ|4kKtbrXR\T5}p hWlu1E`ݎ-t<68.,4zAgB¨ֲ7ڣ(TmQOz<ӻ*N*4I(n?zPڗ>b/Cߧ(]F E)glI( 38[u0,ƨGd|˥u1 ]Q,(.=k,$^dyLyN}s%^e@1rl+E>=t{x-4cFրF\d$ZHni8TrExu:-r|7Ց3zNrg3˜na7 -b>zU]qr&:idrfPsm Ni1턋%*dipL8OT9XIEUA5t҆A%E㚧} ≥~,d{Z#Z#U#\-( Et= 1'67o^|^Ou#Ivq+l<=q9[Q%ti;VTTU)eSQѰ`%"=ׁYgfJFk(}աPu_Pxӂ-YQ pΘ#ŀhvv5Ӽ-nE\c"iKPk4lq/ה&G1ό24i܄w fոuxSQE7fgl|yvtnq16/WcسmyQSڿ;g^iֈH粄7#zѲY3wĬyj`:lB.%ϼ5b!Ў{Nߵ؀}ʴ}uaW8f[ 'ʔ]\^ʐ7f=ߍ_4o֘F_=>V‹OQ4nۓaO?pxZT­g?Fn[cvvۿ+蘉:ݗS7JJWχ6E)Yل{jFy1 K@*Kt$e)[ 1Ƕp2,Xz^;7uТn [Ɩ;%aC 2cBolS'<D9Iu?fЂX]7p4Q\hAk{fہY97ۉOohf;1e?m>U>ۼG^<};Lٝ>C'fRVjٷ]ŒmѨgX_Jcml_*k/U.1SӇ,x`~^Hx{fKvҝWO)gh؃a]r6eӳ }OzEǪӸ]Z۳=^.j@[F zMԡCƹƖӑ͈9:/o=Ӝ7 ?ΐ`B>z&mk֫[#{I L~-~ՈJ@!d6 g}îQ$k&bYkIjݙlwvoU[$tR ϧ'*n%J`}0Gct@'Z61glߨk[|SImr=x`AEwoCJ^]v*OjGCfmgc|:Sr\"Z~|qKq?75@#> CrTpvs&ynP;9g\=g$6/ƍc&3K =,[Y-&lgPnOϗ^ ۴9P/:VZ2|`M/~{#J?qQ89Nɗ gk:"ȶ!M[Q"JWIZH1cgFQ+D$V=GFHBEz9{s9qh̴@a\je 't?L_?i^m | h:gwMx1ݚ%Jw+7 mnKrkKk3 IDAT7Ҋ)uHO8Pty(sQ%OqJU4Ԋ?co%|r3Z6g4Nٛi-(|#0=|꧜`De}TN3_oJ)ZIVM*Oi4Yw#c3b &7/ Mmo0[I+O3\v4۳[t/V!G͔<6axX,FE1E}S14x}[ѭ34siM8G:~d3{5fypuxC1ǵ{OP(Q/G"xbRm<XShAE넻Z[Fϊb~xMB1O )LoW-`>as3 `ljA Rb6mEa\"7jm:LLEi5[#g}zMKZ{uՁtXinÈi8&M1b43.-~5iP|Tbl-QZͺCrء4تpdDYQh(r|ǃ06cJ./V|)VI,5hZf 7NEUQBC}vM]XŠ8>InZb9 +Az K ʝcxuv._CE.._'-"6.mTh>/$Pyr,9JR4O.a\Z*6uty3RBE<q<`P%|\kC牟p6|]ra!F.mwM(K72麜S]ә 0~YWS8~jb ZOb w;'`',1ɼ@bXsSDl]n/K֎ !i݋SM6tR:2ϑA)gKq ䷝)&h~I ?7oMZ=:8/աeDYϐfW>i#WPhED߻ch4@}p _Q䏉}d}nK>u'o( ~|4E:DYW esc/Q#7ҷf`bO3dy|81x i0wmbEVԳ_N˚K4}F& !}{Q Y⽤1B1 t4Ω %ć@!T$iȲ !Q$vvv\ e˖I…tlC=>CB4SAYzdiPB!B!D&z^ !U.!!YB( !B!)H,B!B B!B$B!B!D ( !B!)H,B!B XrT6JURCGVaӷLGd37ѓݾ3B!XH,DKtO5ɘEd[PRe'Ŀ SPy?@B!xoduBQSb z\k4, Ld;"\!ӠF4X[^B!$7TsxF-ɑ{UC z4ű5=1yMbxƕZ֒~/$~9Qr5tGӧ9͠yBBlWzmbq@5l_v?"'zAF:6c}O?QQg2~wǚTulBO5:Mv&vtrtut;0sZQá6]g|M:Tui߉߭tyB!Oe!3/PeJ{4ENr%FC:4'züiRs=3W #TBwq'gᄖ3\2rtݑ/ŪBC!?aD/~G8mBְRbT"f's"`ͤ߂hU:WX6xz X.1M YC Ukg'c9j;VvϨ3C/Ikt r4ʞle(DUK,><= ?K%k L)Vžt* prVFEX4C5p{ֽeʹ`dc6T1L\%Uκ'&ql.tzSZ3*iJ{9pWAwۮUz6adyM$O) -Z,**I{ҵ#˚CeU7jZs3Ér˧Wch0)Ҙ845m{2ɁQj=,i[!O cwlR1?rƥvQteб5ə2qw}B!yFYl+|/jcYk$5䶴 )SMnluD>D5qo3Bk|~hB#ⱫnGj :EI%R{t[54O 㮪'4ʒfsWV(MY0Uy;eSR` 1|TDa< 6V)N:bik6ey*_|zuZ-ɝ\x$Q avs N=nbXKXYHVPQT5c/B H,Dv}u-'OV,=PPxN<$$J!z,Fh*=l!o ʶXZ`'-.9Ɵaja ϰjsceIh>)2x)]u*1E3lL(mš,x|*{zr Z or!ed PBUȟwȍ.: >!6[ƗO !RpBB&CCCllmdIہYe!%Ѐ *Ԅu'dC&v_к re?bI΋66PtLrQ=Ađ/'N[Sh_&1 Uܯap\3 =Cjŀ?C|b9^[jLլ>3',d8ږBε+ؔ-Ez4(`gj#v;"^goR-y ] c{Ս8 dd [V|Ҩ w©1Ё\tuvK>ţĚ^C^!D| 111TR##G|bcr2\R:7&Ǯ]طowA7t:OݺuiРi<(><-l8K\X㦔Z=)9=5-No^ѹaQL;gT{J4h|L 83ۙxF9{2(`_i\J=d&O"|TvF ǿ*6~iK̝G糀i#[2/15% `fX܉<:6CR(~:+T~O`@n#iL5ZkUb[Fk(:Haz:MM8h; MBu]Rn}$}xU=K !JBR*FFr(2!%KӐe_ehӧquv䐲[2d]q+V9sиq,Cw U*}Gj_Nٷ:H|-ouc}#DJ!!!٥Zr/-[&ղ .ұg/MWU{:}_?`!@urTP^o'>mz&TUeܸq4o<˓dk׮Ѽysƍ*lA%JgoG'Wqܶ U~,7} !B ̘1I&eu/4i&&&fu(B+vf ҃T!%]27>ԁB!I.^ә3g=ztVJGAT~,jl|Su@yŜnA !B$Q~mcǎEQ.]RJ!EҥK/M;v,7o~'q!B!ćFʎ;^ˤI6UU믙>}swAhh(6664!B!|,gΜI5'+™3gyҋ:ˎ1̦iYjYz5^n\ϳu#:(Yњ>l[!Pq@-4H`dW)ZeW odxԢj:4iV&9ߠ]8օ^Fa[&B!Dfcl/3%Ꝿ]COW:1}X࿏wvv(Jڬx42]9aւPxoF)2*&&̓I,B p9H-W֟_@sJipkE7|'rk][NaͪQoTGt;7ř7љԶnue<$*4psíQgF>8΃?j91x{+X;oά^|bCS|Z:6|`\\!W"ήdtצԮEA*Oy*=̓p'gnNoӳkۙһnniٗ|&LY%toF4l?p7`&$lNFigzkї9'Lh͂ ?j4{+9ӄGfh??n0LJ;yw}|>dYe!B̤oӄ$`'Yrg oM{ط NKX}[V~'4i=I%[ػg30we3UsI{U#}(:1ю9]i$kdZ}c 9ɱiаL*:J5mFIL/3 ڍ]} cJ|Yl>Ȯ *cVG'Q1{ya?v(U6.k2@}+/)!C|I2Hibcciܸ1'NxnڨQ}sҥi.\`޼yL81"T6տ6[H>/ߜ}u527hШ jr0v_sp. OQ1LNLSB+Szn{M WJB0JeZ-?o;N%9a+fXYxXݫt|1rH۬<1K+K*b–ؤ=syH&sbṰC3]54Z_xQD+>Ҫ*itVJJǏرc?$uY|yr\`AVJ O?ݰSK\~=X,A=)`*'8 j)6%#X !>2Z 4vۙVr"/Hؿ8})JJq6É5(j ǭp-C[>bAn?Ur~ Օ]De'DܺۉUE\f)xѨbXx>ׂ_| xq1.D\*(0~oHmX,P/~U NpE;3\ĝ'% Q,M:P דR.sgo' -GL5`niW " sVP<ƍcܸq| (g$?44 ʖ- $,?~eJ3'X=>sʙaGvۯڈ)ޔw" !>>=HY`نzktaTnnk3)̠ihhad/O#W8g13:ҒcY2fҽ 5kףx)im-7566i<1Vӱ6͇ϧ/t`8q`\;:9Օq'j$MoaYO1N^֜ Ov^vwٽ9ōToR]\~C]k4;qL{p̷Ъ}wz r<-<7z5#_r(_\VNh|GPG*C3>S&ڰam۶}iz|TƌÔ)S(U7oƆ[nDŊO/Iѣ~mݠ ^>]ooȐRrm?ߟJئ4݅oM.QՀS`x&u,G. .zxX8ou䞲~%u{ &2T3x4Iz0D-z8;aG\\?KW|i1`$_%dNXsscՐQ,]fi IDATe+WBٲ? yE:骪rtAOPRnDl,Y}^ϋw'00u]3<<IO&-ʙ?K.$ˋ *$ϛ$/GH6 Toـͩ~џmSrdv,g#QgWqr|#۶f!kX{I9?Ɵ9{w,I7 ?>*p?~Q99f Ǔx&.Ué &I{m~ln$ !I3I|ONԨQ99hʡ/_ل=7Z;5wK0.xWkGڗ5G˪nԴ ]ϱs3ܺwqц*Ikؼ5][&GqZ}{IʥuE

?Vs".ܠMsRN܏AE%>&箄&o`[&NΏFә- oH^viHM'?OW(aƽig+\?1P^ B!$Y5Bt[ynȊ>L5eAeQcV.%i£|)Lr$&ˆp8T33o 7hMۗ.L(d$?5.ظ K!Be&#Df0{D2wDdQ dLJqUB=B!>Df\zظg rͲ:DZ߁Mϝ;СC9x EחΝ;{[{;YpA ˒ ћ rfB!>H ݻ9{ؘG|ɝۂeu(\gM>O<у+W0iҤwhʺY!XXXXh07G:tannա'(gMcbbԩSr\dInܸA\\ӦMGGwB!h4,,,PxɃ$,,쵟I ͛+W+W`mm\jժ Z!B!$ʙe޼y2pB!BdCeׯ:=$ɉB pyJ,IXXXry2'X!B!$Q$/MK%ؘ+V3gN\B\\#F瓅B!D9t҅QF%0jԨ uS^z'tR&N"B!BzI4 Ǐglٹsg&D%B!"=Ң,B!B B!B$B!B!D ( !ހJ~T鼒ʻ^,G9|eJA뱊^ow/lȸ1YB!GOe!X{RTNfK ?ŦH|㹶^rq ;1 ytoWp._2+Q}vܛOW>Ci] zƅEx\ 7\"(<<:R5Ҹ~`O`KBf0F8SnS[ϟ/ٿp ]SFLE[cwpȰPwl?oM.qrY~#{w$Q"{|3#54o1oM^+0?tyQoW3\<đ iЯ~7I5(FY7QAٮ_P ;S:1}X࿏wvv(JL~4GcLߒ}Ock^9?OУpQL8Ya8{od-S}4&urV`F<]9Ec "b(nv +vINzfITsxF-ɑ{MnMe(Wzmbq@5o8ϣyGXgԬߖ?gJ,{zйNWR6(6 \Ԅ> D>qttCm[g;ġpgz?_fvX=l3[ѬMj&ת+М//[ը%c<T" _wnBݺx&ܸ?VNuoH:=Yy'ۿí4={U(xKvvW+e9*Yz>zG_BnԴ3Dc(yGAcQQ>*D{Ezŵ858$0IEM6QLiԨ.]Ju>EQ;v,VVVXYY1l0;Ӹqcrȁ C ]ىrm޲=S?۞uˑU۱G{F Ο]x_pla%}| 7ExޝϢ$WƝ5lk`}7GA%jT/9~ Jsr@'Ln]SMj`r0O8`B}_/Yk_9Y)cC(~z@U|ٝwΨ˿dځh̕8ndC(UjP@%"`6 x2w!F:L-knaZӌ]/0oڟԜcGspL|4ס jՒBd-5kY=*cHEA-jлPc,]q{z Iߒ0:uꄷ7/_F׳sNʖ-Kpps*B߾}LM\h1ZOz<`s[f+fIJwGXm2*&cq>Ϙuhr#7vtS;0׀6*Φ?vF*p2C}nb#lbhr֥0/>48cwkԋ6՚QMSJ_ˁGDQvwvNߋЪ8]A52(6V?V\ˎk[CИƫ7yl`xFFhӉ1Ӻ)twS=Ѽ-^c+oDK z[接˘gڀ 1`L^,?5kR$  c ѢH9I%.&~W3i/YoJ;K.ή]0aBIr1cРAWv>-[|E}u-'O<)WY{[UJ+HB@bB,q_Z=u_W1ETPUȟqBCBXXb3ƈT޽pl/T%ڜ?s XOe~ M|+Dkiu.7>9ZRv5ʄݖoI^Ja_hYU{Ba߼A Eɕ^>yLi򦃂 !&}%[H+t)^ǵYb<$=kܿGG+ Ay|(6<%¿K+K+bV=`]t'0Woo=ŕX,IE1g΢ pLk]/ڸ.ɋĴ-IrCjߔ?--=frt N3INtR .f,>v*8T *%OjҶ b@D}$DҨZhؔr~ **Q79w%4Bsw 1wlK9KZ==^~Bx@ ׉|X{<9(UX2s3WX]%r/#'>!E.~;M>=%?pԀ./C9wv |Ȍn_cFn 7/] p7 C:5nJezۓ"i$'̤p[bގu8ܘJ2o&S۹#9%-Z4zPt&4G ߐLҐ0DW.=@޴7.?a9cmiP0  MݻP 9՞1dw:q]Q:ϙAtu%"Vit3RyR|0mdK?F1d,SaQL;gT{J4hZFyVm^'.Zle|L!:Sx ç nΘOg<&E;0k^MZ}ٍsSbv-ĩ70kp҅+ި!f?e޼a4r`[ C}BT_3=^&P\Ȟ] |!2^nh@>q9NC }'\).id;X9Q/;;s瑂Ȍe]0 ik_ehӧquv_6lm۶icbbɓpBZ-,.##ӿ7ܳgOJ._ӧi\vm]9x*+gvӭ`ֶH*vΫ9c6e\INy !]e+WBٲeR-p"tUU9xpӧqQB&UU9y*(KL6M^MNNN9sGϞ=ӜTR?ST4ի/LJ3g6C%+A0Jv|'\q*Tɛmcͼ<{wbo8Yc8I,B_Hא9s2eV`hZ/^,*U*y$lWpݳgO-Z%Jw^-Zȑ#Sm]~UB{;YpA ˒ ћ ř=6(w۲: !B{q9]8;;S\9Ο?<ɉ%KPxjɯoJ,$͛7dgϞ,^89INEϞ=9tPrYrpvv;,>ploV"B!{E`ddĞ={?>׮]ݝΝ;Ħ,תU+/27o^sʙaGϟ-@<:4FFƜ9#2eOf/;JH]͔yhea|;ȑ\_Uz87-&hL)Jܙ_⟏ S6g,=z'8SgX4d'.{Y>:!^rm#?\tf֚%tVS@!d"~/ԋe_IYVMoײmV#X“к0G}k}EqM]bG" l؍=ذkޢ{( "X5vJ/wX%(yۛ[a~vu?Q (1.ހM7yn[|![S BHlYc[@eGO[Zx@Bj0j6b֕TOɁYC7OOZK,׺l|Dpzn:ǦhcKݱt;;=ZΤK}'ٻPTv.q`)y}R[{g괛D@.gSwpm=M2?6 }Q \u }=g֔xs=}|Wr~RjA{w/3U'j-\NmSDùWzmZ҇N5^.mFobOlDAm鹓Rڮ~| IDATB̎;[w³=Ukrngxg d;KjZq'҆+ގ:8oːI{%NyH^4p٣&V"MYk9;<\qti@[8h5owCv[ 5$5jIZZ$,؆:nn5hϰuI%٣εpmS ۛfu]qtnH)x"g/bۄ4cmz/ }}fO%eiߴn.8{ucZ3d!3{1903SASF^^\ψ^rODK9owo| |!(R:Ɣ.m;ƞ`:-$k̿Wb]}{.4ScY$ڻw#7ߏ?tA2Vu±N}aۚ:CєS;~Pٗyx1KC/G)Z{Xb!eAGmBu(٘WCj$uGl39Kt`?|knsjϡe H)ٌfGH3^*6o{q֎fi^l2ʽ^Y}~᭜ր@-H=#u*'6fo;8x7`Ϭ\f߉t6ƀƘ9#7pv؟}>dP[Pʦ* 3/O%Rˊ$iWnVIhҢ>BU}!{u_F"}odE"oJtlZ6mCljR$V'ߵ0.&KߡpxBC:4Os^:l?(woW $ +:?ҵwilJ@Y1͝l{FZ&H&hm;o|*MF]@MJ5@GҤF(D\=$K7c^F ǖ[ĈecY`ӒHTh#E{ϟ*}wt@7Z(GcPbVڴO5/A9KPFjrP>QϢ> M&^]iR<*UxvqLE*\N0@7 +ȟ(ARW M}k%͍mTX߾Hj*4iR#G^Kx3D2 ylhSc 9b_$e)C+TGg/K-0$Wv.*(h_"ó\g@x&^}sfxZpXMB/G3( _NsI\K1Aņv~}c6]p_TzUtsi ^AQ^K[3u+Z%jphPbNpJiZFxq2Μ#Ǝe>,]f)V\%>"v5]t]NHttA9e7>m*@I'|g~, K"O<9Ek8G$IPQY23Uaai<-/FSYg+z9>/3ueT2B6~IK9!ȤLvfFrj2r4N};-eL;; 2Qg7h~?KBT>L@ 9h ,jIXZ.[b ,+<A%)aWKe("bՐЌ$Td$Yn_j,@YNTrӛaN195>1=P057\ 0$!Fx-˖mKb0yI XRPFqG[oJ*Mt\yTu| &"@R&zfr3[I8G;QvY sRl1Q\(`\αڨRn u >,]J0#'Nuq@/h{b"]~|poL(ţ\Su Ͼ]mJ}_' eAȮbC|ДnWҪ@[,6-uS!@Q^i@%E噱^+M1c{i,_S A1 f9_RiaKljw\mncH7wV>PQK0Qms#g[k4ʏhQ$Ji4W4Zn>_bTΥF￿"-yfU|ظЇ"*f*#*vxnfwJ%5j 4 A2ĥȃܷm[z}/ByȨniuNlǀ5*hIyξΙS9x$%a Շӫ0ƿJl2vBEB$Ԋ")![R JHa/|#oyߕ/@<:ް6 {3 k{{$"c経uy 331ikx.mcݱ} A"pn+ܺxlN3"`y[4$\GzdV;+Aa,_Dryݣ}puHRfhV'k̋//T rw2.2&?"Pbww=s&V$"n^aڻ8_?f7@{bۇ"EJɟII{clomcJV.Iß-aR:'pLbiI5[J pi2Ω47b[lH̏yE5B,4`q #71[Sۓ}oM3[PJa4MV Ѫ}DS;ֻU}J\ӀXu/4jފ=GqKlB4Ξ`_Ӎ#NSؾtKkפjQۏk?Y; )=~TF-=6c.5yqu7}xJAm݂Y d^,٘-Ze#Ϝ^f UXƅ ǂ1taNw̋:{>y>} dg8NS=炋wo6ǫhF G3^w𤦓3[ʳ6k4[Sݯ\8W*J)^N.8:w!Oy[ɅF{5xO`dC7B]lZ\ڴ;g_^\SqЁGRϵCFS_fFg 8 h#q'e+!w{ @rzD])|z-'yjTԤS4W\{}jf杪NEQ:[t}vNNcku{fN8M kR=(tYRb]UA,ŝ3~۴uM5dPeП?(gqh0Qk"ЭHO8r4*UO˕91N|s!Up'E/AȦñz!ɚu)W:\J6ooJ( !Ϝ=m/XU[!Aü<3r}(;EL,Fu9/&^ Af.eKPFjrP>QvTmx_KMq1r*\dמH;wJ.5*4%"05-2AAAOHXLٍ,Zϒ$?DM+0!WڴTM$Ϣ^r:g)F^$8ZMtpc&}tqȃTAAA4D(1{!YUqeNfd,E@4YǔuYSyh6ɏճ8/5ڎF;Ɛ{Z| ?AAA<13Q<ɂ RdoXB1bc.zر>DͺЩWC#.Գd41rf$˝K7LAI%ȭJ%%S   QL$z7ΉQW4(]@;ͬQ;Bj$2M]GvyW*ǘEӘʅq2:&EuM5lW+(}i gn}޾Lj xAAA^%^   +D,       Bʂ    ( 1+hYD@sYMKh.J{w `O"(c ~Xv%Xם}$B`GzjC>XձH\aE {Ʋ-FKJ>{X*CT>*5װ^. @ʟ1n!Fww“Y|'!c{TPb%=p?_j1,lKCF7TnA*zVy$HǾXp)`T؞Ѷ olh.l߶XR\tnA(kMbޮ <䤨CkjK\*-[Ɔ*gZcXRyzbW"z8 ]r[{Ͼ+}Kٺ~A|"O~l̎u\؁aUNJ9Q ?[*J׍YCۜ:lzqS+$i쾑 #·I8}gN̓drt;Lp;/wE> -W/[7 xJ~<艻y&=֍ʿ38}g_N9R,v9JƟ2n#)O.rU5eQ3-#fz dxfƞ2N`tû0qQg<ނ#WsH0aw#V^G{ w0h&X^pdo{>zsf$ N&*'Sd,8AF}z}[bWJv4B{ϧyfʦh솝m \Z`Psdj7$tr#\0@?u FRVgHH*ciXo(#j1ͽюgGһ]zQ݇^O"='=bff;µ/KO]'hnouѹ!Iz/bۄ4cmz/ %ql~lR.uh FnmEMܲ T R2La0WM{F#~H8B'"TZUΒ>Aל!}`JIIOW&=A+ߺ ,H-(jDt *[$ZQ&Yұ fqlAgh EŖaJ}:QvɨLѶ[#1@DNDt(Z+\J`ZaX'D@Yʤut9{")pi/c.0aW0'..8ϻaNJ?Grm=|r$#ڣ#i9^00 bFsT ɂ ~+lr SV䈽]2B6G ڛ,7)NeV*}=\e}L~9bit); cbAP˩/#o2kSaJ[ky@¬#mΞ7ߓ5v?ՙ‰G(=KaO=7x?:'YxᛣC.sSRH\dמH;wJ.5*4%"0ՙoC9{x@ /ԂZC d4)!ir8~(ݐYMwﳢ]5*TLZ]f5c׼ Lՠ6Zq 1!?FTMU*WkԳPPOL *dg /1@Az䌱 s`50a >/?VcԞ ALq~v#~.euZ6/ͣK>i1g-Xpfvn+2 IDATW\ZJP)GYu~ޟ 7O sou7k:hs`@˛d_Css 4>H#{TzZaq /^fC |a:T췙|3DE83S,eǞe,s *ԪD>qU2BU SsưJR̵j$ dY n%S3reVr~I&&r:y,6ʤy *dQcai,A)<+c6q;}$'.)1 kʠ9{Tfr9h3).9ܟ#i1s[DMB\=?sMv@Z_dtĆIudzϜY $?cd[ω Fw_r,Dp{Ԙ? 4;?c!e=>:P>1BPPKQ"3D<&1sp5F.;r}g)=jPrcӍiY黺Jo4EnfJC\]rI^4i.L^G *>l\ש0eI ĊZSFD[xLErFG)q{ P@ý0.Z$JҊA fؙmyHh;)~6a]@I%.1mrXj?c/#Fv\EXǿ,jWY3;~MM, KdH>?V6tF+zpYEWInYo5)}o*\N-ve>hԯ"mb$7C28¬{ NEp%K7?`Su!x\Fyux<ŒyA8:$) v|O4U]XE]}9yJOªF-JƊRQHǙF1KGndLᧉ3~͋HLH !1|+}uB+k;+pu3 0h9OB$HHLA È^ Ij;VhHHH$) ~lڰ6^TaMS$Å!)* T9}o*';OKpmxk(oPKa_]y{1q^ӦRw\I`eݘgaYGҤٴ՟٘Rm)Zv̓ K= ڥ3{F]m!|"{h8)d֡| L2u>*Fx OPIL;5;+p[8VMowQ J.|6y%U}&0R2#ٳhr`Y֋շ +ŽG1h`طdpMkHrKצvƠGaῦΦ۹H8.PxMA/FQN S&OSA/Ĝ]΢)uɯ3A&M}UA99|;-p4>E  u(&&'Op-ޛ>.>giꃫPJA$& j_J ;K!0Mח. B!@jj*nf]k͙?+׮맞t   «D1~x߸ 8]T.6TAAA\b(55Lӧ>Y~   Dmں)ӧq*'WAAAH#^&111ܵ$a]cw |O0uTm,GAAA?'Oq$IL?ߕ~SOAAA>13u[ǬXP2e1 [AA#ʟIVI~t$v,#X2hիUW  «dY͛DFD#dwJ!Iw\VwJs-4Zk5Z SM  IݸydlllTn޺7)SͦeCBGvFF|:, LAAEFDRw"H>.J"2"K_tu̟Cn]iҼ)}اIq)Ezu[,e}K4մ>&o*AoMjj*zz_B6@JJLd9 6 GDF|kV`yt,_P{ʔuXWc  S@[ ەu9ʔH49)|.8Jpe/o|  _x2:勗;~cǏIMW S5&OLPu=!;С?._h}9>v`XRn3񳑊uEt6A[}gAaTJ!c9bodRAADdYaܾ}7o}6SgLٺ};,gyVelݾ)dO)6aآ?Z콑()ލsK_s31 4QRFM |%N /$6 }Q \u4܅α8sz;z3_)ދ4o#JCrx7Awy (<`s>,8AƷ@(Ů*\i<9܃7Oj͔M ; YWOg ï_ܛE:Mێ,tp, J|b aw0\zUfLr|mR~oŸN/ |r`f/,0RA^QOG** V[U*U,'eM'K&2}Am*f} I)ĜKnQDKԝKVb D( 9E!%hSĂ TZ:GʈhN6uplL _fןZ7TپL ĬVx5a,.C)4E{2f͜u,pmj 'KlZ7RۋrfFunBڮx Cƛ:4<72ߕ#NېvԯAF2i)K{80p_y6h6)])eayJmMAxY-m^>;ƒi愣[:N[w%['ӭ'ǧ\?JArInGOѴ "( Y[ - jGA} 0|D_8#ox6Z\8e 뷁;0-gYݐ?_ g]=f\ۃ67r&T^~Ʊst]3-B Ƒۋ1;46=NٜݱAAZ_p\@wIlP&uU4*>][SĿk h{0?`s$XӰeUu@7tkNz Rű"9=&"s`Ujam,duE|S|~׭iKF !AԆmhM %91*srg=[*Pƕow2rSihn *G 3GoO!ԞiRII& (}r)?;CtQDk)  WLΨkcr_jjWলo"uhzwdS*T0M?G%TUNIZQf2$+c312p0U=e\/5>1=P]FfcQ0"F,u/7Zw#Q/xa+wS9D _F:)UTXRͬ\ӏҮ7|*K"PAA05Ue1%K >l:CyrSKHȯ 1/bUcu%$tӮEd)L%z{Ϲ8kffÜUBٜF"%I"$R/T8DJ!9f]0nn߽??yR ph,Oe?M6f-?xn4T{G&`A*DN32Y,'vxHt0L)j9ӽ} Պ?68S5ğp ?uIa}$,p&fx?0#\Z%mp^vuJ|;)l]g`;ǮUв̥Ӹ6fGDq4HO>qf^f?vܷJ$55Ӈ`ϑ9TEcW> xuKPmg'/H=?c4E͞ӤÅs9x6 3~Gqw+iXh0"6lL\s,"""""-uHQ?^_ÄWnQa[*M &7B:uк4mМ~y3(% +eҞ]sxݥX fԜz[1hcq^}E*9t3zfRzk@~_62f {Obz"Z֥VpzeRJ6vݷ <2զf3 [/iWo½LY ,f/0*O 8xc#4hDcW} /5ћ?M5\۶oǡt.aM}7ޛ06^Āo=۷&jU~kɵED'111dyy_<{ԱCv0XnMmN^HjjBBvs뱛v_qV2߇S',r/yoX(ܷRCķkО:y$$?}'_?Bbq3#z-e_Ov'-@AYDDDDDD$`o---5GLIܿV?| N.~z/;{i !4?xw2 _UCB)*ԶHLJ9guLmE͑>`kyȩ IDAT۞uy+* ;*M;/,95yi9B:2-erj>C"A=0{bb";>WKIIם;X6u^??/-vyyll*EB99o3+8_W m)c0\h@DDDbooOjj*Y-ٗ}+lRD Umۮj߃|<{R3M5'cI.2YX,08adv'v28}ft2^0aO=~[t{/^gpn+4^WWONR+ҒBޢW&.L W$}]63Q>l=J9?ženoїla{L_C?zR!"'0ocMymX_"""ݍ}Ql9STۇ[nrGsPǟ+sϟ?WƖLn}S?t%u"_q%C q'eG<$<9ou s˿d"*}rtu֠ x%[QpKh 53<N?a=5̃&55l֛;3z&qx>XG>/kc׌t0_sEDD`ŋcu)+Dnё=(ZHnrGs/o wF|On)opOǔ`e|vq>R|s$sxx~-JQ+p8ŔYoU7^2ag1c=6KY_kXS`zӮ8_Ym-qmpUP>ɳf1] _F YDDDv& <<Zvv)ZiҨ[?d] P`Qt=^O nef7ؤR ͊wbIa;4Hq ^H p0yuL%?Ns"6 ɰFΔ{3yZi-""""KAQ'u-۴f7 C.LJSfܼu'l~b4i(NOjT TCZ>%s>@5I?Ȳ 8Z7&z}%w浈hh7 X9p%jр#upU(%%𸥍DDDDaDr._ Tkڴa[*4(2,وY1Fw},@[2۠[ހԻ$L@ShDݙkT }2v˚}3|e'0.>_azSV_w|X0".vƖ ׭fbx< 'tOYq#~g k~cdF5ǓS׶Ñ_I5睗0*b3),""""erQ=" 3Xӯg: nBip4Y jKc}rH5eH xNV~ k]}Z>JwiGu& Cj̀]yZ?FG09Aأ?| ȭ3"8N&oLԖV"[w8{?#6bAz 8f|K>anqgɛ-DBpANa)oV̮xpf #5g ^W1[`b3g&""""reٳ ^sxd>z*{lwyl5 ;ƾecwM#(F bm),0]'޸Ԭ.n_"""""JKE8ÚJJJRI^RF1m5lcxVs& LZsVL?8xuF<vX HݐfڲH5%3Z"""""wfEt~Ԝʓ.l^߰YS,2iеNp- #2 5c̴DƏCQ$O (ŲHfC,8&ͷhcL[Ml&#|nnXH2 88pPN޶};pI"w.&jU~kɵED'111d}y_<{ԱCv0Xn}~ϋάcZDDDDDD$#e EDDDDDD2Ûy8 l 0YRUШS*:vwqf;X/ݍ_^ձItM3yZDDDDDɮp&l-#;>+'N$ȃ2an̺ONT"(;ՙG`#n F4'f ܂</3;VG&}63`$S߂9}ZDi ~4 ogv?Iaۇ$u9H^tnʏ`3^io$ᏺbl6dTV:ɏ[3*jJe焦\U1 G kHX5r:/nw%dC\31[LMf fgg73߮\_Ѳ&'-8C>oZ{_s2GWL䋯Vs\:8R0^~T"""""0z&M>T]ߢ9FfS3LՃx!l4iG`OՏlD[ S?Ѽ;y/CeʷKY wU~:bq{v&YøU9:{2b`ݷya#Ff 7dxx 'mgs*ɚUv4i~O;&5_w屷1_<} jTH< ʀG~Γ[ kv޵h\$e z^ ;;g<ݒ́Se5λ&Z iK0yO{6*PC η>5 ~[֋ @r1Bs?N .LZa/WYζPj(fK~3<~fcqN~:oK/6KuZEDDDDDAr)Rf^>7]:n©NNot<+`QWLfLf3.nnW16lc8Rwi/e3n^^\٫.k&/ K9ԋ_ Ku3X?gÖtjz__ۣhսU͜=aB5.c]Mΰf/]Bi:]exMVqmRjd$vU 1ڝ*^79w:L|nv7cvQ@ tDHc՟Qtz )⁉4FzqVt̫|w6mW5Q!;=B>r7£5I)_ņĜ70yKD;.6'V~d`#M&\=I>i+Q+;gd̸WEDرkla$2WT#6S5= :A7dګOXCtRZ+Vbv'coЦ?=Yꎾ쌸|pm[26}ggrWG9BJJ*))9rGʕ+剈H@ cZ*ƎJYk]E~apr0:fMl_OzWlw8W ;GLgp$U*c2;xǻkX>ћn.4HZ;gwʎ{NvO1h]o*ԣv;`ʏyC_vѷO&,_.гԯWEr?E~X,w ""=e_N[wIj@ Og\)֍ É!?#jJ/,B[ ذqtPO‰eNѤgxMSf 5ve/8XTLhL6Ct:~$ՃjQًL|3Ś>E X);;;+Welʕ{=cQr4u|dǘ>qIjBhV5fQS&dXXYSϘ ҏ#y'Hcp}e .h}$C%F-g-mߙF "0ߵ{Y@!kx%)sel;Ѯ3{ۓ mQkJ2nG8wh_AGF"/""""rhFY$2pΔklɏ[2gfI`,"{cEif_Ĭ,CTV g56 ~O ߏ`+ WN]Jtv  .}rf9yr5Խj]6R)n&W%$6/^c^<[ ;g . nBip4Y jKc}:3ע|{L8Rf J!p5}1/ X Tk.=`.\bgn&=oƽptЋ2ew߿|LDDD$iFY$2{ؠ qNpV_1L̻Cx--[ċAٌo\3IHH|fuG{S|K:^~S˕WW'9e@LD\)Q+cxNN'ڙZ'cOgf_l3HOP!!#b˒aKIW[IN|e7]ѧ>̞9\Ӟjsq5&\9t"1GSPɣ̾}_VҥZ|~lJo{ܤٳ ^sx\{⬴z 8;;CR4S G}LfvaAq3A$JZwlt2a䉓^U8gvxg0?i?CČ{ZIv{.8 icK'Ѹ5Hc^ߘbF_^Qo< 88kٵH.kϼҀ؈~ vGӰı?S_a-KF4/MĴNVyU ϒ%p;=Bog1=Mxֱ|0I_9(߬>%ƴ.x2g0oYXIo`X |8glÉ`ӝ{9 ʙ8/O9O *]a)F"[bί-a~ř9vv (ãE]IOKp8g+]gHNSPɳL ɗ9֡UX1OF^3Xߛm)EIht*IXkx0ՒY f-~rE۶oǡt.Ie;"fۚuWrͮm۷V;$ƿdmà~xpVO>޻Lu*^#s_ݚ'YQ[()PLL >>>w?0Xn}~ϋάco "9Q2~N]P.Jzü/VAQ4q'ɭEDDDr6”6#26Nlx ,(ԅ p΄%J>eʙfWn!""""K DDDDDDD2PP@AYDDDDDD$e EDDDDDD2PP@AYDDDDDD$e EDDDDDD2PP@AY!`ɧ4#Fmkz:.un?"EDDDDv]@^r "##ٶmgϞrAժUiժ]4EbrsVg|^iYwgFlA0oq(7Gv&NgO?_ njr6$%%1bMFJJJnsSf͢_~ݛaÆ%I08rA`|=9e!GHQGlw8W ;?‘R4lv֖I (XAYDDDD(Zz}2a„</IIIa„ HNV}P'Woʅucpbf}ȏ√ҋ! d 29 ;1M8s֘ Ӛ5k\auzEn`FϷ.wnHF}Qf4]!8ER _ڕ>Kٿ2W$""""r[4|#F!۷3bĈ.C2# L)?Ɩx%slj\?*ҹG0>v`_$aK?ː6vq>Ncђ>ߕ*-tĮ"""""fĉL6-S=j3ӧOn:Үj6m}_'! \3~x'{8d/N&oLԖVŠlƷDq\o(rIN:KԠp^*ǖ͵64-""""rRPL$۳aTKUeώ;*,IϞ=s2̾}_Vҥʡ̦tVn>k,W\>.8+m&%_k.Kw2$ )gAKc۶mjժu߇d*UPVLY}&,+ ǰowp4> kJ>+}%nԖ2h^6i9d$ӯC~<000,hԕ3>%D ''4|Y'n-NHH`Ŋlڴ#GG`` ḺYzYn#3&<45Z> ,2iеNp- #s?!.MY?g{Mcćy}a^G3\EDDDDr=Ȅ _b=3{09IYɪS]yZ?FG09Aأ?|"""""5=|0tPNJ+شiGϏ@õ;+W?,9c`I;ɾWgaTdOwz Xng;kÖxӮ8_B9y ^Wz4[`b3=,""""9vҷ+ZUVwdUkVITV!bh=-X̤]9P| 癷ޥbDN%a`!&$&ރb͘) |8a" /tDDDD$juرcG.Tskvu2k)ƙ8/O9O *eOHAoOJ<50lw|(_GVׯ))WJKK#88Zj陋]ӧYniiiW;:: oֹ/Lu\'4oO5Ql:fUdVW1nmDtmIϛ_@I01i֟Qvh,v[L4mNX.1p@&Legر]F&jU?gk׭y?7v^Ȱa2?Æ 2DDDDDDpvvfҥy:,tRs؍57쾣YgVoFb.]nGкeڂ4i5wnH_3m?$}ǒiDDL[$`%="""",򀲧Z;:֭Ҷ,)ܐz7+o)ߖ1u5~pe/KY~-wis(q_ײf˃9~~E&f=ʖMh滉52Ҵ oYzckbn 2\-&  VOaRt4F"Z?4zy*)( h 8(['o۾!9\iM:TɵOD䊘|||Zav\{cjFYDDDDDD$#e EDDDDDD2PP@AYDDDDDD$e EDDDDDD2PPUYcf;WS.7rSZJDDDDDD? ʷF@c۲Cqfk̇լ9q))'m %ת[|xߛr 7G'fUI ]lBrXq|$zmLXjF9m\8;sv@ot;f}q*:0'tqiD`pnoߐ jHA 5-"""""roD AwqG589&Hd U+$DZUvu[URT%"FT{.R~ED"GАDnbD_^g~3E=Ң~N!J 9T:M =:i%vf=k.% 9?im{ٿq6~Wn"'b|shv{묟~رo-gBOwd[!B!MЖŘ#OpCxz!=žɄ$HyO@jVƍd*$GqφOXcgV]BG5ab}"zs_QL]3 b;]NAe!B! ɼ;o`ݖXꌡ ,? ,MJE \>4cLj>D5 ۄX-`6m'mdL-tjcp<29S^C/!rv}ӚXӿPB!ȀL&ƅezwOGwKpv񔯡(+IАLā v?۸2m?P!.[GU9[~Z[QQݻ X.& ̑=3[ELFlsp|p$YodF4h-˻9ԇ{[65\Fѭ{MU, /Špbݿ3h# +PN ؉eBgnOgV95Ųs!%_YBW@P¢o$>-VPejMFg1cp͚Ĝ'hs3>5f@";hVϙ?g`N\'O~WΝ%5iB!O8{wxlʴL]$T/(/0Qj[ĥDJ_ǤT-fO)ǟQ`}1!kE?l7 UI0fv ~zX, !.uI^3*/D龈{v ?oI:;3&` pPZV0G6s3ai jT9ArmT,(\_-D螝aԥy[o |+[x }RgUjͻٷ~0w~Ck={#wTɸ)k}^6kCc}l}&uV3 ocPo4 d$5Ul TnA.KrIa VgPα[ IDATdzL?=W1~?\9x(sGЬր !B${$oc'-psqfV>PϦL8>%U߫>W/揠yQ5S%f& SL=߭2o*9V} ʵGO}P<{ͻ!]}!ν>v>J9Ⱥ\hyY*`Dر:7bl[rͲF-<J+5jK荬?$sqfIG1H\7cG<+h)Ҥ3 ƚf8*QicJ`S WD q/X9i1paEĉ$@zѠWwhANR?<|xl!_?g%b5B!o7 r}h0"+"r%#YoIŋSBIЖhI2Y0cjS?jfߞFCηs\MU2&/Q6{~e[R׎?±drv6${lAOv.$FWby !B~( a.(~DCw7<;M"4ޝǷƽnCZ9DQrϝzqe]0Z3f]ބn7q19iБcqutڃps>}J< `LͮChtmm[wCalJ#Tkf4oYѠMFƩEo:zx}< @  g1x6em膴r(Մʟb\|ƓZ> 8^A~Ț!ԨBs8 !B~ʈ#Ց#GѣxUʹ3t7իU˱s_2g1#ہfs\_K=n.xܾ}멪ʮ{rs^!ěa2,H%:'\ "A<%oSf\ArD(sv_ȧB!0Pn+;I1ltϮSQ Q$];'^=kBe/sV!Dn F{|,6}yt{u%Z^9]!DqmwB.@Y\"\%J/+ "PUް2s." !$P"(X7opI?I!gϝ)j5p,H2, H!ǂ!B!^)V!B!HEe!B!" B!BT$PB!B!R@Y!B!HEe!B!" B!BT9Bw^'0"HJJ*RTi4k~>++- r6}?`޼y߿?kFFFһwLvssO>m334}||h׮]`9+kB!B:{l={>$fffF.] % gg,d.]$(BϞ= B!B@@iO~EQѣ̟?Lϱa=zoo B!B瓩s322q)R-Z(7'`E,ȾK.PDɻ#""kʠB!e.\8Mڱc >ԩSԭ['Ndԭ[ӧO|^qc?nk)Kw;ZMhZ`Ӧ j֨ηN`„vw#""Fn@}DE%jHZ_U+B!o Tl4i4ܽ{R~}nܸapy7nܠ^z۷ϠեL2'x'cIx}B6:~8Xr?N{2>=} 5S@L`Uס@ǥ9NP:iҾcW|! T 6󂂂hڴi+c1114i҄M6=4^622B7_6%бGf( iג5jR ;w⟳gQUâ6_׾}x{_3ѰVaL?ߑ@978~=ͬ{(B&(Ң?2<uӣF"00@FnxZna9k׮M{zzbmm9B7E&ѽfI=7b{Ѱ>?gXÏ-ɕ+WfڵY mjE QG80:6kHTӬUm O~f  G@i~߶Ywݙ1KkꕘGmLMićvfZ+a2n~Mȗqٚ&i8zɷ`x|Ѱi>ӱ*Bo:O xNb]iE|ޝ{B!^l<6o<>4iѭ[t^*œ9szqrriFBt:ݻwoo硫ʼyҭtǍ}Cޭ4V˗_}_jL(w3u1@u F,LTέU)DgCfU&o޼n'5Boޣ1=DrײR;A|>?.3d^I=g~ȠVQbaWk=OM|[zf?i2 %~5*O`鷮뮰i`Nb7iXOM7S [wch 5L_Rn,Kܰoff_nvBjӦMgOݻ;Ȉ_ O>+V۵NCi,oڴ)uK&s3؟SU[_{-hV= nBoTSjAkYN0?oN;pil Ǡk%~C'kke%sta,u÷B :SJ[{$@ӺuqӐi2e& ڦ=h]:/[7ܿ;sH3-: Ԧv9-N h+թ٭уv\z{` YQ}}_rmiS xΙN`Һ'yBɈr899ѹsg/_T#ȈSNѲet[f5ka;vҒۓԱx|}}ٹs'+VD1r4xPBF%J`_J{'O?U|=o·|wLyTpͽw{:cҳQA ND<7v'QSjT0kݧW4h5 ,SjhUd#1w8bp¶֡-*MZ&ftGIѻǣ_ZO!x[IEÆ K(9sKҸqcݸԔ7i&XYf޽`Μ9qEQ6lX6Z&x$@ЃL]ٓ>70zH#ki0۾=0@λYS *R i̱y'4>g?/̸Lg67sxR35ٚRO,U*ʹ5U>:`wTJ9IƪNy₏S346Z7y_bB3du9;;&}ȑn:G@f<==YfMӰoܸA6mϏ *\M7nEBɟ?ѹ%-*"`s8J:u8ª}y֮RLv9ɪGy%''׫5<W\}J"L5: ·Ţbo^xt GŌZ> 0gjb4^FZhQ+vWp󡎵4)ˉ?le|@hJ6Ƨ~Yʵx=pK&^ !00z4iќ8q"M(,[,&\fҥi6 i3=[z=E9+@3RvB!B5W69rĠ뇕;vLsww瞿j*oPY-wԨQàB!B!ҒlHowitQ*ݻwgӦMY.'((=z6jժؤIcB!B!2'r9s4'Ofݺu,X01NGٵkڵ:+T֭K7(^~=gϞ5!EF$&&t5r$3'b_/C[!ĻA,6mZ4gggzAbؼy3i$$$cM!!!!16mDbѣQ|yfD.`"Ӽ'zeBdrr4SLAPbE6l@&M*_BB[fҥY5=zHw$̌*V=ydZlT~q䔭v +\؉7opQ",,)sI?^Yo! `ݺuiX7775kT;WUV$''?uLѥK޽K޽:6|d###֬Yf/ooo\]]9pSe 0 [mgee(XLT(&ۛe˖ѽ{4ۗ+W0vX 9=ȈK EO>Oʏ*S+++r*o5CY!x$P6Pttt͸lllh۶mtKKK:tf6lvӽk֬I7H~]v 2'iv"&&&B!B!2&yh۶mibff󼽽ٲeKkpppA5[n}n )u:]B!B1 t4i...[vmvؑ2RP!vܙfMrFҫ˅  .O!B!D tڵ4iժU3J*{nViުUdwkCW,B!$P6Pxx x*+W2{}DTF)E,B!" &-"""TUeƍT^>}9ӇիnH,B!dkUP۷?xb|||}iѢ+W~7ǃq$ !BR^ss pi҉Q" ZZT1bќQ"mYp8vEyz IDAT+b׶I)5{6SֻubV/7H/n䧥 |Ѭ)¦b}rr/7}M]C"/0ggM?gټdޢZΐ@Y!x)&Vۑfe|1 S5&֒al%?nnvFբ}Nܦa(0T- 6rs,orfћ̜p`#;WR8u9/Fѵ_݉rW3tr^-7cZ-~>#-=1~cw>m2G-5*6|F5`R 0v/%)Gϭ?2aanjK#лJ"ʝ\Ɠ73vv/sEPcOr$~}N Ā[<ؕ}lLΘqL-fa|R$= n#uI.'n[{)Ag#HW0ث&k]x=9We3G|$c{khZ<~xscA17¦LULp!`m',Vmyo}яƅG`YMFXbi`}~ĜgL#nw,*ؗƫ4~ &<5ÜQhJw`Fi@|Hgx@.Ž2Q2\%v*9bv>bㇿbuxRbӏM]~<=`l A5L?k#330h=wӖpT mC1C^4/wٹ3#qdPI\#d;[ca%rp. ]zX1>nWG}F_[eCr=Y]$pf}6q*cs?gr ]ސ?YLTɐwh?!`\o\'ϪXg!+ng_?Um5$ZbXΐ-1ryy=Tk#j`fvb\xY!.x$PB! w [h3X#~ImaR~}<=1wcj" k GL1*Gn8qFP ~XŵXGJDގJ'MSQ7sh[z7*LL ԥΜٰHS6/N^ ~e~'{IKP0/Nu(nE<=;ѡ%4XWO-뛄CiB$Ҡ[gi.mxy/@{MoдΔNEM;1Ih0®z>ƠL Sۖl-lVRy`LP";^Dպ0uE%r[Q{XkA?GL;歱nhXSyH`6>Mh4Tjۂa; P'6~UR| l5-X{xq,ea2~-9m/|ӲbF,IB=2Z!x-3[3tDFֆ<,3r<^l ,D6H'wՓ#o07a֣4}CZ.ĭh4pZTe=QQP'uQ0/PGu46ئjV^_?Xx Z%4P`moKZD ]R*G+{7ڪ37}Mgi}t8TsH5jL6\Foܐ fl A_5}|D"i?56sE0\>{6rHuO〣}Dš&Gq=Ds}>5b-gѲM)@ؾ ?`\V,C(C>mN٧W :3;p-x$PB!r152} 5WRɃ5R1r5\fKAIck^'S{|RcOLDviO1 &PDrMlc8xV֧&tXgzOMMW2b]D&ãQL5>$^iV>쌹sΣ@ [Chl+jw:~c,(m;Q %XGpOr+*uOڂ67`og&_4#tP6Ո&66>.C3z`g7bήφ}!yLS>ؔ"xp-,˥mJFk-QY!^z-BBHS8V}dmjM!_>ie†1w9n%pNq)^4/usw8[:ԄbQb!LH-G;Қ|aHQ`[ԾIP!z (o+(< \j\z5X8tQO&e~jZz۴?У#R~mOf0Jƙ3y(SƺDtd_*1~ qIEPu Ψ}e9cA˹5JnDZ`\ؾx)G"@;^&Zok_kNGh.]UOT).MBEUrL&)IE' ۖ\!stIY83j4p!*h[%:"&]v^!6QB!r 'g,m DYǬEWc4'N|tNvjo,!`f )[1'Rqʴb+@u?ɃyZсP/#J7]i-+xp ?Ɨ1XomV︜ql仟\w(wtǛЛR|;+1w/ajjCYь̋zxJSdL0"+AmL<=2E[k\q!Bd2bHuQe>r(==^qx3 Mjr#GR+B ƇY{r~>so;rFf57|"wQUCǦL,SB!rle8-g9/MJMsBWC^ !B7ǃ O\1$5qpB$PB!x6ޅp"-ENWC[sB!B!D*( !B!H,B!B"B!BB!B!D*( !B!HP0F~rrNE!B!]( ׾}I?Ϝ6. ޚhEljuepw[ ǪB!B!2"DXnNxx߯] B!u@Qu. ӝnz}x_w[h^9ɜMil_K ԔmJQLB!B(+nQe{-%01]fFp~ha_}nx+v΂B!BrI2hQ}ӁkME[bgٳ(S!#naцM,fC)} !B!$ˠPϯ.7{p/)Q[zӼJ6&HXc:\D<ԃ WH!e!B!xdK`=q3>^.o~ʹbO'4E~U>9nh>zꘘ:%&&q! J/εk3q'2˾ Ę2q'╖I,Y\\B!x),,, ZʕkݯB!B!D*( !B!H,B!B"B!BB!B!D*( !B!;n=W 6Vt%H,xWcs*Ai*߄d]%t5ojuǙּ1ca0m}j֡] {ȁ Mi14oFC9q4B"pTroPv]ƕ7zu+JC5{8ԬUׯpYƎ_}ŏ?U|rBWߚUUHӱ!U@QhĈQlz8e.(Y* Fj4.\^eME1`N&w*|\LX(Z0yFA* țv|ِ|*7E!V~" |x/:'Ehhdx ꚱ{Z4u|u\KQPx&ryD̾@R/6:{{;zt8|9f̓淕|=-hjh6w%1mګ!TmBYm/|קW'F:ΙIj兇G|@th3~Q׳)G,ݽskltiM3x6nGQ\4sp{WlKIw`4iؐͻ1{v>j{SUL'JzWd'ˑE*;ֳ-&5ش>ui?P'/ w7ww`ȂD$\~| Jnl͐_tV4>!Trwj{mȜwRdH[u|4,=Ϯo}i= Їo35hMjS˽>&h8|;3eOmW7wsMNųNj7e>>Wە2xٻ?{oYZ5 APTVFU]GmjHDb%f"ȺHBDh$z{<{s{ @Q[8ȇO߽Rqz5+]H(K>ƾ&E_?G>^q ]F{|@_]6z/=N>U.N^X6h"iХtBBgˉZV͐n8+:mgBHg%{yyz|1/`n7/6eHb8s,l;ʺo?ޑ~[! >E}75˘?8K{4+ ӝNz GϯOĪ%| Wݽ?N"b B__컯.} С NN˜q(ڋ3h/c'.vwdúxho}V Fk]Ιf8své85=˘>mpw#k-gz8:7|XoF٫u\iDzt>kQ.45M}q&8ouMG'7C =c5Z|@e-rOos#/&> vqss'g2nӶ+8( ©Cpc&t4>! Bi<we ]w}މ1c?NxtٚY~; 6 e i7tScY΍.㖱5h'xr6/A#S+qlº뢯#ev".(ӞD$0+>uT¦ t(J+I ҜY[C[M/- ķ1豘 [m0hͥ ;ru2[eDŽڜғ2vn"C:q{ըz,"to(#`hȼҐM|]a6\5c**1ʟmSheB$qtƟg_8leZ+L?giYﯡϲ "ocLzEV FPA{/wGY>I3I V`rvGGϜ:HɌIgpT| 7/rpk'P}?!xC'ou<~#`8Ѭ&ʼ9*@wu#S 뿤FUzt=.hݥYAT, =X?k."3T*}G7֔u29d?=̐}{ž7q h.ͮOwtWf[m;:q1BHPV(?~6766ݿ+Ӆp-F֕ȶtI~!]veK&4eiѪwd$ȶkӶYI@}aAW[ba9vEr0x?iLc7h%%x3̜ƌ jxɦplC,fl}-ݕ?oOo`o4εֱo. )Cg.[N;ȉZ?o/!`]`ގe x^ckm]~6yVU||`XF pU0"wo>)GwѥqI `؀Z&EiЩ P@B\{Jvo24Xt!#j[>`=%aewRO5϶N=4T܇^a>Ѐƒu56]h/w}qlJGcDGWT/ ulyu`Tw]#t]Gn&oU*td=lwlr"cU& 79-16L!bKmѣ5zؼ[kMx+!+XQx7c^,0n*=١&&yk z~BTF#Cvq6ЫOW IDATglAmV5AcyOi6ʛwNŢ5*{g5S @ִ,`aC?k=P;n]VM 9m۶s͹56I/P_bvY#|VBOSw(mC]~`E)g$0ͨ *,vc3Ԩ'\̫PS ^Ӑ[U4Q9xǽvgOG+tFU>䓦3N,sizvFt ~^9{Y9Y7g=?% z}ֳ)p2FYm,c;%{3[m*:<8#P2EF1iJB(/-x<_}B_[xa>PQ=- I&bڇM|.5CPS 1ׇzN s[r`gOq5ji):܎>̮81*` -y4TB1USt(船C_ 4cBZ`}|]͜dI&c93kfrZR6KagD E7yw=&&)Sl]j2:ɅK[,?xzh:Rt h!c;@WC|IDbcScfSw.k"$rzl:ȕ߽7x*yO;l /MU܉US\ NZ bmS2?KAgQ(EG)uIK]Z2LY+ e 3htٶ@*kHZCTVh=?O! 0_7"EG\lb%A{]nu1ě.,SUAʨ=KsVjī0(6ģzXYZON< f%3y-EU/|nqƑ To_0d! fԨ7)x( _ڪmmdXO*sƄ=ExD޾IQQ>Cs8*~ǤJfdψ'f]ciizmI^Qclau;EJ򋯿xST5V6tPV x&`ugm}g~Ӌ!>Y7cxD6m3=~!Xy/j/ƚbE U2ף 1K}bc` PFb-Fm`Y#31v2_]#d@3ʏ1 F4 O#7㰲F ժe^!S)t K 1b^MPgYOJLM'29괣L3}mCU[3S] YckUlZr;q{v,4{]~з84Xl?.eC\*篋x0qvN:܈ѮV?d]EQ ۷ṷ̃.gO]g~~6/J~jaYѪ,ƪv k/}ɾ,T@!V%3~{֞-JQ$(&bsd_?rޱXo_0d! _7 `M,""ұclHDDDa)fzӢ) q(:+:ON;æUNݽ3^ {C>x<9NߡZ93h=Ⱦ̭(bYq5&xW8a\}tܿqs8_NB~~0jN /G*=~}=Pa]~j<)¯QaV0< Z@D3\ycT+RBظ#i{$wR՘xN#Rx>4__ͽKGQViP ZK%~aص^FHpZ0~V&ػLq ӻG=S۵bLKnŪi%9T64 bؒYiւq#pjaO2/g2nF5ռ4g0f@.ACW- ?i0ؔoKmw>} iSf0STGͤs]#hh֜RN 5*TnC?gjϷS1(^6gҷFzlRKF[1.xzgSat$c0]}25}#&{10x 1ŝ?˾^6 y\56_szRlΟ\CH9{J6аl-(ޛc^.?kE?Pr(&_"1tm,2uBu0~MycX6^)tZbDA2NTZ_]]#S~J`^xCIYZ%s94BzUH83RɬT;PkN2_[0-אv5bP1v7bCZTA/q9#?GrPb բ'x?x{mTzNԏi}*zƅx]+WmwҥG޶-rTXF5lp%W9Gz8S=Xj -lٲWxQ`_;W#89:<Lwet9NSit_aȃҖ?k}XW}&^^B6oi/2ZNl:^!=!VE!l^Pc߾'+Wyi#d( .L'M;a͚5/$Z͛ӹsWBY-,?Ka}Yx.p$M-^q:ݧ1R?Kٷj\.qpuu؟ ;׆!`jYIB0 -ǯeaAHLSPnۉjeb|kBm$Q.Nzf=˗bŋ9rsu.Ӎx}]`aG!=@@RooDt>Ytذaoi6lSN]V!B!ī#B!B!;ypM/^̉'j %;v|e4 >={D%xY*B!Ds'slڴ޽{MKK476֯_̙3Yp![~u!򟩩 077+PBKLs?OJJ 1m̞=ٽ6;vL^OB!B7GtҥPB!B$Q.G{Vʘ1c? !B!9D￿P\jU~wLLN4!B!G{ɠAr}E """*U`B!B!@ULLL2e SL)PB!B@e!(`:sQQ܎!55B!J__[*WZ-$BQEE=B!P))D?ǹ(ޓaJ.;!DC%IB!Ŀb`OSءu$QB~a!B zu>t,_\+JJ*bmmgbcc9s&gϞEQ={ }ɓ=3=,,쥒dHʹp—ZV!B!c(烄^fÆ !B!$ʅ~NQKO__޽{۰B!?O(B>>>lܸyٽ;wüB!I]bfܸq*,!r)fNy֧絥?X7Ůn'hdvlB!O^ 3h3'Y =WqUh"ĵ2._Ogt>,B!kBe!Rupag$ʝ9kF̊p_9:P: }gp.G-Bߔ/Ce!RN?; U:r&uFIТtƳ Z}Ԑ[;ޟI!C{0z=@Ռފ =4Av;|@&l[/V^K"|lfzx6OC_F%tWo-tNndgX;7У!ͺcں++lE8u)e`GoS"ړ>kJCҢIcykzN%?@we%uuc O~96&|1mh؛.#rD?߮Ii՘^>]kIuб7M{Ҳx^yflwóAa4BJOaT64iE.CXYk:z7gSZtςۓB7KRR:~H9~&A:tP"o)uYGlNC!RՓ+:ȑ4{\ʌu2W?v`E7#ڢ@jF8^6ml.&Y| db~7-22(m˧QbбHݔmjYgї!Z3Xq,ε~1jx`ކBveP>2F9[ ]9U JV1s";VPcM%:_ UoGV+d |RV̈́ b22Dݵk \L7mL]z:ū+dVo $xX/q/l uDzn{0 {`0F'9kc5"d?I? î2voeoivݍaQ}4PQ#R-7k+85Ь{BȈQߏ#M##( !I_N:Bjժ}jժ[ES:!/(k6cÒTm'޶}{ S AcKc'iGvƬb[>nT<÷r-5.Jc;!}Qa}5ETzB&<,g&'L#o^Fnݺ72** (^xF'<tÅ9g͝X^ZFr FʡTqKtोذw5XVa:nǑ|v1zx45-Yj'bjsʔzj +GOV5S4ՠP\гq^&΍GoN+EO?Z˵ XKcޠJS[l--wqԠӡS+:NFQq :‰ʢ(֭!Q[h őѠܽDjqWEǝ;`Se-m_lL,)ҫŪ  UGU ?ϵegm_4t@B5Y8a$ɅDHDDDIrA֭ *&3Dl0*kJ^{74NF˹e>sfVQ ḲueLX;6O.ilreKw ؍b ~h-٬OEF߳ó =j.bk{9+-O@!33E"+ܬTpr*ק):dsYм FF{Kĥ@􈈾 E1WnqpϜh@lO²;5ƒquȠV~l+6MsgدeY7p !xe&}`ܹ$z*U/˔/_>˿gʲ.N&08G r.8S:ŰLU*Հ.S'!*sZ|<EQa]%NV3k$]rA>=nIG]Ubk|^ fMYO̸ϝ vEv:q8{P5GĐ$_a}ȵӅ5 q:ktg9~Z@*4!-5B!4̟7I\H|>={sLgK͚5^fM|}}9sK-/3%ptfԫ3q5_:NT;.aalay"}9 z`ohoV0ٻc~zȌCh36a[LLily1 ۞zE01D3&ݕP(6QqrI:*CqyM)qfڅi#b⅞֭iBO0uG47äL=Z5Kf*K!ִ‡cszyCL+ؓ!1n7? Mcn}Z8TBs?c~|?!g 0¶7&T.xdėȏB u ;4հÕÿӇ9Gz8Cǎٸq|||Xn]u --]*Uzn{q^zyx߃}څG(W!!ԫ& iřu:ft75+b+B!aC_Qvɓ&Rxqڴi/Y1B>쬮(Q U<]E~|BZs!ȉ5u)KP5~= !BdDY!DTNK.L|4 IDAT+霯1 !Bzk!B!" .^Ȇ  ;Cwo> &'%%B![ %%}}yb~D9NNN|ׅF4hNNN(RĜϓZء! Q)b^ءuu.ƏOtt4V*P]2~Clٲ\~ǎ\! e`hHѢ!N\l27oɓ9u:ZM>|=Z* "EiB!Pjsss)Rءu$Q΃Ν;ӹ T?T*XXXv(B!"2FY!B!Be!B!" IB!B,$QB!B!DY!B!Be!B!" y=B;wpu߿_ء! R055TR+'u:碢Cjj+K__[*WZޗDY! ؝;wu;U*cffV! x.^xn|.*d100xe1u碢xJWWM uu*S^d!B+f[<׮]gcnPbW$Sb%bnǼj( !D$B!fffyʕ~D{wADY!B!Be!B!" IB!B,$QB!B!DY!B!Be!B!۷o/>eQuZaIo4о:3-]~9-q뵆| i/// /\ToOFd'7 AVzN0%3{cXvAo=%t] ZOF.ui S ;Wڡ4n2ȴ+dQV8a 7>!2K]\+.[eDlݺYffFe!R={q¨f.8\GI_}>8oϙPڟ?Ӫnj?]S n }S d2h99T^Kdܟ8Qg*!&($~{\.ċoWW'V3e%"h>]Q;x+Mt7VIl{]c͑s{2rO>\}J=I(=ܟȽۙտ_+9㉳u\ZN]ӫ̻Ұ} ;&!]t[Pׯ_37ѣF1g@I,[Sn:,5p<:zуa@\[D-A3e{iE[1k_$f k?'/>6,JZC5>m WQ4hҧ+1I6(#Dy nդGY=}=}:yr3U~C1֜ևMhhR̺JU$V͢只TjZ"": ?33'kNRgtܸrjxPB MXI|ң;7n|4o_|||~ o)['ʟPH*yvMr&uFIТtƳ Z}Ԑ[;ޟI!C{0z=@Ռފ =4Av;|@&l[/V^K"|lfzx6OC_F%tWo-tNndgX;7У!ͺcں++lE8uéβL5MrBѠSըH!|'I[.aLj4ȿѦǞmh]>JNtɝN&zf:/囏삳gG^A6}] ~pucݙcݚgQ w`h禸֣Aw].eޟgWfGׁ߰C~lECْ mqmئ@&_$`JҀMd}i2GL^7mG#Ywq'nm>f$WrBME[:QA{8= ?ҭy\\qnCHPqz5+]H(K>ƾ&E_?G>^q ]F{|@_]6z/=N>U.N^X6h"iХtBBgˉZV͐n8+:mgBHg%{yyz|1/`n7/6eHb8s,l;ʺo?ޑ~[! >E}75˘?8K{4+ ӝNz G%ϯOĪ%| Wݽ}شmenLW<ݝފ>¹y_Ѳ3^tϥyڨ 7CO0#/YȂ/ vwZDdtf F; 0 ܐVrhV3w)/ &x~Zr)[ڟLm1SϧoF8:v4tsN 7-kwdίKv V8ze k UMaΛ0[S\i+fm'w{ιȥ-*ݵ)NnoӏهSJ31:i ϧB#77w}/S6m 1#k1,+1sb+.눃i"| {ϞU07tn:J^h_iάD?D nn[XLնoR]!aZNf랽PSzWUnMdBZ'`ں|UE eb /ó+?̦+fL[e߹]]†m߶=DON !A[]~LXKo<,"t~`|OJgvfH bj]ѝuuY M:b1hB 4sLOn4>d/c\kwv?ӓˤC=TfہQ˷w7>1bӔehϱhN϶}ص36$23ͭȱ-FnQ)DN}{ YTVm(vAA[UO?-ZgQ5T/`H7o\|@Zx˄?Ng\M|U4rIu|s&Cjt3]cc8hRv8neuGٟڡp1\yJvq\|4# qa_=Kc`/:t/=9QRaajl @e~ʔ)n`OU1Wa7\޹ښ.SH bT&5&GClze`ldASoþgiNkB #Z4qfm'ޛgcjv=>Wrzziݍai5+WIPb,߉MKc>ESkF%1@cjA6kBevܺz q!~)فM``ґL?ƇXOasbsSmMszY{ ?AmK hֹ̩#"32.|`%u?kli^ tJ1=/ٔ 2Z]R4Xi ._ׁQi)vuU2?֟ӱjۋ nyˉ<*Ҝʖ%6Q=cl-&\jp< `,Ci7f̋=`_fޭy?˹b߃j`kb8Р'.AeT;8r;dg3s-tuVfUYT8dfiU]rM;AbJ3+qbkZy|s6)Jq|޶v QyȡXϻƨTFNJ9uUcL9pDKzװ7Z".Rs@e^W2j@]ފ%f7e}G0WQ9Z+:XvS-:ҷzάj s3w,J<3aoH^Ij1ϝ,w9 ݩf Cʸ9No]]K^Xk@cUO{k[c[\ڣCu{;bEMwqwHg=?% z}ֳ)pзWC!&h4]Gy̪Aq{\9O{;W/we׋Ә E'w ^BOL۔o'|1s-.̮81*` -y4TB1Tj5:E1$.K3*hq> ǧeY(It(jUؤC~l4gfWT͒}ag، /*,=olK1ա{MLR[7ৌٺdt2Z5Y]=4j):?es[g!CФt"ֱr\)^܊;Odҋ (6Y"1is(T]ye)C2Ot,t+UhTqCNۻ(MH4)REI PX+J/AAEP *(RU@ЄPPR dGHX $IBy^p;>{0=ӜJJ^ )ќ9ڡ-%݆ݽ-䍏jE𻰃36;9ٗiI~G{}*`ey_T4 f;cӚ(cYΥ{&:Nɟ"eQc!w%7|ޣiLys-.ˆ]eh0;1[2~&AܑD,_c9ضn;>;& kK00p`?N_j{l.MWK×SҁT⣶a<6< &GV|&Ph5:bx\*zfl>NJ{h}ݪe88ZC5\h;B_`ܦ(xz͘0-eyrFbԶLsJGi/%uy2KT0'(8_:{rLgC[#{wռΦ[3 \CꝙAg?RNF&Mfe~y |ICX^m;w2e<#^;XSN5,?X4^Õco;a1Nء A$ּTg7 _?_ x?J+fz,-F j2=pınj|[ϢR'ُ"ާ9v2*^L=YΑ@LL"F'8Eo&?~My~ś튞R1kE_vNJqWGa:MXʈWT{ b8UK6UE=2ӯk/{K8ؐ>M|/[=&h^|'zc5{m5s2{flVTAdn\7B޺BS/vk~<3Ќ}qEے2l4 nrŎu͕r\\NNs^èsMS;ro2XGχ~gOJKAH*?z6ac&u<讴Ҽ}&CH?۞G#`Xdz,՗xW^jH=wx">}2` 2${wͩ[t MuRewQ~e9-;Ya̹spn~} k~cps.|Usؑ"X>4/'p ܿ7(|N`~ܸ9\op_V{$;eɿp`غ9,ܝ\  ֹ6i93NH#,jקOs*R[,|P&7^1T*88rmO2%H͆?׸"8Nu{8؝|7w-TBgG윉=KS'jD^eChZ|_|`Od7k9HoXqc3Mgyx۳8iLHFt+S!5n7|6!CzϬ^3C r]qg8gxK6{y3gSknQ޲܁dKnw/n&p-Bu }`iMY4)mYԔ>WnabԩG&U.]\ <1׬KEWj<"!Gģs8ˋsCd IDATSOQ|Z6ie,HXH0 Cַe.KH']N_hJ?3%ڇ3fƍpw3e8c#u7qBvm/簮"7+ƗiZOǩ&o#m?+.ԡFtc9>ßci ˲c+"^%/"˘ޱ{J4b4iG=BSзRۓx8f&=קF >Nmص/~Y`5k1iYֿ%5סqkMn֗%>0ep#<ܗ KH}5ŋk);h am,kREVkFōCi\fc810af$Dcya,@yj@H n}f7jTjPWT%-~E֕3N3}~`>dmO`x֦~2wӯWq%{,۾J&uZ6̽;m#̵WjuOw:%Yg<;i EP0M̑JLy:V\X V~oNf|x }&܆A߀'rԸ{XRX|:ġC.{le*U*u!C9`֭4 r]Dw_\+>n~ahab|Lh3DS[ڽ2TszLefL.2ݟ~Ҙ匪{h5Û1{VñqC#wk։ˇQ}X=V+.ͣÚ-H^؏yYY7Җ-9*`_7~X2͗?9`/ݟI;įFw2̸6q{%1y:jTo߲u+uξ6=拔?x3?WZng~wi}c0.ViAC|SO7{Iu4&x~+6<nrܦ)w?_?MKTs1S6=Efip+J('ȭ*UM`.4s7w ]oH!%nfEWHqQI1unޥ.wLsfeYnvV%#,~ζJBܥSRv=WL|6HEPF>nq)( BWCF\\<wB\\vٻS$''Z]BL︬H;s 'NESb<<<Mųl?{D5X,V͖g^X1֓n߈/"r:urVHӃ2Ku4۾ѧ)_Bdŕ}*:WדEDXBBB9ʕbӻ󂂲e' """""""NEDDDDDD((8QP˭_+ժVzݺv2󌂲sbpw-""""w}P~}^xEf9?<+Β%:,3ϸw"ll{ Ϯ y_U%axlB]/k0Y(VM;W2݃SwhKpVN ȇ%"""r8t{GF￙:]Fc22JAYN=䵆fc蚲̪t/W;Yp{3'(qY^?yᓗjqqv+V fы#Y`hwՄQ :${qѭuiLЈS885AXBF=Ir,^aDMh{2Ŵ*V|7IXh(BCiڊ~s`7艼GAYDDDi-[ʲeKݫg~4GYec¥D<͠W=H"L /+CqgH19ǯm5Hݽ:%OnsL*EjL ? fS%6;^E=S1>^ çcBIm_ EDDDeG0fk\MSPSůg*/p&]_ |hC `̩XR - ۣ9~Ž6v|6f>k^r #ZVS9#.fn񛗱tqaW|2.%""""Wӷ/ !C򹚼;TO X_5% _tjU Vpp旹ۛŷ{Ӥa,]UKw~Op avFXٸ&1˿`$87,'se'!6/ #Vԋ+͡.Goug`Ȑ^3̐!C<e;r,#(ݲ >[Q…rMpxr7Z>چ{ӟU*ϽaSq8>ϒ17fSˡL8<7eÛ{?EP_ N==aݏաtmRB>78k}J*2m;tP/_RJUYFAYtqSǘc83`dogl] ;W7y¯m2n5!S)޹O'l=F[( 3ĸkL93}~/1g>>}0oWT)>>=? "wN6""""w ?[(8ш]B v;FEDDDDDD((8QPcPͣ7Hsww#..>;@\\Gt1/' """""""NEDDDDDD((8QPq,""""""DAYDDDDDDĉm0.ADDDD$JwEnnnn'w"""""7]B|nn .]LE:=w9"""""7EB|GFQh.%mjpп$&&s5"""""aXbxyyw9En#V5#0He' """""""NEDDDDDD((8QPq,""""""DAYDDDDDDĉe' """""""NEDDDDDD((8QPq,""""""DAYDDDDDDĉe' """""""NEDDDDDD((8QPq,""""""DAYDDDDDDĉe' """""""NEDDDDDD((8QPq,""""""% jjqv:Obrj~s[qs5@B4X)1GNHbcbINNΣ JRl9LټgEDDDD"XKPEqz\HNeˁsg7r_$ɶdjԨbɣ J6[2{CH*kSyoB (jf"۾1/_A!9Y,/_ؘz]$19.U%G'''cAErݧ+(8QPq,""""""DAYDDDDDDĉe'yH>q8, b"ElmG0 NQW((HIN!,M?{ҵmk zwbO8M. GCl\z`Ӈ |'88?12Ñ BG&.O)(HHNV`f^Z֝"Q'f}1 È-̲#qFM`RJ$%xw Φ͛/k7L}Ss"y"'WEs1 ˳k((HK%1y , 1\2[Bh]4B(]GЯً9yEtrl8+ cSUp_ӭԮ̈́:lXa{'X(KLdS*ZS"YKc^y-7Mϱ,؛L}y>ߴIϴQg*ʎF>ܕV-Biփ_\ư~{".Ԙf_ۃid-[ѬY :c:87 #4!Z=16FL}S}a4oڄgәh_((H%%戁tsهd;pZZvTžxxr%-ER]5rJl8m jۘeKؓ~=c!+W.`Rp ?l9lO˜hYT:=ܑ.->aL5ή̫35|ϷoLiqw~jĹXϤٛ蕌t2Tdz 7LǏ|7I"3 """""rS|L>tc$&1ٜ%9g&卧 Q&0w.$%6;| #'"QELX+Tv;v31MV_/TJ?k2co """""rS4o`ܫ}0M̘au!9MkpylӇp>:C[ =.e=%,\^w0jh]+t^ֶϙCÆ 0.F<י,²\,KlǤ{rńg?aStDbc/5-d&o%zqٵs@F?nWV8(IڄjjZG}UE^MӴu{#_|?"7Vtjm槉cX0ɩ$E+u_ {UZ_^| ܭ{aaM|8nծU^~ >ˠE?ڼ= HEoGJ;.יT㯯w KokLsZk:o$)@!j5o@ҏHNU~{_?lNE!*1oK(Mդe;B媗^Ã{3|udWU &t4ZTȢRF{3㝪 [pβa;#yO_w}J0L7>E*U7v Fï8Na<<姚iֺ6|]A`vvqmKH!+JL>aᜱp/^.&R>ߦ3)C;ީ$\xifd6u&EsؚWW r[ q 24GlJH\.IuԨ^=O^_)efvZNG}#/ʸuekێaaYdɹxC#""""""0 :oOq9"""""""NEDDDDDD((8QPq,""""""亂.M.w3"""""w &A\\|n"r:w.deܶ.$jζ+6-*lɸ^s>E8p.uHvρC (Z,K*Xl9pP0O.–`~yyzIrX/cوuEq1Zl6PA)o6cծ'idzxp+ζo`=;~m۶jd|G>IDAT9Y,^/zu=ﺂ2Y-y[40 ēzqf6+۾V0"Uz3gjjw)w4mۛn%""""""DAYDDDDDDĉe' """""""NEDDDDDD((8QPqb9|n:M?ZIENDB`kraft-1.1/manual/images/en/followup_1.png000066400000000000000000001711241450127457600204240ustar00rootroot00000000000000PNG  IHDR^f pHYs+ IDATx^g@Ggwz.Ů%1jijL&y5G-F{6TPDAݽlt:AĹƥ/Յ K͚57@! B!PcѰ! B5Z<Z#w!6& Q=aSA !B!2F2l%!haaà_v/k_ͅ}G)94#d®,x'4szp)B!jhcs.=v`Ν{g ͍C;^1x-#)j{FBh_#y~svhS{~3WK]mw_~@eUͽ7hT*PطB5^O5JWW*G:; W6ݵ7@[[f Y V~g eG_:F6m4j-Q ^bp״V<.y{Bׂ{ȀKؘ!}9m%>d*?u-3.78g!Syw/叨tԱ.^׆?q+_#9nڄ7@qa) w0gT3u(GQ :ѓ?xÄ[,FٕիVI3*3kʜ6N.,W3_Cw]N/x&_"R5mO'M5[zuPXz+A!H4bøuwn )*\?bۢ],`W.8~S9yVZ\ODMmb/\Wk)LMZ51G2'ݣ{6 egt[yeX{YtᢡONn;z+g\F",ƭ ;}j#[IW眧o>|>>-TEBF×g~]Ke1e9L)rsEmk?E"WqGwOcuzJLVW0@ --LsuМrR̤,)WE%R T ^UI]ţr 3qQ6oZ9sP@mߞvKfrׯ W6 >SN?̝; BUQ{wpiѧ,R}b [-wlL=~_f~](`;WwJL.tnGe^>ok%:H~D%Zٵ*2l~I H2btrN`4yU̼֓6?}k?-= ]>Dz6i|}1 B@txSsR.n;&ĦVn~m{񍧪_\%]w8!y 蛩Ŧ_krICiu?h5EÆ_ۘe#woM0w}7]k %%;( Dt~)}>)2n޻[b9ϖMcgw7̰Ţˋ>sDԧsDC`z7}T0͆|&wM<ʹٸ`M E!!;3[bu %*(>zʿ3|?n<PGDǦvkfVKʋp=.Ev-;rSKt^îr$q^)snmMrá4_1eКvv*;s%6M%vRߐ(Pg:ԥ}nF\KS]zX dس/չR.=4?ϱ1u.J웶 q51 F|{mfQ~Ӵ4vk/ɅD{rwdKKE=K/ytdxs8R =c&Z2*=D/޺Y4ɂ.M[ǜ5+~KV ;;ʣ繀Z)" dVb4lGޓ7MYBNR3|֯Q"Rӥa4@0=cm%Ƌʤcûo3œ,Bܙ۳;v7fwz+nߵ)Ўح~n97 {eosYtP(*v$n{yٽg/+7˽up9aчI,%?wc oŌo+@?֯BQ4ME431)gӹR_i@/lپ#}[cv딲SZ eWkpzPZz̛eJBQ%Ī(F=䬝\T,ċO |y! K(UcZݞ;+촏]cKS%z(l:2Hr,Ը5vQD~z/sj͖'_Be_NsKAZƷǴ5\eW(SkօYRT^9}?U `fό5g O-Gib*u -SmJ[|84%eݸt&AݰC!y|,V[dE0auZqT<0!"*]򊣪lOu|>n]/b}%n3G_|HZ7KV+g|s1rw]=5A|I< ]-v[Xr^D-NαlپK' =uc2×a=ƬYs[}˴~qi֯[K^Ce$jiAV)8߲pĺ='6d.nXucP-f;m!jP>Mhe\M~;e%ʘR͝D%I@aiƯ6<|zjąǟw{Jі.)Ӡ9Kl[{;EY"oY_$]zف3lE??#iy;~?p;]~v.Z:fT/:+W|4h'kA?-P>g;h柧8tVm?}G] vf`}'>YwՑ\A3w޲wג7ǔ\ؼ>ֲ#>_0ѹWxּ%'J;9PO\{p_K+v 1ӪsnpmRģ"[9Ģ!M}cfܻyO'l6f|ȪCm#P]u\8Yf;JE%nVV|6vrٝeܟ1$Ab^:jh'? &.bm`-巣܍QЮ>~K;2gcpŵaFJ݆;k FD]b:dogp hڲ%vWr- ?"TXeƢ]H'ZUoQwfl})>e{PD9vgsY Pٔ; 1RnݷjD7zSةwW.۽ԅ$s??ˀ n%Kƻ:j8d%,l,jBEbCe$VҨ@Kz6]ڡgGMXes~5OBRDP*<@(IBkj6LtB苰{}_mLB&JB_c +}?BsjZ5hܗI:mcbI; HT>9q1'lXqĊ՗0 F!\fVV] ũKIkS(eg[[+S>dN=gt+_ztrBܽil&6M,*Q!Z6-=Mf|%{+;[fF}f¿yz {IGS6~bD;\/Moׁ @XWck$e:35J&AKX٘9͊)H O6S/ ,7pNjz2fEӒuNF&S!@NԢ8:|ic~[8k롰7R4 gB۹1\Zbb9qRI,2v6 EyJ oԤGZMj_>xWѰ"yYȸ{%._ggAqhcf,&DK7O(Shgng^AJfFh~5s/~ۺm] q{oǟ0._p[Lm!la5AI]5/+bĭ}[ /^Q (ʼ]fLt+  a[d-n1,ָ+wuƝ;sй~&'6};[݋v5uy+y,T %kߧ+fRĜ;Y@E?L(FXEqUVLN\>KYYٵu}i!Zԇ;p˲~%M9VczʞR={uٺȼq R:ݛ۶w@/ at 1j-҆ IDATbRzhCGwd@ݟ~xЖksgN|@_J|d[ ;oɷK1ޚ~wq9[ܶ\d?0X}2h:G8pZ#q:rn64.An˹SP1R{O4z/ʳng߾X_:簑B8ۋ]ڥWg Zh$1.nWڢz9w~^ٓ;Yo?z9;ЬC{}l;i*1ٻUkY=,xB{ { za\N˿ҡψ^~EB%h FpIIsFr2Bh oG6.~w6.E! <!B`4D!B B!kBѭA G?VUovk!P#qz%qhr[Xᶪ'VըƝwTm^bD!9>p@!k HYhBDXw8^{5}FCBZ\mQU[GF!^q5j(yXc!BGE'!Ы`g\bkz1B1C > Bj yx<!ѯP=G"1khh<!Ы8 LĨx -(EQOFCB W-&('F"b!BWq{gBUJOjW ?BVchVL>(ol% 媯ϗIx ]r5';FN  wSŏJ?Ms8Q%OܐRcӬqUC@D:S> n/5jNf]3f`YJh OrU5r0])W֑ BN?5_Trb*!#"PDŽ _|4,)Q$%% {3%UO(O$ i!e͘$@frT8OÌ5{6teZ)-⸻eX|'inmGlm ۙ1r+璕[RuHc,#TvL Ͻ&g_Q[HZ)Fk4p& nlAb?^fl~7 sJ[-aO' 8|+r,$p# ̄փhOFWQ|kSq;A@-d]qEo"?ncӦ?6qrwfpnk!yb_p)٪շT odt %5ݓD db0+U15Q'6MV;ZyHն-$}M=w.|+fni9Q k@ ?v݉,QEJұ< kǗP+Lɞ' \eX&g".5>z2jVs#QRi9gJnv&߶`?{ҀQ-F5@_ƕ`9`b\df2 RWmi1E_gr|N"&ϰV3 UKFkm$9ǔ!%B #0.EOGv/Cqx#1JS QB*: %z2-L:R/JD>[%qѠڋDi"9k_*Z&c6PeI1:|劇O:^LMsI{*QVP}Ms[a[ VUVZRG3(HN.ە_Cve>^rSogyIiior/EyͤUyt[u}mlT6;с1-%*'L{ѧR90,%N5.*7]t%CL\Ҵ >+{C q'_h)!%V}TrfeEq'o_*}JP\ 9 2ߑ/(6E|h_#L'UB!<4^/'Rcy =zD+I[H4S#,lTdjPjD,4/Q.ZjoFTO|hrg&-xBuxa=dfaқn"rS8Q-%?"+p:dA!( _TyK" -|Ab.liRJmƇ:i!mN'u3(sْ2Ҧ:.Sq@ ꈆ"Z`*^Ц'jSm>S&ڣ8< >yXr.(j)kp#?άRt8 n]& .r!7su3I ֘9;ZQI2(cLU G-,E`g'm8Ή6V V|AH[MXHLWvkbmmK,Dc Z(B@*ɆWpjbFMU\j[ۘuocux(%rEG i+ޱ2W.(`QqF UTUh/!q@hshrQ]]"2e`q/ޮK%UZc+hŮ"W[{$;ENk;+D0D@1/=4hD-tev*)Kv@ZpHz\s_G+y,Hi+ |՜&_E/ɀ+Z6l%xs.:)/hRlDA)OQ Jk^Yn:S$mӗtZ``x(uemmTF?BJ4`.iX(B $'L[Z4YZU)1)4'Lz2RGރG(`J{1_25U||XZ@B wzኪk&:F4X0ͧ$b֌@&%j]!,is T`PyO.) &BG*JA_ ?DN_/qÈ#'j ߟS:ie'5 QbS@S%!xH䢑(1C1|Œ Qb%|y۟pMsahW[$:CWG31i }Ts7̝oE0=˕{[V_>tbdEYkX!bρ~nF4ށU;uty (>Gj-vk^Qk2]Dm5'u-)ƨyx3e99WUVϵaOΒ^6e"V [QׁӝH'!-~"O9]C2-\T_b47 _F 6Kפ$F<L0ĞgbBγe !W h\Acp {KL 'rr/9\xLl4_^W>P<;k]4񘢨̺k KAfTVl/#HB{6dKd@ؽJ-%KzLhPTfI~zCM9T/>o+R~]i5h3t'F}:; q|q) :}U.+\Pnz *eHpk#3 (sÜzgIB~(83ȋ+%PFy`4D oSꜣ<zq* ?Qt7.Ϗ~yS<!%sƅ; :=]l? l~k,_ާ2#{κƞ+.yQ\[]^N[6h>éMMkUSG!Jhr%?1 \~g,-hۅ}phˆ֪8t~^ր9aeD߇ =mo0wO;Ӗ^=#V8{de-HdA{u]s왣CxƤzB20K ܔ*U.̱6?`JCy^w>i)'us|Qzvn)Aэ72<.̌"tʔDM;{ @;MB6/yV0u|[mhaA}jK3jpc']ʌZaW>&Գ[gG,0nN%W]M+M[ԺBaŠg(׀vW$&\QAecgSgѓJK Ԧigi8`sK"+ʢ"n1 q*]KS0qP@Tܮ0Hjk[{ |++1of]{hk;+mBAZjaQ!MXv{wmV}YM!dz0"z=H5$>ގfTeL)ಳr(@ ̄fq$R4VW\T=j5͛E@] %P۬5hn8T֢x$7|gNuܴ^}ڴ0+G +ǽWcmY\Nm$'gBU?&L* Dz:~d{xtߙ'3|h}]EeiK;E[?CNjnug{}Bzj.x [o9vm>@ N}~-B[.5<<ZenǴczv}a)Z?>e8K@c IDATѯs[/+ېYN,}Rm\m=]0g3WsC @.M; w*ݹG;zC{ B**ǐ*t:e92B9{ y8م?O玬̆{(}{.5D!tu>NgGiܥc˅ߎgdABq\;>>v;8EܼJ& (q%&݂.qٜyQ[@ap笰}wU$0}{rkvpZŊ~w"e'͹vC5RI|Uo}?·ϣxoDGK݇|3a? ! PDٴ ۶J.ya8ؑ;sWkgBeXh+V$/1Ar?<{g=ooMK~`źؠO4z$?~;w  ewO[5S7&i?u!n'N3w)k'1GVMZES[!KPGg3ye#BS3AyH ; (Y5;ĉ,+r4qROdf]m^hwchmϼ]WmF^ǥLNG3l{t 7/PӧUH/Q"';̛%ζbzB Y*P=.3*ט)NQX@YTAlD% EEyDnpI#œ՝D"mѐ22\ofkh䞍[?[yG BEDC6ҩ6ce(sUfmLhJhbJ rX?I4MRXEQ9y|Zz|6KBnm.?RH}$hlF즙/9gb:OB58\5.BEC++LrqCYea϶uD]8/ޥ [lg&(K*rʻr鲢E`'ҫLJs}?Z\ٺꍸ+M$R Y7Kh3 Nn8!k /^3y2ym}[9ze߷3L8 o7@wA&q^9]E 6"]G" `a vآ(vwtآ*"H7p܁p?8773ٙYyCOw؅m_=wِC.(MlS9`ѪKV>dvy&Kߵ|L;:w {c  Ȫv Ť}Ȫ[ ߪnp WD7q:4 Fa׉;vXT/m: K^G%,|"g͵!w> aU)Z[1߸7 m=ĆQg WN}SDiv?oNVPKS|ӟss蚏&Jˊed2g~_k 6̲IҺj}>lFrM_qꖗCCpU 3e8G4w_S?ЧA6{:Jd۸u8BzϸXAv\`2`^C_lM'>saVΨWZp,$!9;B~nǤȚt >+v\b#_t@/x:rЁ> AhF$?h|Gp! 2'u+M:mCQ2q!3kjG00!:qC _Y]U+&-Ca.CJ_Ko*r|׀:(%!_u80%=M/c*&RC'--ɃB GT7eȪ9 ~t'ӓ8[-beOs2@6d9\O{˸e02xuņjD[5w%V>w9ȺWz8YQM*m{̀;WٛM9񴆵Gԣ+ܬtozaɖT Y;Brc.jeJ56wƫ<eOhmijl} {ܦ.lܫ%Q W+3S3.gudebvC%×Rg1m[S]V_}E.b;9XR ܍l~mϱ:J/3@6f6gjV'Zoz|~d=mZG'M0625fZNȎ9ͩfV ܣ]l \*bGZ& {'m{ޔvfVyMXN^7{{A 5PޔJ58gå矍9/( c),/(/Jܯݻ%J22F*cFLϕ=FϬzcԝlé6^߉ώ,ۙ9|Ȕk~>Kt_KwI?޲:|(,:Lme#+8#N\-jyW{*ϴ|KXo,P/eGoFDG27݌ o^wJ6saD Ąۜ ;^*'2:.wWmlx\\>%m1b6oVw`P>k evć'-<L\Y/SDIXkd3g,Q0!&;/Dڤ{$0u@]}0rŅ^99c>u7bbB=NaLnE^u׬#k(1~#:W>f 90,>܄gA6<9ZavL䵍co]%̷c柈 6Y@Қa]~ _Keߌ[w):>݂ϵ2g!%qʍ?btnj\ZYxώ?䍵6]s`O{r*iF3Y %|#I:n\}d{kR+]Ʈqc#Nw/5ZsyJ;: W3ヿ ygn pwYHys1 h-<|KhXhzsq%p]d-ӱ=Of(y߈R?^Wֶ- aeL|Woi^hzg5y|? Y@nLj_">T*-I# 6qqӜԫSv5\*ؕģ:UY 0ZJ @%Fi_#kxY3m( WHN!J.3եo1{O߂g@.j.$~iAuȏ {!ܽ'w!7&c(KfeLhr_pѱZx+Dkj)/(*=3nJ8*vZ- MO,āKbtW 0YަCxiOD,l1`V8,b>c5zxnR*zl,'~g JcY hn}7E1 'δbC|t9 H;gMn>:C xW,J]LL@[JB9t*|/a^ stU.w Ӟ7(i*)n:EAn)5xU=y*W#EGqϤ: cԘIsϠgιTH.1> d&7uώ.ْ^>8`flnn>~i}e!p%Sv/ sDzzpXnYJ l5ILVW։ ИjLITVTҳ̲$NIk$k+&>)iں.Ls~ӷՑS JJ8'$FPVFÇ3+˫oOe D+!`I#:JՕ59IJCMU 止f9'/f3Z>&.>LDfD]uL/GRJ} +RJrȈ{q}XeI4V2eTڊfˆ>VaW:kriέ`i*0Arj>C(^kTkVe#C6#SK_)8A5=xw0qkchY+=qO4N<˯L'PJcI( %~O҆n$$7poF#pپ [gAB Q\`qd%r[) C0_ً| FB0!u) So;8nQӞv^%L?ȾG|w{s}OemQq  m p!117cbnC,a ցvf ."&B˩ja}DC]#./)k+jqXڂ,AQQJey%{356z5@w-A}gE7DZ%DkJZߋ(/.瑒l6s讘zqZLXJoW*-+5s`T@=S1QuGťZsX01ڊJ& lgͺK:P&jC&"&ʭ`ў _ K_CTH|SFc$,b`8Ȍ}Ϥ} wn`bȚ7 [gufQhB!Ob1QAuNM==s, hYo9(ia&zZ`\dsMM|?Gu+@g߸q5hKnCeDHs$FvWSUBհlV&jF wof\8}̭;5Ɗ*(+K.aQ}T$R6ÙxjF-)%T+%s +4 kuJZOCGkQ/n$QJVma&pBZP@k$ԩJ!|I?H_CV]jekh9@}K:ݙ7e=aohohoda+']9?^!3,P'J\HCƦZϏbJ44z,(1ҊS-<Uħ6g[\Lu ,=v'un7Ѩ6 ?!q)A&ꛌ'EVOyv χ.6Ksu~MdÏ\ܦZ)gjС;\gl[QpB_lV3o嘬fSל}V̉wܲZvÚjl:>odͻ'֒@H0 $㋇_t=~"=}³S]<<)X MyWgG74s$s|6jKΞ!:cbMs.QZGylxzv`xE;'P]vR\sBnwLb3,W% oYDt{J|ӕ01 E=N 31uV7虻?z S;¥VZs"%hӖF~)FfߠEPA!.}Bvik&ٶ5`0+*%Y~&wu%  ȏE$Y_TX'_Ǿމl;\oֆֽ87AgfL:0.f9ځ ^XkCrNmI#/- ś^Gr~3kM6N4cioʪ  ?Yc&͉vYϪP!0\Ź/K{1mg#LT?:o SVDYɃ]QhB˔ ۮ 3_5Š޹}z_%|*UJ/E*_a=ZߝѸF{]C7I o4}uUDT1 >}reuR'/9=QzP}u$4]o:~O:g"(8箷8pZgߣiWZ<=Ǎlx}kl-M]C%Ẁ&Qp]'@5.T]izqu/i7?8bflllRF x9뚹,:,jΔQ7Yl1JV_rtݽ w$T3aC\Qp}ʁsm5&|eBՙ%uX % =V]0˻CAe>UgRwM%#\Ň?J{~>B&/,]56iJ?X6=iY$og&2J@_~gZ`TBBbV]@Y{I`kIwcn,5lM.?pu\Vn$$nW}wpd9 @_^6^n.ŕ{T\w""!1tJr\[.(?x!oٹJ11ۦ+i\*̏A~W1C?ɖ!q3smAAnpsAYG=<6}P7ƣ6YI~%>2K:KC0s&w'ZPEcDU$m=LgU)thNzYu/&Kkh ɪ'ΡŀGVsː|qDܩ<\R$>gp)9JrJ?ʺc džfr)ܽzdJ bN#EpwYG迎%ĥ$?_, ikoO"|<%bYH6T~[gkjj>;G  Zjn IDAT#W)uy .(!ނ…n{.#+MVWVcRjO6i^\|% a5 ʊѡ8QUYIJ7eek*U5Lit k\\B pDŽEǁ`,ly7l?m Ť$" . N >.,"TV0 \}B#>pU骟{~:ߴ^rEO鋻  HlԬyy qGmˀ%eSSxZi0O^GQJܣV]ƒNaC(ȆҒF i .a1QxE IC^7E\J\`}pL\LL\LLBbrvV9JWTQ=j# #H ᫡AA?Dا5M &ta#YO>vDZlʏ<~XZOPMeKFcy2TWr.d֘&ƒē+~[ v㱅$KS^|9hίf]zAG$.ۯ7=+M />fSG u6糋:DEhyمOkRm ٰH҆ƪ7yg}C/D+7R{SKFA{d]Vn)ZfΛ$=4y>i6CnF {ךKa3ZslenX^ޘ[5tMj.+μzf3Ypiu~NؕF3Tn4Ld频u5u-<=&1)s/W;:L9{]lSn=;TcegTmu%U=9 ZYTTL]iL=jMdۻM0;нQyH%=%r/J/CO_Wu|#o7bQ4lW~\wTŔA޾x8 k9FQa(e]SŻ^u=, $(4HZ\I<}נiȯ z>{itA%3ܪF=zpТtt 겞8}3<h%P7^KJ{{j ye_\}2N{kqq0o_lwĥ"qU>i]A~{c GwݢϿ/x\z*#==AY=6A 1LXuEE">p`U~ASS5.j0LC „>h鶭[Wd41PWT2r |ޱbWؘ/ +dtHDgws9S HJJrȚgF wA~2z  e `s :&,PmkGَiRz}e{u%Xoڂ7 OMqO1ǠEXLr1"UIv_߫-xs[{$sbfZ*Vax^DiQ 3xo0;t^3 Dsɓ"4i9tdsIX#}:#jsߟ]x3bD+"V;s$l`a( _6&GuIGJ.{;:kaB>|[3ꢵiVČq#IG,lώv[n}:]ْSk-Awu;CZ.X0`@S֜g^f/y+=SQUoq8q \Ko?\cC:jLv- 0ϴuUWh\TE GXC|e;˽ c@飬h ,'S>KM 1M.cӖmhwIsFu CC=YE?hF:@Tƿ⸍ڋgȄfGWYtfx1rv}`' `fُ3KPFσ;ÎqEGgB>]nV$}ȔjCnabPHK,Q ԍsuza|ow'ox{߮;z(m_|Ϳ!xǖ ax&oAu]&/GojH655$C{}~wMGGt80xUGcKK`. N (F+omGjAY~ɐՂ:v2*J+kSV%bAN?)4%~8Iɍ9vKUy'\FNd8`8¢fF)@$8f K'إn΋:qZjn AV0pv;=@4@ucp )̚LG kj1'\RZ%똋f :etc# CCq_Fq ++%.4f@Pz52{ 0@q!e$;j:QUQ+>TO,F8Q~o3<0vۯAT u^WWk@#qy;49r&}"}}&%%M4… rrr4\]LzS-Xa "uϼ9Zuڡ_, 2p8@֧_,qcZN% 40+ڭn"\\N\bցc/JIYR\IH1q7eM$p%)%!;q{Z_0!S>v(#V]\ )D2^))!"}:0.n88w4+dfYjteq ݉)S^+z),tn3 ,BCDDJz@SЉ)ҟЮ Ku?ucWDrc}uBbGPd[\TSLELBkZӳ}<;***ʹ Ye1}P'hkf Pnjũ,դ;oH0b`̠gNR}F{"'uGoK ~loY-:2tȷ^-UiW#9(u8I}nL}R_Me:_mFkjfta&lΝ.&Dgއj3iL@5W&k[4f9ci4 @|΁&X2i4aLxf~+}lP2|+m}E:v&RS=9}(c3Iҫrߕ1l|TBɨ-2f}^՘BCEl%NyVc!LS{u>!솓VamG;Pq u9L`Cޏ/K#h̹y%dyt@bAlMWO`u^Y+ƒT/D7׏Ņ"6=7, @4y]@I ~7\ɬb-Uy7DKuޣ;,XOC &4?fE&܊&N=h,}+P[cqz'hΞ7S߾]beMR񣧏=}|.qa{ 3T`] ;|ay!fpqړ z*U\\4w}䓖Wzvv-9 Š޹}_{|k)˯0lxJ; )w/7][s?Qrr㋋9_4I)̺T]m8U5Y ; ̬K{gtcm0NtV:m٠bBs?qcu>aNE兯JT՘p՟6E(2+Qs+cz ǺO3/dn2"&N]8\#Q_u<:*?Qv'C5M ǟ0*?pֆC g̼ǽXe{B=?N{V}v"%"'O]ۂ*pk{:~#5kj۞]GSt,$|C'(7^Fo_n >9M4d=]\n^Zfn;"5s[#޽W;hR]\UG~SnD)q cƩ['AoӥӞƹvh:d=mr-!\'kkU55Cc1slmqZΞ7ﱣ66DQQѥKtް 1-fKֱ`σVf5e__s:E@z$_d0JS8ػo QvZ:ELeefL0r?S l'f=:bac>mOzaL Lݷi.dɪ ;ڛL_E JC)nسb 7`5=E麻{HgÆ%#`m>J [D~Z*zsӴJ Иadu$S0k_i̙i(?u+"6趵PhKg<=v["M)F~V}/0( r=%zWea ߀>6Xw}h 03&-]eOuSz3x/.?SeB5 ӷòЭTAC=\tsѺmc7J[g! 5F-3/?x*ǁ(:?館}Vto+< :5df[xQެkv>: df8xoqz YRRR>~ gOjZIfݫK@IuO;$I =G<`)1@Lll/ąl*J*J6w)3T%)@ȾH"/!*o, inXΙޝ*fȴmrq B@6a0t5)#T$KVGwc ̰ ]i87hL4kye ǐE6W"kj q1Yj6Tde2KSϏR64uuDۼ;6LT\4_JJsll,77@Qz/pW%4(BZn~K>wh^e&.ggWo͟Y)Qѻv>|Wąz^uBGJJ{Dey%c̏5m3qYidd>{)LK kS feye]zTV\l%hRma'Dn"XMe?[M@5ʣnz EEڪSY[U~.;KMM511tR +6]sg!Hsz. ߺu?1޽qa7pQ1ZNe {=:b+蜾r8YZ1F(DiI&+pwFmMڗfS$$$d7Zұo]ʈ+QOhtZv!ư/E+rḱ гSˇ+}qW=c:99q" H555:kV߻GLL,11 ֘F&I$P<|y DRt"b•9o*"8dk]ыCK^bN\<@N<(k)?bMk=q阼0 7W_يgE(Z˙{ϸX[ ;Nɨ+xS>/m;wɡ|Cl<'PnnXZ:^Wڦ7w~Dq  mbbbrrsŽ/;i'Gھd5vFGjM&rg2aQQgS 5!^ZjXtℯL[/;]k.gYj'.8cf]wg)̀r}kN]^ 4ِqgjZ0,uڦ}nSbqnDz$u5 ^k3;"9}~ ߄:q966kL ?(7<[~t=v.HS~ҥWgV6daSWpnQyLG#/1A|_ۘ5osrv۵skgW;K'jȣ[0+_g+-8yrTeFWc7܌OcRvdL:oO{;.1/ld VHJ 9@ZC4u|\wX3Y}4(!%!SLG~q!`BCt F}AOqvF=^oΞ3szpGl4t8əNV/w]=!ޝ*7E.ska"*γTX U*J_Ko_} cw Uo8`tꕍ=鳶V1Q P̀AC'-Jlf8͂j蘈~wk}<YB=cZ\xBW[;RO{0F\9-9b?0JRO ~W "k-u$u)<}`~Ν}n{v V M;}O`\?k[oV70\F|xr灠&Gb-ކ:w7{ޠ I%eC:Yp- dqY̶C>4 ^q, p^Z+vlBI-b 6K/җԀzViFօ:W/r&>.4:wBϾ­ESNJ`DK{\B'.uUt.޸rqYmӄO&du\iZ0u/1EF&VL*i"?b߅*꛹4֮ C9g|{΄˼p!ܬ/(Qp~[@'n/٘5L~9%>{qYl]g]Lֿk{-}5&й mC-CdڅzYym+ F_*@/J9djRtNYo߶G;***ʹ'ũ UT4i;'vy'\. zgw &DJFǞȚ /MP0w=:_GVcK(ѳa_2x0ܴ¼7SjI^4a/!֏GQ ߋl~~"BRS6ByEQ#OfA~@yK~pw:^%u#r\c~XE=Y9; 3GQwkĮ+]QU:ρ~g[LEf΅%COls+W'WxJTlW.oYWbŅ]\iե&-=z!1їk(+a'G:@Tl[us  >@&=}YczF3;fuάGo͟?d0 +Vv؄Yehn5<8oly NeqZ3#Vb8>nOV\co?yIJؙub>= P7}Z;r/%zWQ8ӯ<&>>hnjqӛ[/"NI{*{PqgDL!.d*Z\PLP[XOL"/b6J.3եo1{K~?ӰG92rMa?bH3]xF6Q iMxZv]I?|a̫oݭڹw7wWƨE_1.I̝{̼yˉ|go. ӧ\Ƭ7\_Smn=B3P=Z?h亣!<\z#\v#Xݻ}@ q }CONpնYJf^m^*V=Z?gͳGv# gMӮCnl̼8٣Wn]:TsrZi'&; ~]=&T(>\kN}G/=[S҆ mzJZѰ3o>s;63ȞE,ξ[ϡӃ|*9}FwvJR%ivc|褰Q?gXoG[{Wŧ><4˽[W2Ϲ^}u) rfѐ ?RЙ 02-B'MLř4* }"GW[$Y֋j ? #cIvN?tƃ;]xOrG92Cq_{ }v]HVHЯ|*8CeƸpU(CEH:J0ٙRQ Bhd#hȰh9ݦŊ{ƻ`hD.g̜[+G } ˗|}gr?.HNN~uH&.Dܻ}:Tڡ=g'Jo =B'S~ ȯ-7sc,~޳֚\h'P8xc3Murn[n۰%~嘬cmja|'j葿L~GW]e#Yi‡[zsn,4%w7xa5  t >»QS0+NkL=:sc G[ 9c̐z% Mo͝N*#oNJ>]VJn m$ȼ?軛'lr|^zlc.tdI5co93hbpMgjnn\mtqDK ^?5ļNe@xev~qk'=q9j=tx-ɹd^ qs->/u˒{;,eu[şyۧE2opiӦ(vEI&MWWɓ';885RӤ`>Ϩ"oL+VGg 9u>LC]P%[>Hm^\'/{ fˇ]^bD 4޻uɘׄhcq!tjJ*t1 ZR(^1ς#3~s 4ik]kstaM@!, Pf$( <1Yuf;v#Yfs:ŔYeE76ZC3jTr; @T}C}K(ȤA*#-S'EFps* I`))2Q)*B1r8W}1iIa!."vAmY/cngWuZ+cfu`>\,C^T@)2*lY&_B=}t18J$*ܽ-nB} aahfhs(VTi鬕S)΅}B»s!0, !7us=V#u rJk 71blC=ml/'%P"ҟG>j3` )0rwȻ EA֦$]vLa^~!,Ia+vdjfZBvͺ}Ɯ{mv]3鶿y ޺ʫ_[uY w:}T \t H05ʨ'SDv\.w<|+֚7> {Q[@@g1Rwg6p-uG ,,Qey ͮ>{ZF|*`ƻ*P /]::VNlv6$IVcLdlvG1FĻwBCC]\\JBPYztpTTKΝ%羽yy\P9o/Ǥ4lѸ:5v+8hP="W.*h k887ypp, =f_m>k<\.UPOٖ7t&*\.SV##zۼ͚z5Yѭ?wLUc],S߾[C'3"3]m}4JG:d _v]y&WѴB&YV6c֤1y¹> :wJHڍQ eYVfg͛6-yr[vWv~ KR*ݷzv4%07\fطn!E?4խY^9{, ;2(&/++ߠQ(>ŜkyB}Al\{ttmޯF{7G^hPe{ݰgϦ4wĹ|K#W~⤑M¡ RO{ꓜns'GCJӫLż|jI$I֭[G]rUWoټ\H3ÚPٙP݄Nh aJ*Ώ_3kY)n&  C5N8y/r{L}cqH]s\Nef̌YohPX! Ƶ:uW]:@A'_).Xu墰 a痨K9uGmoiWv'/٬:f!t;vZ=|9u<,]8Ʃʍ[&R5[ XiaZk~|rkv|`sΪ &YCkj2:$W^ SԞ?j6>}w+>@a%ƍz/uu87K*r)|Z,X9iؠ|1~ݕk-ydt:L]y[Jq+Y+K~hutUStjVV.45w<(h֐5<YuAC3 ~3l6RSecW.3~LOG-]LCSeW^L.ҤU͠+G{PY[Ty%i)zB#0iۏ;G'[>F0i'&}JBnfj 8+8۸9g_;:fx7("~.ޚKe4 |y$F|_D\ohKƀ  I2>$ 0 nE.7 :ePXk5UZE+]qZudtL~mlt/xkykұǣ[Wرc_w :4>>^T 5jڴi%۫W6lذ{ڵkwzX_t96ʊ] 1y'?Jϧd=on44M4EQ*xr6ŷV嘋2T*\͛7_G.Ikѫ~{43I>~B44-Ƶ;4uڕv[NmI?Lӹ&Y򋏤EcS:nFC,9zflż_-]80x!ߦN=:yw 81` ^]9ZD%|֯xQs9hP3סç=29a׌G=/6Q9^j5mdzXy*1j[]LV>YroEm f}z\F׊_{nZ4 ގ\Uj b^[d1%b6jaWi>& *5S[Oڥ;u^ u] IDAT!/Mb~Ƶ;PݞF]\ħyuzK{dqub׽-_nCa2b"b]\kU3vc쵵O^3E;trr\Mne:wPg[ٚζvC}7 Ykuݪa~Pݤ4ڡc}8ܻ"kč?5M['7yg]]=BJe|7_|yNaW'o?G;iWw.vߠz&&&:?|0k ϟ_;~sΒl5D [ k5T? U̅_z#@pbs~#è^c ^Z qAaΜ9s)yBbB軪\BNP:uj㰰0HTD"QXXqZZڨQJT#BrTh|r`e˖KH$oB!TYܖ~g / AS(KKovss>~ȮF!BTh~ܬYgU]f͜ f/ !BDC\Y0m-Nff\Ws#BUhB!5?]mvB|q^C5(J BFXvi1]ve!B pϞ={+łB!Q!B!T7od !T?X4422!Џ{(#Ta|||.]إ.-eB!T%eM:::[dW*ڎcӦMKV"B! 5j~|ĉ;|'N7jظd=B!b.Ə |{us_ikk?]B!JFѰUVE}qqq% ..Ν;ǎZ*YB!P!aÆĔaÆ K BThhll!x]l-9f| V5?@pya8y hGF?9) {_UyR)Z~6ɩ̓psrr9xiU*7Zo++\!ЏwXW.L8AA %N\vMeK)imW9 B"CEt{Y 霴O~ΧۧɚV_hbd|3QNڦY $#26.RdO$IzC Ib he>)W@ .4PWUt?m.';>&VY/ZӃKTFCBjH6V57]~5a>R}]uT:ЂońdFNq;٩K5h|`\Cv\(8n|NFYf`e A ]Lb{HY8"#zrWdG .Y߬F-ޢ76Pʞr![+k'Ei2t|fF,ϓ|-{h_`Q$=y-if6SISc>0g.?cԠOv~@عwN!EʵO,]%5m:KN?ϡ~$aHSw_y32 ө{5߹5C. @˒L)x+e!Dz<; vYL6IgW1!@Q?;H#ۗ^Z=;S+"_ovNgkF:;} Ӱc~ ibYn.Hdl7ָph7;;[Q #?ٴ5OLoٽ) 5C\98*vZrh])<;mG^Bng2)7g{ ;nޅ:NJVS=2v:to !Ye ng'׿{?Γ ͬ%.O.5ui+*U$zc㬭إwݐ]B,E*E?PR(R?x>C{[+4걆XCB?2#`jgQrBݿ{6Vۂ!i_iܷѭMriJɋ6۷Bg-8x[pzz^ww>mσ\2F;U;v6:;}a*ҙ8W!px],ʦKI>U1}Bmcrnm|\`ĥZ㥾'wo8z/鞬F/ŃG;/"T*M˱qVVRpɻn.E!T)E?PR(R?x>C{[+5CHU^:҂U)BV6:ڠzC ̙$Aڌ L֙wtpJ±^ع6֢yO~`Ⱥ$' Z|X3l߷wMP}fk䭄,Ы>˘iY.7kS*na5}$2l;l$6yݤf$_ظbGk i`;ǷG-6fWS'dQcQ9;ƆZ|Kﭫ֬~OcC!N}]ݞ̈́ԛyq;A}ӖOW'[cޡ\\߂kuMv|&#l|^Ut FsG{We3댕/~!vI6ܐ1@03qqwѦQԙ}LcF_}D]yz*Fik_ptQH'%t[y4:./AԲNg3`.q'BU C/.Kh;»1ͺ.>k\?Άѷ9cFܕ{bNܐЩ>ReB(T*cTEKFhRr+}V>pܻ6uk3bb ZʔowPS]]:wNiNn}MyuBP[W ه؍Q'!Fݕ\Qo2d3(,mcILLՋ M_$;utw7w"6ˮ3Z-RS-N"=~#jh\%N)gT:Yڦb}j $i~s> Oִ1@ vM +0"BUCB =H8E΀:s*ah\,eG0^=! d,8=:E:Fu):@ 3?@& 9BP*uHgYyIa] J u 5zװxf@F٥OBD+k$Ei2t|fF,ϓ􃜨ߣo*M<ܱHo9 *#~F],8q~_G9VX:l#:5Hj;AQco Nnk 0̄wij%=xN@S7Sp4;.rI Qd&̾~\a>mvҡ+F:%Ha=ѭ&W/ꔒѷt~jgmh2fռՁ=$nC%; ;LZv,EGoݼvРroШĥ+o7̧eh:n釄Sp.k?J4"գs;iALRa!~ReF2 XCn4Q5"B!@9bM|.MF_!q[EakϹ SB!P!BFCB!T!B!* Z$ɒKBVCBYFUFCB!T!B!*!BhB! `4D!BpB?K"/{^Ki`4D!vB\%wQM࿔ImMܣ$1 wΣ̵iePk{rT]hBPt'xYhr 9 ϣ-yc/Uuk*e2o$ٌ[-L]|jۃ @Lj2]$\5R2~M4]Mަ歽9R8 0"BlhU u7秾@^ z@峗 T| YD"x+_}ſ¯fgG62LodS\PbNLyuC948-4+̍l4$j9tO!P2!k.w9 ^q05[ $wV|&ZK98]-ǘsE@'&@pZk5s T윜QUPv U hMAVvXWRŀR<{^n!,j67yʳe{>3Dپ).V? g^ݣ#eCn(ZٓP 'Y۳mo 4{<*l'WV)s尭VهNwKmZ\V,0~;-4]8zON{m_h'|eܷ&Zjs9$'T8©!.rO~=[`"Z6Ҳ7/PURKgO Ϙ%ϟ͐qxQe`a4D!YP’u!-Cf1J)^yJq-hByd/^PTjFSSsÇ]6!KNYW.JZ t!| d Tњp5xkt\>$Xaff 7R,|WnRhBD Utza"G}F"d&=jTy_%h+$f4U199 e% SGDla@OPa/'A +fcc SC僅QBVa(9;P-)|oDyT)`ߎa$J) R:,~Yg$#Cu^JhUq~]Q]EEE?~B!TUL\kMF0L>s7sSIJ*iЯ_^eT@ /+:bii32r R4憢zC- 5<;bb2bnܡe͎fd|!9@@wCq΂a9YIچ[갘`29C@j@FC+ c)m+_9VW+R+q|;7{\굾5< ],Y,KH$ӽ{5k]>}zjlllXXٳ!~nETpȨP8ՙ 1P/YhUfQ͸yHy!%@p9kr(GP s7I1{TMd="#pRlAϔbӽ4-f~_6n'rPS:IʬQ,0bθF$`>\Jg$$nQLXiRQRif1 u\PEYh4}$t$W3 nLʐu`CZn/yK˘{si-n _)2<>i.`^f9 FӐ[T&*GKe4gp̙ݻwgW(߿TTիWu!~z,Pfו"$Fkx7h!yu y"g}cIvZ֔vc"O@7XZoVga-էm]#=T^dd&+k<}1xz(Ulه?Sy󗒵M;sl[*Pj쬣 L;ԧt;eiѰ͍r,o5ƫo]RILʦ?4SCI:q0X]1bx͇z%D"''VZ%[E,,,|SƏc[[˗/뾷˱qVVRp´! 1}E?PR(R?;JCtl+\UBraBB/n/T8tٳgCCC PlYB*3YϣfrL4Ν;|>o߾ZZZA$;;{„ cB!~U111/_K,ٶm@ !C;w4##cӦM_CEW>z(!Bg̍{c7jٳJrzE e˖Aܼy355J*==gܹ7n,tB!Ew@fJOUcmmӥoI&8q(DpM6a:D!'T2MMMaWnݺcǎƆt__Ǐs8_~իW7o\`Ù4ijhB!jhee)nݺ ^P, &ر}d۶möCB3Tk!TVCwwd??s™A"##722?~ѢE:::v9rd||ornjS4!b3о1!T;բEɓ'x;HVVĉ;΅/QW5i$,,m۶r׮]!B?EC3eʔ L";v$I%KdG1 caaq-Z3fB!Z2hjj>|xժUJ7Jq-[LKKK./X ((H$ݻaÆ{왟0#GĞeBݼu]*_!Ѽys##lJ0̷_/,J}||=JU444ϟDQTzzرcwҠAȢtF"ɪ5"ކ]*dܐg?UL&7n\xx8x{{_^CCCTΞ=[ ;tPvmX 48v옥L&>}={eBoQhܯ_?__ߛ7o40LRRR```.^^r$#G xJEԩSGSNvvϟ? 6<~x˖-RiӶoߎ!BU-r??ckkADNtuuSSSǎ3:_=au?qITuV}}}kkpsssL6du:lРCZn-BBB0"B}EӧOs\oa``Gu#{egg9rD=p\.WPToڴhvڅ׮][" >ٳ 4nx߾}m۶UφZEB!PT-FEEZXX̘1C 888xyy@lllZZZu*t̙#GPf@P(fΜT*=<<6nhll\|u:477=z:6mtfffk֬SUB!PeT-~Zl)XU]tUU-ZԫW{orIzm,Z#'&vgNeT$*GCP YfGbW#B^Q`m p[N=۳-t'|GWLECRɛ˦)9Y`ˣionھvgKv.gFxQ;a)Lέ 3.y ױtj̎g#+ 7Z j['a}M4T*O޹sgNNZǏ8!Wvd,{!o>ӴXQā;۟%@pb^Gn[O2]ݨ?zLq?Qk;h73|㾁]*ZȪws9†]GO\竡kFJwLeVm8<ǁfۉ[`M߆D=I 5Mgj7l paͧfns7d|#AIb>UkV&跇6kƵ3Nf@:3, ;,`C "v 1FbĊ`blQcXbKF;k4j4ƊBRDcu]ʪI^9;k93o_uЬi5_ڕUuKF~cww3.]d҉0++kw.))+7nܘ9s͛ccc=<2~/VQ>PXɥ )umZ3f']/|`f}"_#KRߐTr>_[yKSQQwIDM6sNIII&Mn߾W3 Yq6FFFEP~=֫IιymMHE$ ?IBDTzl9t` *XW`9ervDuGY]d'Midt6#RhXuUϘ!rrswKT]z I~7`۷NS?bV_\Nv.cm[y^,QL2:t=9de)Xwz>ݢ vAD!!!SL7no߾vڅ 0pt~2kԨ!ݶ1XSbz:j`^Q*23#,[Y1Oe&vvF}v\vf6~*3qp0./"kam +323W]E-aYR*"3#3ܬ(Qt/Pa,͸l*LY:#u^{8Ң~ e<_n0>>>//AgϖJ5R'NذaǧLR *TVK>PXCMli_M[M[%9vJ ]\CDǏ06ViensdXr/S%}{^aR?CT*z ܭVdwѲQht 7o$f͚OOO6ʅTnӛŚ[e&~xDܴ?4EI4[sF𤄸ٰ7u#yʖҋ88;9%C!մ"?J8pN3& 7]~R'M3)S)$oai~;)+'yWI\2ms2 }ƃs+;߮_npuuurr26ָt-lR8F(zOe']VhYlh3iY7M{Q}kq/5Xg5:6T]fGlZ$dMZ^CI9 M\%"^' {aJQG5B H;ӣө 6lذ_ɓE㟮§o?A!{[nQLLL```AATYEC ~,^~Ţ;P *::zXk:9~޽ccc+.C)oٲ%??֭[P(ML*uB1ucǎ)-DD5Zv}RRRhhhZZ9;;_155544|pݺu+9ϙ3'**ٳgϟ|rTT+sr~~~||:#%%Çn:uTYQ޽{sttLII駟JJTd&!!t%%%_zB[nZZ\.wvvNMM=!C[V-Jxbk׫WŅ"""?~,ADDkvww'"77u}}}~E ݢ+Wbbb E~O뛓/p믿FEE͜9[e W5 6L\2,''E9::tĈ}%fee_Un? ͛ GD{zzz&*tPol`` n jذVMה0 oY%aOҶ+OhؠAcǎ]vMshEv211qtt5pjժgϊ_͚5Νkaa!f͚#a_|ѸqcRt˗/k͑Rtĉ-[ݢacbb޽>zha0JYd2ʕ+Eu={vҥKEEEj ԯ_֬Y˗/䉸1 cggh0kt^^^{Yts?.Q &M:uBPSyxx5*55UX ԩS/\uNh*'Ο;f6wnx2,!!ٳJ ÄҥKUm8q #SS 1"z0ʯ ;n6tfNU;F7;;m8*tBj֬o߾5kxzz/x; CGx.ndƶi*p ?]V=W!"7z|W}qm½{+7ONO_Sr[I*)e-imZz ~Ne]?@\ge򁧋WvÇ߻w |Yq:d+9+ӏݮ]ygVƴwcr&>˗.9qfO ?~޼Н7H.aj2|_>#z|r"zԗ+ )uvUq׬YSPP@D;w׻cK+H~my?yJT}J55bG39";h.^}C^:l\`W/϶>B(VnnB|jOyqB~x$.7nb/fh ˷טue|r6㳞>>>Sշ8dž{xw8q%.(1ҏ)_wC-POߤF67vO3h#6rdm ۚ1Xr1r|t צg 瑑+V/9tPbbbNV\$~6?cY׎ÇEWhRÇ7n(\Upta.R) hN b֬QֿWK:unPɵ#7ѣ|3cZe}qRwN ^}IKBg^ܳCљ%7 ܷAzIDAT)aS66V^Y=i5śmeUQ/ADk|şO5{w۾pVZ:bŞ.[GOΛhʚ#]j>>5~XۆH~c+#-.=vm`ZXm'.:a2[kelODkyb[]k-*yeee) 'OupQҒZnݩS'LnJ~~~/;PX6ܽ'jZ5kXk6o;79&{KXW=s8VRy_Dʓg>12PgeZؽdJ"+}r悓-kicaY*2,8YYEcm" 8"bMT_]r<ҌtȚթc/އc~HCT0>f\S=4=~v˗/wpp{666GgH$h|zzzFFFW_}5qDx Jhb… K@U!h}\q={+~ cڶOgnٲ A PŜVEnn)Ql )x]eq&zF?QGDDTq Ye?y*/W;aY88"H+Ua, Z.VOQ+RuhV+2HōDc}9\W\!͛TׯD"III6i06\X~7pT*lE.3jYYz9bbcw򹐈 zuۚ JYvAR^?rW*g&}ΘWcg.1{)IuuƳ~\v6:Re+[Zծ-w\{#7+Y<|/OI,̸{AAɏ1`T J; q0'g˴,(* 8b̭ <(rϩ7@hD5777744He΂ qutɅDDxnխW ReOz?\90hР!3cUZD_ww_4`ezDĘ1Oa}|:v Z_-DJd16|R+s|=uۓ6ہ׾!~۫wGSʼm-cqZgp$j2;ja^⒐۴7tѾCuvv^|lriexo#W 5jTTTTfN>]\\"bcc P(;fnnަMH^rrr Ri||oFݾ}'O޴ϴtsW׉^6*h#\9n(J_FTr~/ Unݺ߾}{ݺu5e$vp7 Geu25b\N|||fΜ9j(5!hZt[4433[zuV8$||TWX@Mzg͚"nifD" *OhHD6663f8|={ Ezz:~> & ݖVcY޾UV zQ^^)^JKK;{,0^^^6 ml25eYOm*+b4$"3f\z5--mf~]q0Lǎ &BXoO+?ew{ɥz@^=Coݺ ccm8QUpPtΈNuUE __ރzDaz`J_/,ҋ%$kEC"jҤɲeU:A^ ǩ7|LԌPiD}GCe_7TYQiea4#FTCuh E˶ eDa?u2 AυG7DCf4!bBaDCbE\}G~8ء.jQgASA4AEEu:|D|oGQ_ iVQ.V ~dau@D4@WDI0}o睅BZo3\(, 7Թ >ՉPND5Ԛ E oxKcVPhUfdӡ(ia98q*ehHbۏr)[|2chOR߰2Φ䑩Sq7̞cβAfGu­?гpn?jC͊0핕ʪTKeo *rsM4Yۆ~##0xb 6kMh*!"*v ^8E7ֆ ^|iV>63bN9O-]v]'?q+|r'sD.ִC*=W~( 4kDG\NḀm+""tkL%وHjODDz.>z{F.ԡuu4djt82`Pѳ=7}ψ!?o̱KDĚu6{lf]7jT[/D ¿@4d,͹,%Y蔙Wv=BeH?)ND\ލᅯ0KYO3;;UdLk8d?TefTfΖaqowFmȤMC:`Ӛ:ZV" P͔u@4dk^qȝac\:{lhɴ-=|"T-/ OkX^t@Do ĩUx UuB8DCPA4DCPA4DCPA4DCPA4DCPA4DCPA4DCPA4DCPA4DCPA4DCPA4DCPA4DCPA4DCPA4-tIR7IENDB`kraft-1.1/manual/images/en/followup_2.png000066400000000000000000001466501450127457600204330ustar00rootroot00000000000000PNG  IHDR8 pHYs+ IDATx^u\"*R"*(gwzƝuٞgwb#H7(ұtcayx3O33%6n܈@՘Yi!DtJf^f`aa_DOZ$IA$ɔaJ4UPVV&dsaaؗDYYbQBi&DcB/>SiP3aa}) E113~Zl|Nln4VM%}/OյPT 0 ð&?cfDx1uiv!K725lՎe4-TUTTUIyZZZ[&8) 0 ð :;jdogh`1A#c! QcC4f`Qc_ 6L򗫉 0BD\++Zl1Ŋaa"fƎrhania޹}GOedessY!&V4&aWfPb 0QMӵFP6*=5$ă1z!;4#34a#W\E 0 ð'{jijgTs[l{c,Xb @UqŶ`Dkg{@#@ !jʖ?ǐ}ⵛaA>}ZYZ@Ff'D¬(9ԅ+gdʏBHcRJ`١5IONbgr:@ rB݀4Z0UUs Ї B8V0P0sΎ f/Z! ۶Cū7߾a<qp^6V طk$I,\>+'W>S`in6sx3S?#g%s9u.=# ,{us]bX ceb^Lt\P k@KSs_ݬ1)h7{3ʅkle.D_(LL= |u H5ڬ|6d@2հ9w_ϊ$S/EFZzFDWTTg(ާiwa#]mƍބɥ[}E%e2иQK:p7t :׳Qaaѵ[w?zdޥoϮZq/*.QSSܯg655433NߨAʪoH}3X0{?n;eMEE *7t`߸y Up+yH$$y9[x4 },|gM8@DT| M3bdm fOkִ& ڰmY'ƮM#B4#jLQ׸Q;ʹŽp)̝-)5@@^VٶİY.x@#3t`_6Jc}f] mp^\|.F lS3e$Ira-//S,1 +w~ajжPt s<(@.M}tVvR55a v;c]ە&>͵>=ߚ;v԰߲/Xr}(Oc̔E X`NϮn.K1 >-xƂBr*X ~ŝڵVڱAFVk7X iжP(Uv8ۉŒ)urmblX~kj fO۰m71QڂӸlZzFDP}ҒyeHcjLŶE7,% 4 dmiI0G$bq(_*Nm{;xCc(•`w= z̤U~wnڼs߆7jPR4vX"u0^MM-=#sׁ#y"s 7XD G ΧG>z1)++eRv> L .];sfc3m^(̅+L*<*ʲOܚ63b[rsS;G{iC zr;(`)Y_ {SibIRx<^:5gB?>Q6q3mm?)k9L\n ̙6IiˊeifMp6܊1Uuze?GgBzBDy GØdfiFtEYivA|AzE:zcKˡv;=9W_zaߟKGD[ 5GN$$[ SfmZ$=33$,BJIwT*{9tl| 3Z3X*.sA}O.+jjBwih8fU%Hip+}Uida3mRjZ iM0z}ѱ.ΎqIv mK\<(&ኇ*7}ԿWk7y;}ԹrDl1}9x4՛mV.hk/?O_,sfyEŝ=]Ga$KsF -EL,-&Μ}J'GMalfLVjܸ->1y^{e}k].tf_ 264:[ VǻG"åmanYYZGE3 +*LJKNsE|nA8}𨎥|IVoޞYZzɳTJw[vn_ҵbffرŬWnVٙe&oٽQ1Qږc8?4e RXmy3402ԗbB*N|$B3;B npf1s i$ɶ-L+4?Bv,k8% GF=LR]F FElض{f\W,w+#p؊*Svg.^Jܠ7-%ыWSR=ݚq+z4sMK|Q2AVsfٹ4׹}}VFFI$ҔtZ kWoޑHy_Υim9B`fjj[~FD[1 ZMW@?xTfVNe[pE0=$~q?-# !P +܊ mvV_Ooo#u%oP^UU5@L4NSSf9tJLuRձ?zɼ1-C@a1w;mrSg'&i7X^՟b-ŖUqٰB;ALY5w}rSk^GDBJb.PmsRFP[RPӫW{&J@ { K~%FvL&@n]ǤwaЁ}6O-/Pmfh?mX&M$%)l<##k +*rss  3btX,nL"ddȆO"`gKtQ~w rؔfLpyy얗J*SA]@uשX?[|ͻ9}]WTvJk-ݲSՕp /0ץ-7TuDTC ץɥ#o}2*dZφੱi@ 5aaVk(ruqsvYӢ.aMTlFsfoB䯉F4 f_/,iisĵ/>y\HxzDҭsv>^ 4S[XT}![8jƂ"c#C151ab 45444ՙ/Z#P^H"xՉO?sjIiɻNJQ$I2jj!g`$,Rv_XЀM@P~anbb'B8o ]41-0)49k2@Tm hnE`d>5ּzѲ ]ΎVƌm\]Vl-&͘ZT\G.gfԳb4JM@LV,{ϸ ۻ5(]~[ruCsCFLq&tVUPޱǴo"6ڷz<XvEi Hn٩L.M?z V;{aӪ%Wn,"<7gd= vsW߶{Q'_;v<.,[fv>,2Z8yg m,-+ IMKg4_5j oغ;//[Q$*ظ}ϘCgM|]#@PTT| cFN;=AΛ1@_?O$ZnsVvϚ2,s[kwW30t[Ԫ@= nq/9)˔WAIQUVVQVZi,{5un;0)IsKtE% ԷɌgLrCj#==cmKϮ;V+--[i{zz|'bG@O7YCrL63IxZ:Z:̬) {zW!^ǚ  |Pcy^z8JcD^|̕bv88W >iWSHaLp(bgϏ5ưW9(a]Zzekܚ6iDȘ/^FDLLD^Xl SF[j+3UUQndHͽ$J$7%fta*0 0LJz.Sذ; 1ko}*fWfPMhۥw '`aG hfɍiو1&2+aa1d'A)kaaWUCrYl:aaȊ Q<+f6d7baaaB,9^1a3xu!n"aaEL8Kꠍ%Bn!UnV$aaȪjr4?Yl+aaQbJٚ,6[0 0 F( Y.YG˸؆, 0 03Mg'\&[An0 0 U 1稱l˾baa߂5j &҆0 0 ð4b&jQcɅb 8J0 0 [(e,fVƤոցaa}56)!ffjuii2aaWWAr̄b 3aa}Ȋ)2;˭æp`aa_Ii%k(;( lb} 0 0+pC,,UO(b} 0 0o4b&dרɅbþAEյ3f8Yw) 0Fid՜T }KFg^r2E贜~bsm' 90m*똭psnwT {:Ֆ\J.@;Fy&6-kܴeN%Q:?m|n&}N|fx+곥NuA 0 /\ZQEQHԺgSuanJtDΐJԱv֭8;E5PN1kT&FEFKv)Μ/|85&*\[ IG%iёeǷ/e{}4ke$=:wՊ[h"꒦^6c4qMGzzѽniPZ"KKgIZr{{_}m=5"Vaa ֶ,zf' &>y9q`WC7Fp?wŀJDiqI"qI܍uS+@ _i\k utMĈаlֺy*QfjbL\izҔ/N2xen>i>0 0E$P@I t]$2ӤƵFԸ8v|>*=^=LPiң$V95,p#Me+#*^m%v1*켍D~֖1.J ảKԍl]Չɧs]|1Yjnw{UN[7WS#*‘n/vN{;ȺV ;اTX[di̮GEW,%u, Z. e/B31q|8_Z˩{&\[v62D+_\*/օϣ2Ju?.rfdK@U۾^ŤWQ=f^jD!aODVJ($eFV44HUVT51J}k5ԙ~muZ i3޽zrq[wԭfO ȣW8WWወH +J7,1jzy%蟧$iV\scU~S-l03DDûRu.M4d ";!*28<8=&2LΣB^>|?{FC^? z>XVevj@ȋׯܛ{;!@U^rTd$_oИ3|)gOP)Q@;˝  Y1oFFi:ٖiK$Wo7n_vܖ JaD很ɤPIZLdaYhT0s.CD+ݜ'_?eˋ ~֭fU3uU~ԵMr0 þuCy$:"jy Ӂ@7ElHj=pSo:շ&J9gWnO]zk[laUZaJfC%[ A,,x:viHwR~sn>G뇓7o>. X|#]ZZ DQ_^]مui";ib I B2Wʈ"޾zV-ܻ[-PqW^Z4QGn[jB9e۶w#I ajqn"q3=Mj7 Pw)5;_Q3hҵ4uHat}ʁo޳8C웗:=Wba؏A[W*/hZU/|Mq'!T>~Z.s_UGViC>jf]qmtgG&S!1elԊJz:ktCKiJ<+w:έ:ةIT )Xp1 Z-f3Я6zF֝Swx1Kuq> Y5VtŤгi! w XPVm`NH;s4YS 4 ٚhPC=*}/nGY~̞`-UgK;ҡߺEo&9<ߊ̀ _ַo d{ {6dۘ Ƿfol(_fEv[v3TIrSiFtԍk:up&<ͯJe;-E! mZ8Y6* i0 0{H MMP24-P6mӶsج. S \4{]64UJz".[])e..;ⴰ<ھ"((ֺؗo /4rBjiiPNWUV ibM=!uu,Y*a!R݇up/@O"uZtb.#t[̘& *iqQ) 7@U}Z#! 5^ݘ4uv6#?E4ؼO!M8$4_bHnwrȺYkk){ˇ>".P4srW ˢM{k,1yV]{|JV^jDNS󦗍={skMB0 ð6Y mzڒ$YF j}sj=uD|)S*;#@tEann/XIR]w<@ҸȲAIFmƏT#PUxPH(<# kseUUCePSS'蜬\@XkԔY׷ ivVC#MC!/AI А6`Ҁi@Y4=_&AIR#I3 Y( кW.\2{SS5U7qMggQu-bDPAyymUϐ-AhZXF4=gF;sޜ>Cgl(0 þ\\);͠#n=dC`I)HfedH&|sw 22<kƧuYpypЫD<ݴj*%>̭y(|YMDK)DS|Ϊ׍kn:`|>O::P>(Jp© kW# 4 ( >wnwGq9."';ЅZQ:- .i ު܇{x5܉3W|<Ճ'0 ~X! eωBo&t1sн?'_qŨfL@\TL<۴Vi&5?YbDhzv4G>{ ! {xԜ a7ᄃHc7<^!(/+[ l0Bdf306 uHΥ}-;HmC}Tʷj\x?3p$09gWYIe EU]mLt?@CDU*--U H.Vwq䞽BE 캢}0 ðOW*O}JTZkhz̈́?qIƮK7>H8QEfF> ¦.jH#cֺ6AZ{yMig$+Xr*a>̈́ws&.}PsfV gDghFPqp~OIbvRhd70N輀rmѥEU tAn@Unv @61 I}/EWp 2r/Bv UUq~ N:$ qxkc5JD@hܴs;h@e~ccas+AES]Ev?Yn3FvPFjM] m M|ZF^-MNϢrkT׳QهW>"qyAfbOru_rϥY7G+{hGOHֿ&z6W8?Gtw2R^܏nG{{28Cvᠿ֦ⴗ6]"2lEAm?0i_41D>&7Oԩ&z'ޞ6&diZkwi 4Zk kw4Axb‘m<>wE15"A,qNN%)Ŗ=;,7ΕhmCo=RӱҸccEthke)N~%an0 ~XD'7PSHx#-.5vɨҜ緽>fI3ww+^ gڛ9&pnwV g3M謀)cԊdMX::|ȂЋ[B/VXts@kx#=@hIzMd:pm%חr]VYV"Cu($iɵ =8Bx`Nnqȉ!'충@ @t;!D͞˔pmԈiD^y-"dJ*]Wn~>V]Z9kaN٪I_/ԪT*ƟDh0 ~4M'ZE8[la/ǔ'6MDK@ }KG﾿/-0݀lDC^#OOp8AM}K;.r^mmڧyCS5S]Ӈ&]y[ h\O; ޱ>?t%C}t|G7YZ/G_xؚm 5$)4nДyCG .@] 6shLM̛<[Cs}M!Iu3÷=kGt<;jScg)j7j@3<Ҩ5 l,߯yy|3jl'IIn=I 0 a) 4i(Jn(vI_=F!81 90 ð_Giii$x4d5ٴ\5PIrԇڿMZRL!Tv *a>q1:c&0{BgGܹu3{k# IK/@h7oaa? ū 8\~ Tqk/jao9鏮r0 ðU֧5[_UCO#-LYMDbZva9-6Բ˰X< 0 q)q}na{BK!Ӽ'caWl 0 ð,P'41 0 ~4L!jE!f4]p5jLbEE_x0 0 þTaaaUU4i [ZX`[f[REaaa_B___[[&>#IoI&f sbl0 0 þY_}Vaa}8P0 0 A@ 0 0OZv'Ovaam +oNAAu ` !DS4grT Jaa7"kw}baa0 0 ~P8P0 0 A@ 0 05 0 ð0 0 ~P?Z&~|?Nnk~[BWfx!6Ewb|rt1sTZyJYi侑6SuܩԳ) _o*/TfzKSS! |=~f.ΡFv4mk#K}utﲥV^9E$*eJyҬ#^tm,^dH$ak5NNd?G;~WR7uɒΚ2 $#tiv-nfUz =c@ݾuf,l3ځ#3VH & 8fߣUڕ_/oa@_/9=r=U롙 :_8g@cMdމ(,hbf{3Rkv&opZ1i1dqd}s]wqBNqmt=ΩyuZP/2/v :sҺ/uR5N-=lPJ!a=zΚwvIB!a{Y@y;յjEc W&W78qٟ=mPxsצ㏒Jxݧ,ɪhK=ȷmkH эY6vv$T`ʛE~szow56 T8'y F4%wg24mHOCxYvL|=9+u 4reG4 cEbBľߜ {jvCͱayʁJc}8(*RʹmD^شRg=v^l] c͌ѻ~_:]+=-&g mѹ wTxww @qn_@%Q6m<"Jk_}VH,4r2f 4@{aɡY.qk$z6yf#|UK s˽{FgUj9ff{3sw\u܋sY˦3^0|5mNCZ}5 K=2~~/X$t_>=urhO/Zṕ[]?-oeer4 ~{HA~Hc.toY:rT+[M?q; w@9!3o'7Mle\WIc;xCy7N_:dK3m^<Gor[z߭?eYp88K^ֽF?zׯ|1 ]mByk7l4O@Pغg;C@{>i~CO?rαj~;E0WHc.VqA݊Om9OL@o=lűwoZ|fo XmO.:ލޝ:vq7C~Elh|su&t\k<'>;[)j@sC;ÜUNMڋ61_3Gnܺwܬo{T5`^߽ietiټyLpD%*z콵mYPP hVj*߼,ʝ[Y :>4^ŗSiPS ?0r]MT{([h3݀~6NnY~PY9eYv. fT'κžnpځ#[ZTF}Kg p5d!-s6 ~}ۗ cςg-tݾ,KW/|Bv@Wssҳ/i{WeH{YfnmdS|H;NIA.½wTa/2*<,>.:$'ĤgI)(Iه҂̴G8~ρ :Nʖ)~qxA`i@#P[/l-$x-t1yzC:h:9p -=5I j&ʩP?t!x.{3?<6|\K6`tY>޻z'nkZauHPies>Ð|>Q|Fp# y=}@𬻌aImHSiqCqޭ4%>jX˂ ԧHf /ɓ} aBˡCzi t@h6v7-~{A%ݾݮRu6Yk?7]{4ukuۙ sqN o=1#-w'/iW˰ n'+_/m;Mn2Cғ@NkS=mzm?dGlN .ۼ IDAT -urjVՋ;nBöϰd 8B3 Ýo=HAn$ arRWgVߪ(7en={e˓kVx_ F 9i#ull>ͧM0oME޻\4-lk4y-u>}n׳_o'#: 0n1_pi@i_q4*K6zjc3GA:$}edVֹ9BZmK9 ?:2i2TӵUIOKH(޽YcJR/;f$t1Y49sdN~Ua=vTѭ*8>(O$?>&ˤB-3ӺC:?ʑ"rHQ^. U L5dM u@Teb.K'ML0./s:>}R@]6IS$y@4%/Z/T%fr006~|h=Nv_?uZ  4OthTLyx՗)gY:ed)39rs*}_Hz9AT@P%JRCv/)pA=׃=HqC%}#= y$[KxQ;>;]&ʗT0~_FlyI !$7"~L-&-9*K)=hjn[ཾAN۴&4J6[S6U >WEQ>UrZfZEU:ldш}6%+_J}d=q`M 1GcUiunVTT@xk'O.efˡS21/KOŬi n/ߔOoq}t7iD~cR:BH@"&x$VT&uRP9i>)HTahl {$C 2A,~I0.mܛ*4YVvf!]^A5TNf y0#t1j7N!}B@6ƜJ0+KȭDՐ>*yS̽zS'O:P[_%>K@ x&e9ssǐQv 5K$A"^4U\TB<#C>/OT e2.]6) E4**.C9%HPiSVlsf<Éѣc+F%I 8H]}% xqqn "VĂkb_Fc45jX[X1F콠bEq[?4 ٽm78fvR&P w0 mZS?u'>mW[űo8$/'_XnMkHAOb(V{C]d^Ŝ>+xLf?J<>j DN\5FfB/?Ul7*{0AԬcƽEٷ6od׾2Ee+ vrwdP<9t]3Ri?_p̚Wo?zz썇 rKd +iվwUV0`/ed탿blRC<[,zfqmV/Wt,='0a]d,ޞJ+osje]{Ll=ga_Y][֏\8CC7s^_-m!!C'a/J3بg>[XƑsjݜsT瀠ݪ=qn ߤ_oșG:VyìQ7?`а? P|<*%&.E?őw հn!n8jpxYotU 1xө=;w{H11Eeb,[Mud?FulMk?'m2kuXݠmNw =t_~ ]ЇkLYA?¾e5.72hv캉=; |%6XL]2k1v`豝) S[︹C{N;Siq-$e ;6F0lĄU͂kvu޸{%8d٭2Kfo q Q8s,)MKM- r/o;?2Xuծ&Iھx5 O:"OԂ0ͅ!e}N7=s6B=}}gq6S:BeeY8heYanTd>{c_BB,%L"S^wwBC"6SwLi}PЫ~oX/."kuLW J}kŠ{2,adcM!ᐌӆ, =BոBPB1f!K8B!'IB!TAaPC!0!BUPB!*( j!B5B B!PA !BȤRJ !RJgy} !JsB!P*@`[CnaYV iҘ4D:cyh>5o)B!.$>,'B!PA !BAfĎTSɌ@ubЎAEgQC6f_^9Kp`@mxA}sQ. oBφ#&tAm0ȵfF)`f.-BDiYIh`AR.yY;9Uܴ\ h'Q!Sr۠[ԭL9gY٣Eǡ#dg׭xLTKcnЖcx[yGBP%c|%˕OzgeWQU; XTbɾg]gR Z~&Neм^=LTiD4ciA붟>)zՖzhW.^V,+GDW>8~'u#8~ :O9T& /S5IV(N^9F(w@~AÛx -MYYFJc-rƙ3@o%Yuus\w[@ /,v7o7s>=sޑ Իl왃+=- n \Sۧ֍_Cuod]-!XbY=;wxO\ǖk$/;jZ~<n\;Ze_3|n @ϰ%{N1]`>okj{ƒ~[Y @rnn1KP``P!7]7skˬmڄhQf"[7_ǀ.M۷k>CO5>ɸnꀰ =.?<)dƶ6˰J:u]w2jc&]Yސǭud괋  =r{-V;Wڵ۽{|i?667]Ȳw)s#/i t1cc+H1{ak@F%8CX)kdMW.غmW_jnsI]NZs#+МK'PlƢ)#kY n쥜֩K\DC!j߈>ELk2akPxCk3rV.1qh>Y|Ñ=Wʯ@!л j% &a'l\Ɯ/gBq{_vԱf=_>yu}_;7^>| 7d4u|Xd?.g$-fͭ: l qHڡk"Lvs@R~?u7}ٴ`D םh=GNw^].<1si}$jSw'Ol[ʢٚ~`S=>]שF"6۷+}/TgɓtWn4x& ?#=߆&, N%[Mۚi7n4vb;ݷW|ýcd<|,zXJ'-pjݑ#zV֟!|56׻ECqvXx]Ǐ\=Tt|Yݚ$Ģif)(էhy]W .eװ|ēhqyw*NԻwzpn^!@^Mk i>lأBv)aA`hVWv{?v͠~="B 7svV_fZ |%ޯ4ڻ% u_4˹x'6Q} UL:ޡɄd^:zZQk[ fn_@شkOO L]|8>m plCCH _ uIn~™U fƂce#OO{ڰ_D3`.!_vs||6ۇWB,2ϗX2e- OAsqXUpͺ8[DjtYT.tLjDr$_7;aKe [lcµLR%o!z[q!X`8pھ~&EN%@rk8wW=Ȓ5iB'&m#6=;>]X0Zⶔ[Y_yA^>(&Ze͒lwu1G'I^V\pp~]<4VbceBB|Vz_.R2MPclmtgM1!9YŬfRpU\>|ʬ0'O]Ґ<~m%YYʇ#ö\]i֢IJKĥWIs͝usvP2RUc%wFw ?Nl6jDj\ rR$kwde²^5>>xKUF"HJJ>B!̬t$#5rlK5Unjjq$#%Cho'5mj/\M8ⶺ:aX[=fe(0T^`jUGmӿtUYiiE6 mYFleYixSYYKD`fXLU _u)KRbm+[ eXqXvjA6OM&Wb8 cmm {n[pL(Ix kim)MV"(qnM@JK.t6\Nd̩lZu;cu7OмI9UZWc@rr/VܛF :T*H\z!z/M$Y@{omtɮ}eHAP <ܽT\mmj嫾xZ_/!p:fݽR/w=)bwGϹqUm4.J{pv÷~{7vpc!0~[ 9eڥCڹC@ݫ%K ϟ^oV q}/eHS+L~oae<w~]xVHTfFhakkQbKR Ӻі4ku*MF7a YgVU]޼DrlͲ?}Wۣ;nԮB# +#HB1#N$*㸛Iy:yz Yz~?!En'T=OIWƱZU ٮۍWR-;pغV|qnAާ@z Lfnܸ#vBR VʞY J߿ɷ ^HK}A-*jѪ2\ qNkQ>ܾf0!`i6][\\ƥ*Pb[`bjic-d`U1) IDAT }`bQVl:e\B#VSNJ#&ĔcXaʽ4%q!B!P ƫE"q~.J ! ||B!XJͰfU]ܻ_$R_h B!ro"2qۄw[Ts&թOD!$23%i n >MUV5 ٌ^&!B !B5B B!PA !B B!TAaPC!?C&{ʔ3*HɄſBcߵ^Jdic-1P]i}W2B_A+W6@|&bINNq)BZlB!PJy% i !<F}(PLiQ6!`؝VX0wQ {ZB 2M.z/XmB#Eq6!`Pأ VX0waz?XmBd=0O1j8uw>̌8^ %,.;lSL|geowYmx[~wwE/Ǵ|d!>O6ꏉZ׿*(_;b~W/P U$1[k]"quGE]I).bq0G|JR2tol?-J:TкvsoVdϚtԔ3]ϥ4q dE.=Kǚ;_Sd{BҸ#32x&\ڂ1/kL\;:{Ab)^<r+(\f\Sz&5h=`, f\W_=嗄E~&5~2M_J72?STB0^?;9]^1LYe+MX9:d=uxA ,9k慝mwkm7040QB4:Vj߹m?Y^Ta@^} c]?*M;mqk\Y6iu%{W ֍7+ځ9Z[U5g^LkU37ӬBѮc/J93eY{i ΦWf{o,Mx7-߿oOS2e*~>CG׫L>ll".bNa~+_PP 5Mk/};6?qEzc{dO+ YWmx39۴ܭPe1ܦI?~!v%d]y4kiۨg뾝Mmg2՟C7|7of7==P<qh[ow&=Kblٟbҥ[OGM+zVtQ k߫=%aŕk* ʼĎ~tj { si4+[׷7[`*UmB+>5RUXT;YfP?okX ̉C P?Uv0_ggj]šd;nӿX&~V-Ƭ_S)<МbFV2mn7QaӞ eɋބ6xI:qEӎ,S{`%c._;|0[-35-ًp5ikvx苤<+'(P"{sĚ~v _kD;]_qxOk䚈8쓧g:"wG-~SBt/k戕{>Kih}@1bsl"Gi¶]*B 37DSwgU=|]~hIuM"}g Wje;'NMZ1Cdϥ{"R:T!xW^?h:T*~fśL *#aeHw#jUBQCs j<)ʳvruN"d[;d1ֶژ0gae=W,RB),Ía!CBڇJ" NMH,53p 9؉~=F(Ȕ>$XLV4ˢx%jYߌm~cRZQN} K '[^^,h5~Mk5;WDz3&M+RyA>H,  :[;@)((k{sm S@;!Bĩv®G^_kM^_kҮ&.A !>Aj.sVɲ.ZٻirS]5kN %{y76z(m# ['\}c+FP/,vw<{[J^Lٸ)ΐ6$iźJe7YBѽGEA/k:+6ؾ3$++שR=_W~چl*Z$/{#0m[1tւܾ)=uS29_ڱ}od:w| n|#n=uxjƲ_GV:c`N?}P@177DKt$i)=1Nbm'ik|r[FCӤC;_)Q|)%M(.mK.)Qf=˓aPWbbyDQIR NO))ޗVnU8JEL^S%J/JqnY!|,u+NڿeRJ{C _ԺK7 U@/^u_i lc2WV+lw=OP-MR1E;Y oA d%|N@JBbBzjx[Mĭ^S6Oh\ђRGf36N HƁ}5۸_U<1n߿/iGmTg/Z omW\u]g-LNص浇E VTwI=.S0Z(cv,kP=nAQ3UlIe{TPţNn85z|n1svܸkv{{NuAƳOfqbƞ.0%b~~pO=h){, y/&50l!. "H8cYV.wa,2#'Lp/_N, h.%yJ5>ţIo }h|~.uvv=Zy)MS-kƳ'+Uko@Oy.7FƥY ![5RO^uPRˊLJonkC<@P*mo{pF0 0@j{IuJ'%!^6);RJ)%Dh e>7D҆2[0 탂/1QSY !9 j2c+?8a2o2zߋcn0a8!%+0!?AQ:Mh !DS_RfʰOn2 P3 `صY !> j'vT3o\ &]}Hv1Kgqی0 PhPf !! j UNPJZMeEE&"TvS0&T*ٝ`4aBjm&RJY5(6m!`P f(QJT*UP:ތ3WM)a²,h& B}(>]F^FMQO&WVpIFFFfrڵj)7 !ϖ.iSJAMR9ۇ+2~ BoIR?] !>,O&M҈iz?D72eLBD`bbB)%PJyeh A#J)Š9BF1w iBƨiRVUm' R5 D!~0}&J5أ9}-*!à7TAuGMOh!`oxpcuĸK:[BC[8?+i) TY:LzV+&*ovM}L~yq0-3 ĩT, gB*^?LWl/*3X:rB=`'tijztM*.7^NO`V&(j4 4.$娥*T 5fo5:¿ۈ ATLPJuw_TcB=jO?m(j~B9u%ST.BTE<$@nK{j66^)W6yI@%W/ڜA(+V&)1EJuT]z#.oA 4mYM,dLcq Fceꢆf -ܜI)@,%,>{^8>N%e6a6@Sd+% r"J? /HzX2f LVN3F!N0}4ͨMZָ&n'> Ef]R`=,(:_pS Nb&d;Z/y3Gɒ&+XAXeK9Tܦfg+aci ]LI͒/}JT0U,VM/VU5=&{SŗH׻_^4uP0u'(gοs|,sS+ WSbU bv:"VukmUQ)%rF;d]7 T>3N`D_W\Ι!hQ#[S". 9!2`xHd"SNi2YR0B}~ ;94̨44DiSb+^ !?%74f;&-6 z e)k-7d@S/E3j 5T乌RV\I+|3A\`ͅU;P?Hs4maZ@I)T]rP$`Xh`ȉ{Ҙ"*穵v|k*QH SwBBd˓Yj(+- 0*D!aøcMiY(jZ]|lJ1Sz=RfTn<!3>lDJ2.MNyJkyf,Kqmj;9re]lnG) BJM2t0)۬fQaD̀5e$Sdc#(s3D \rRkKu Lݶr =!fݫ?mWڏ8BOUYyuYŭJdin(NsU)V̲P픧 ,Y1 P p>/j2Q5JaXs6TI =ω(7rv1 y@X1k4n=TC=a5`\Z*h' 1em̒+J}(vdo_B<83LiO":d4_/I W-QM~Eަ cgY3+y5q+&a!ʙ3 cg)[L#7q=!6-jP^$O U81`i*IJ"/Tr:q9a&kR<'YĞ:e(n(-?EC&D҂5eL,P|Xx(df(-E}Yܴ{%NT 諓wB؀ 2N]L>/J5(~B(Py`dJ;9Ye_IR*juL"łkOY!Ь51 /dYS+&&&;Z]1q:VeّDk@w{ CYMEs 1B}>Š -64יm_nXu<"ؒB{YE%lqwֈ6 O2*?<)-{ !?܏7GH;^մ=4nԬa];J&uܲ>l:KP@}&Ki%ɊN]zx:ѻKxp`Pa=U~<"~nz|'H3$CxOT~h CjԱE!TO8i0͂|ƫ@q{_vԱf=_>yٕ" q9|,sG`W_;}ߧl]) fO]yXg=Nw^CK;o^X" Q`n5`>fŎǏmWʒ B_F<#={AJLak29][scڠQVedQZg+zE8y!>YY[ c' mk#"9q(V ,L8S$֦_}Uanb1)e 4U g۬[3E@شƶ`$-xYFv^"8-j23K xʯEVˌeu :aSAMbˊ>WB!N>>YybSg]AwDAVskdЬ0ֶ60gaeͲ,RB),Ía[J+i#˱Jw +:0[q4/YҸ# ã5$ ƹyUF:kf!zƗO:4)`[妦@2R2v1MTCmN*aP 6$/G@Wx=iam˻.΄2SQ@Hrbm+G!90(vFTM5+2F41a&CjDt֕oz^oꅅڎߴ`oK5I@77؆dkB0`9E!q`PC!02̃#&ۇ+̷;.ί{'ۿv¸!T*@JNO iZm9GL?,okǁ_;89?$G/Ǭf1K7YY3QBħ5o4wj.VXzgeaYjۨ&+v) :m B}"cƃ"ۿt5c{7mioWr(I=xD06|: _-}o?wڡM&̓@NO sE7);7uN=tL-þԷ uI O:`dǶͼh7`-%Hq`HkV >W6B}b0۶K6`11'׆1w}X[~܅3k6.ޙW[.֛}]/xY.p5^<|V$qÄoVl㫾Pwgec~]s7/E9\eˎ\>p^nzBU0Ԑ[֭۴jݦqFƴyߡ>v`=\S}jZ jꔝV]j\݌gųtbڸkttL-x]xgoɉ'lh-|t2؊N#ZUq"7Gc¿]G²޽;}x+RBӁר! }TaVh0ۉ XSY"cd))|[?[u}c &^#_(hltLjs$63G2Hs2sXV̳hgH__WW٧mw !P0!-3[{{{]+/1gT^]:z!]no>E蛕^W+ˀg ows-ZD>5%kkg YZe]wkao#=tQ?} !#DI]hQ͂>3&B?^䪅wo]:8\]ٴR io;_ xOY-SD4[t .ؽ<*.[ @ُC !Ч zOfm"{]{_ .֫c 1~lv䲫M|YNIIc[ ;-¿E[+s(~];vFז s22m>[4 {[EBO3uwzmQQѦ[W>:-j& BMZMx'DVgdf6D+Dm+W9 eYDZZ ð GGaCH$ 1O5B B!Pw}"ݸ8NMq!O`0y}">C,/[JifSUj:@ӻ^[J[7/ʫd q)ůF'5o棹43F5=kBԴq60u\,-]&bbKzyu3;DLٝ1. &ނ^{<|xݏ/Ϝ,ѫoknHD^hs4בpDY Ŀy0"s E?}\ 1&֥˗2|⽘$ZFUU4Ow ȄzZQ%"}}4LKO_G!AI %"=}=߬JrbN[H* $ąy>ֶj>c8]K"߼IHݲU[ȾKY+51Ėr˗@>OHY:!I9-=jJOV*h jK:4Z{d(qawU !fA~ vlt+/w?GnfU68N[6phȞ-;9߻|^SϿ0*KyroYԶٴdo7v +Okv|?j~ q#OD$_ #ĕrkmC"U2aȳV{٫o-]Ho.}c;jWVWyJu(!ۖ~ۼB?kTRޡCmֆD~v?‡?u<}GuV$/{k5wZf/&):Uڏmb[((~Ƶ̢co DBՋ:uwx|9Z r*IRlçq;\w#V yhzhlߕ7#NNkuL">2d7jk ٝlԥE;6nаe5197C^ v0UV؜!|{{5hu®)D$$l>+ڿ;4s%nt&^[}j_Yo -k;g׊F ^%.9qlO^wF ]}eQ>gI"ǧQ#f]G {F ;Z3N.->/(&dq6:Jnۺ'ۚIݹuvǴћ ]ًË7\'g UT]͍Us:4j4i("ccVAEf#4jl:u^JzN =+NBOM܆QIi#N*G5veCNNsTl>{0â'Oku+8n;oDOƨtUm60Ò.=x,'!a[4twsv5twn^kp~PM_ݨak5R&Qڃmc~oѰkΓnYۍ]ZؾmBgo:n;&nӬ !PFB҃S{4Z`22&zXPFD8c͚5=ZdVڰӨ-w@Fo$=L}kI g$>ܸ]ũ8vp藯\2]hAO;vV16…{R""Խ]z qfu2R(/}ptRݞ]pڵ۔9uz:1E*8,k\ͥNtDV;ϷQy=]팛A׍li0:wi&6)b3 3Tzk^LBK?{蕢6(pfmY .NH;ξ[O݋Hg9&Cv{W)!N'ˬjYe0R%1ƆB\t@J]~507͚X^a茧5FDD,~E-f$ek4zq%j "RnNeݏX"!| }d@'unDDdfy("Q siԒطY\J78/}.27d̰qaR*#- (̼ÖiZJ||I U1-%r;kUFO=.]Se(++2&fo_BqRiTdjo]*G\ګukv_|s\fsivbJ6lcM+~%e9>uf19eY%^ H:o'h3GDGgZֲZfqoc bcb GEDݪmf:"%BP jiii+ʅD"_%ovIMDz/NNZIBDĖvs)r1AmG^EQg2HLeolZsC*Oħ||,\9<'iԵt-J*7kjva˶q2p\մnV޾.CgoӫQ3we_T5~3~ۄI[/NHK~!*.3b,,#>f=@c&xDDXS "^/x>򕐐Y} Cwcթmtwjrʹ&5Vrm^l̞q`u=G5_{ӆ;mY"ms'V?[Fkeqbd ^^ݶ0Mj_/ϖmLe &T^M{izsztY}&aNۑ;8]CϺ [Xpu_OFwQxf_ݼvU|x  ;l::QG9EVm]gF)#hb֫ Hyy/Էi5uF|dy~;/d JT6e񀚹7sBNii!WڔH$q' +oo:ɂתYSse`` ?1 xREP+d&*4|15%T:@3 h(5 4BPPj A @C!h(5 4@AQ;;874bըF$Yم}yvlo nNe.wL. ]~)'"7twrlDzI=;0GzN.n: aF-˱$_]3snN޽mĿéƷo7vi1}1vjqʡ3l""R4ѳC T^$oܰϼ Ivc3oۣ[>΄Ʉ:[4k? 1:=Q+7Rǥ^~;"2&zXPFDB{6^_^r/ IDATf(@ܺMj;ለ;לg`ȃ!ୃLGFF3i™b#v_|f7M/Nqɾ;] ?*`a|fڙl't-+0voWmSsS"%jv=4wDvy.#" ZM,𶫏_|pXsӺOy'8X?B >RͦQƥmfCt:OJ>C)f8uhG >5x[oVd{v8XFD$D nӲ]ͥCg=5k|;[ W?rl\ wVsˁK8L\=݀HY9سvܹ5.ːvѺ{:?Z&D_8y\^Ŵ5J^g?{Ba8s,+S*W$F6K1[U7ҵٕYn*WC:ܜFDyv b$<~sI*h!!u+qw*MIz5> u*1ݻV63l6kľ]o:nY1x2תn‰D|ɀ} ^Ô#оBr_W7זY1f($T{Rɝ+e[#"">&*̚)R 6*ZQ 嬹5QQtDDD4̖}zMX9Bc36|NW;F6:ًԴW"̨R""hkCLGgʐX3sS8526̺e9A 7U ]"<ߌc ^ {X Kıx]|I'VDmce"M[fͱVE-3F' dU'FʬX)8m6MyccfiA>dlV˂a ̌hDDɉ 9Ss3d3;5:kkFt5Yv߰1cTV {=^?rkV̪i^!iWmʼ'S&_r \S |Q땚ip}WN=3$32Ivca [Ԙ :(mM gk=+ߥ |= Ks{*On%%J{r / ""ҳˋ?OiOKG%ʈU,a ̤ʈt*XkI3r=_cc_#>^4"ʴjWZSOmN*O cljɻ/k9I*hfzqz>F jm+#>5Gd|^ߩ{¡HD+ 5RUYK3y8{t]=waW[-gvqj=隍vZhv mXӥq{FBt͝Cbf(I& 2&%rLa&O'o xN*R*FFE99&!{]ȑA<<'>bߠV]woiJ~ԴlmJI$8X"R|U(תYSse`` ?1 㤪<ג y )7GT]Im'"pF*Uh1| o01Z ~X+Sl~G[Nyеqml\_ -j$#hg h]թv#=H[ L̔]?N iX!m:qou{ nT?HjUs(]9y4:OEjٷqi[ِ-g.]:9E}Z6p.N "ʼ2O=ϕܕ'WuN|& }NW oo+B"kdrzvZو#δiP+ߢ#g ڸ<f.VZ6c FJj^3AiN۰xbQa1:w<{ɏ1CyԱ&*J/kuQ+!6*'بXbE ( ??qx3L~Ƚq]_AW0 1 o*\g٢[\v G&W9h-͒% d,c8c^ϜyLLD Du'*+]^WJq2^yDV9"xtwK$X[zVĕkи˃C!#j+_ OH&,(`U+ X Za)kc19'f[r5߱{^qcXmr-{*9n{/ذ6,/L׷:֭]͵혃2HӪ?g:ήmF/-xr_ 1&MyAd2M&K2,99yMʋN.4qXŁ*#(JšaaNutuKBii!W/[8$ ˲DZ,0 ˲<6d8(dתYSse`` ?'R,LQm!WQ@P+Z2WCi*o0bC *W< F1i ]g_^AP+</uT(|7&Oʮ]Qaa"DDKeai!|H-mmy8땼v( WAP+Z #0 #6ŬyūW9'<-mr46N5 $6Vȣ|@q522QیA~Iq@ 16)*!LE1)~BmR^oV1qaĖ5C%D!^nQ1  %1N)2iL*T(+R\&|?BQׄ&^cz,+Xy^ʳ8*Bh+8*f/~aP+rCP+lnTTr+N 2DLi)~8,_,Zbؒ3(*/Sq= F!9^-CQD1 خ&/WP (;)E4q@q( 7@P+Oy|0IJϋYM1Ƀ˲'(>U[PS[N59KV0 #O]"K|!@ 9&;YSqBv_')ttMnMm!h&QI)c%Plu}MiJj=sy(X%(6J)MUq@iZŨ8aeA@~UMfyܩD,e@0F+y&S|USKiZad2QxvAiU/DmJS[OmR [j_EaoFCP+p |["\} (V rŷZ!lHS*/ЦtYUL5҉3ʧBI2(|[U@P+KqX)~*M,/1[z@TW ( wBP+<[کԴ&NeU>\ #cwS 1{}U6<2Vnr+WZaHULaQy$6%@[R[TUߪ-oV)e5Ւ쐖5,(%6ʡC&S-oV8jkbJpP{Ŀ ZBRT"\u QAP+f5Q;6 PhvU=ec rkڤ-M-\Y=گB^n u _;=|-_^YvzV4j(a~qHf5 JKɭA +7U.̀4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPE,\ _#,,e1MI Pʽ?}<˲U(8j(DRz5R$XA @C!h(5 4@!'J?x<UPHyܽK,aee<໅?B ~t}@!:%%5Ѣ \-j A |S O2]P@"'|e)= {ܸo*?O2?/M٢Ww((cV|z@yAyU),~$MJGP'S_(9XΤ1ƞf(kKLZ'y(GD|U3݉v1fLʆ sguLb˹u1c#R_ݲ߀b3tVk6p%$W_Qdª9?*4pmI]svԮ/|&#nXqJcj_ϭCDw.;p/1_Z䄤DUYV[v@ S>;)'_Թ]W}v'DD|"vڌD[I XʡU]r{e}c [ܯIiG^aK5sov_?\0cK {Fp![N_݅5qɥ$AH~s'vʺ;DG^}̹[{ѣvFRSsS3JIg~j⟾Upfm,.4+Kcztސ!%\=tcn~GM'j؀w=(*Өb& mXJ2.h}aN:#Kn:"3k2h@ZS!ޮv\~eYؾN,4E]{OF-'b^~S'uk{)ʙc/u-!綵j5ɞZsּKsDDezBN^wgâS].֣cR[iqQKńl|pn #Fwbd^l; Vy_uyMM {\h4 $@$N@Bn>àc[ I֘OID & Iy4c8lQA wmjș[mZil{֯sTu""+5r/Ta&CFd-GjZ߅KiVKeCJiG k Q[bŢ>5cL+X-j|6+7^n?BN>6c9'&}|褤ϪçOUk{'H=xxf>w{M.ז,s/Z>vNgr|Ľx\>ekX*]8z0߾' *zqNCj\20R yg੃ .x6Ld^[N9g6U>}L\ Э:h~JDg[*:hK[|n528o3b'v(2{_7ݮ>~{`E,:?N=);_Өa,?u)sF${u ޫ=nNjnAͫr*g[[k#n QS(4U6wƣ".Ohfm|ƴm7}^Un8QvAEm:xtU'ayk;m;?CnIj9WP\( >q.k7gؖEs| *HmeK^|T_7Զj%ݸ/=*U^5qCޠM ~Ezz ޽{[נA)-uN4BBlcfa|ջu"FϦm^>r>F8֣[Uc-S+*3 c,JmXtQ}F~S'%yVNpSCHObMsLXc􄄼ߜ xZS/'K ij.\8w_JDDBZ[|JB7%ڨ.eֱ!KZus3oՠэ-Y5!.'f inŒ]]OK|w5 혣UHbͺU׶lяf*L qpp>lbVSaTUAjf XLs^eqY% dLhgMkaY$1>rjϣܫ=ءTo c*30c㈈! > >:V+i`L̍Y""X(A&,:"&ƢMλJXs%8!SX:Ș|. 3y)3Z6pϦη>dp{<kX&+zt?RchlXSK 6!.A +"¦TVfY3b5R܎itTtMm#""AUJIEX[+[M>Q-1K u v)R|l/(ci\lVV/eVmF~cQˈH?) cYr+BzzX.,>>6ɴ5#3{޴,͘8t]PJ]w>5qcv-/tteiizYQ[,X] ׎}y-gMH,99 ¡J*Æ.6̗DJ 5֪zbOz֣]v"",MGdAfnbÛ*C$FF$6fiڪQP\,QLT4OX"x""œB"x*lZLRĄRa,K3`10L<ĠnoТ "mF55F\e˩{G;O #ҳ9ţ{3FY\|T/,ףD_RE|\T#">:<7jn+[NˇV{L3S/mkg"ZCD7Ddr\>>9j$ֲZb/n+v% .:^B3r}Ψgê FWORSRRe$ȤH|T /h!%113n̼o̴dD;-gm^dB҃O9o?:Y-U&hNQ}Jyc(\<ʳF>>&d/f34-9CJ_Ca|gΜED'OrSD*k2=M蔌wOalccHD& oD<_߷nd76mjQꡳ_L[a769!'S>>~.~!#ǧΡu[nDf$H=|eW|̋3bJfc$P|!ϓy ްYz_Wyë> Ir;GsW;LO>\zKܶtAȈ}:R&QTLDl[~ћ'sǤLYzK[s֪{ybmyͅyئTުNe̞۱Y@;RFqCmٺe-f*eV}r/\3r!#й^?r$ҩA-}J}s78#55555]*y~y/LΖM!߼-# kq0yS̏SZԈXhoYy?$fJ +xΫXҦ٩ i>1q:B6Yy`azeFWU1tkxzn@DM"f/pλOאDDes__vs:ڰDf ΋[4t-k~KjȞlXʚhVڝ+w jeU>/J*4s0&MyAd2M&K2,99yMʋΤҧ$ZI[])Xb#.cFGaҹi[.~Kh: Gl`z[6@ނݕK[{J/Fq'&QaѺ^/.\`ggO^DZ,˲8q0BesCdzѕɏߌu[_)۩RZ5tuvt1KHqKhᝐ{?/L,xZCvl$="#~>ȸ^~W٭UqBG}0rՙmJ5 & jEfUNLJWVCO_$UW*c-[oTO}Jw_yA @*h|' 7i@!*_O2j ]P酇[YY)nFFʥ?r*=zٳg#areY366lo<Gο/@P &Pj A @C!h(5 4BPPj A @C6l*^5IENDB`kraft-1.1/manual/images/en/kraft.adoc000066400000000000000000000755461450127457600176010ustar00rootroot00000000000000= The Kraft Handbook Ronald Stroethoff, Klaas Freitag :toc: left :doctype: article :author: Ronald Stroethoff :email: :description: Kraft is a Qt program for organizing documents like quotes and invoices in a small business. :keywords: Qt;office;bookkeeping :experimental: :imagesdir: images/ include::locale/attributes.adoc[] == Introduction Kraft is a Qt and KDE application to organize office documents like quotes and invoices in a small business. It eases the creation of documents and helps with repeating tasks. Using Kraft, there is no need for fiddling with a text processor any more. Documents are created by a few clicks, edited, generated and archived automatically. Kraft generates high quality PDF output for printing, mailing and archiving. Feature Overview:: * Simple creation of offers, invoices and similar documents. * Customer management, deeply integrated with the mature KDE KAddressbook. * Maintenance of document relations, ie. Partial invoices vs. invoices. * Templates for document header- and footertexts and for document items. * Pre calculation of item prices. * Material management. * Configurable document creation in PDF format for print and email. The code of Kraft is open source and is released under the https://en.wikipedia.org/wiki/GNU_General_Public_License[GNU General Public License]. NOTE: Kraft is driven by community of users, coders, artists and others by voluntary work. + Also this manual needs contributions! + + Learn more on https://github.com/dragotin/kraft/blob/master/manual/Readme.md[how to contribute]! == First Use and Basic Configuration When Kraft is started for the first time, it automatically enters the initial setup process. During the initial setup you are asked to select a database to use and give the name and address of your company. You can fill in your company address (that appears on the printed documents) in two ways: in the setup procedure use the first tab *Select from Addressbook* for to select your on address in KAddressBook (if you have filled your own address in KaddressBook) or use the second tab *Manual entry* for to fill in the information of the address from your company manually. This step is necessary for the correct generation of your documents as the address is automatically used in the document generation step. image:company_adress1_EN.png[Company adress,float="right"] After the initial setup, select menu:Preferences[Settings]. That allows to prepare Kraft correctly so it can be used in a proper way. In the Preferences dialog we have the tabs: *Document Defaults *Taxes *Documunt Types *Wages *Units *Own identity Each of the tabs allows to enter useful values for the specific use case. === Document Types At the first use you find a list of different document types, such as: * Acceptance of order * Delivery receipt * Invoice * Offer image:documentype_EN.png[Document type,float="right"] Translate this types to your own language. You can also add new ones and remove document types you wont use. ==== Numbercycles image:numbercycles_EN.png[Numbercycles,float="right"] Each document has to have an unique identifier that identifies the document. There must not be two documents in Kraft with the same identifier. The format of the identifier is configuratable in Kraft. For that, Kraft has a concept of so called number cycles. Number cycles are used to define the form of the *document number* which is printed on every document. All documents of a certain type have identifiers taken out of one number cycle. Each document type has a number cycle assigned. Different document types can use the same number cycle to generate ids from. That way, for example the document types Invoice and Final Invoice can use numbers from the same number cycle, even thought they are different document types in Kraft. Number cycles are identified by their name. User can create new number cycles and edit them clicking on the button btn:[Edit Number Cycles...] The format of the document numbers are defined by a template that can contain normal, fixed characters and also some variables that are replaced by the respective values when the document is created. Each identifier needs to be unique, and thus has to contain a counter. Kraft supports two types of counter: One (variable `%i`) is incremented globally for every new document. The other (variable `%n`) is reset every day and starts at 1 again on every new day. In addition to the counter, more information can be added to the template form an useful number. Examples are a constant text or parts of the date. The default numbercycle delivered with Kraft contains the year, the month and a serialnumber. That way you can compare offers or orders from last year with this year or the month April of last year with the month April of this year and get on this way an impression from the results of your business. See the following table for available variables which can be used: |=== | `%y` or `%yyyy` | the year of the document date. | `%yy` | the year of the document (two digits). | `%w` | the week number of the document date. | `%ww` | the week number of the document date with leading zero. | `%d` | the day number of the document date. | `%dd` | the day number of the document date with leading zero. | `%m` or `%M` | the month number of the document date. | `%MM` | the month number with leading zero. | `%c` | the customer id from kaddressbook | `%type` | the localised doc type (offer, invoice etc.) | `%uid` | the contact id of the client. | `%i` .. `%iiiiii`| the unique counter | `%n` .. `%nnnnnn`| the unique day counter (combine with date) |=== A number cycle template needs to contain either `%i` or `%n`, if not, `%i` is appended automatically. Both `%i` and `%n` are numeric values. They can also be padded with with leading zeros. The length is defined by the number of i's or n's put into the template. For example, if a daily counter with length of three and leading zeros is desired, `%nnn` has to be put into the template. This works up to a length of six characters. ____ NOTE: The "design" of the numbercycles and document numbers is very important. With the flexible system of templating Kraft can not prevent invalid number cycles. It is in the responsibility of the user. ____ === Taxes image:taxes_EN.png[Taxes,float="right"] In many countries there are two kinds of VAT-taxes for sold products. A high level and a low level. Fill here the appropriate amounts in for the high level and the low level. If the tax-level is changing, then you add here the start date with the new tax-levels. === Wages image:wages_EN.png[Wages,float="right"] A list of wage costs is maintained in Kraft. The items are used in templates and during calculation. All data can be edited, customized and new items can be added in the Kraft Configuration Dialog reachable through the Settings menu. Remember that these units are later used in the documents, it is therefor important that you translate them to your own language and to fill in the correct prices. === Units of measurement image:unity_EN.png[Units of measurement,float="right"] A list of units of measurement is maintained in Kraft. In Kraft Configuration Dialog reachable through the Settings menu can you edit and customize items already in the list, and also can you add new items to the list. Remember that these units are later used in the documents, it is therefor important that you translate them to your own language. === Own identity Check here if the information that you have given during the initial setup is correct for the use in the documents. ____ WARNING: If you made the choice to use the information from KaddressBook then is the information from a later manual entry ignored. ____ After we have made some corrections to the configuration, we go back to the main window.Here we see three tabs: * Documents * Timeline * Catalogs == Catalogs Kraft supports so called Catalogs in which templates for document items are kept. With the catalogs creating documents can be significantly accellerated in the day to day business. When creating new documents, the items templates from the catalogs can easily selected and moved over to the document. Since templates are organized in chapters entire documents can be prepared in different chapters to be used as template documents. Of course the items in the documents can be edited after they got picked from a catalog. By default Kraft comes with two different catalogs: `Material` A catalog of material that are sold, with their purchase prices, the profit and the sell-price. and `Standard Templates` A catalog of standard recipes of work like planting trees. Both catalogs can have chapters and sub-chapters for to organize your templates. First we are going to fill in the === Material Catalog A catalog of material that are sold, with their purchase prices, the profit and the sell-price. First we are going to add new chapters and subchapters. ==== New chapters Select with the mouse the column-name `material`, select now in the context-menu [Add a sub chapter] and add an extra chapter like `Trees` ==== New sub chapters We are going to ad sub chapters in the map `Trees`. Select with the mouse the name of the chapter where you like to add a subchapter, select now in the context-menu [Add a sub chapter] and ad an extra subchapters like `Loaf trees` and `needle trees`. After adding the extra chapters and subchapters for dividing the material, we are going to add the material themself. ==== New template Select with the mouse the name of the sub-chapter or chapter where you like to add a material. Select the sub map Loaf trees and select now in the context-menu [Add a template] Add the extra materials `coconut tree`, `apple tree` and `pine-apple tree`. Fill in the price that we have paid. Fill in the profit that we want to have on the material And fill in how much is in a packet. image:catalog_material_EN.png[Material catalog,float="right"] After this we add also in the map 'Wood' a item for a 'support pole' for later use with its price. Now we are going to: === Standard Templates This is a catalog of standard recipes of work like: * planting trees * cutting grass * transport costs * planting grass * sowing grass-seed We add here the standard work of planting a tree. Select with the mouse the name of the chapter [Work] where you like to add the new template, select now the context-menu [New template] and the extra templates `Plant tree` and `cut grass`. After we made the new template, a window opens with 4 tabs: * Template * Time calculation * Fix costs * Material First we go to the tab: ==== Template We give here the name of the new standard template like `Plant tree` image:catalog_standard_EN.png[Standard catalog,float="right"] ____ WARNING: be careful, this name is later used in the invoice ____ we select that this is per piece and that the margin is 8% and that the full VAT is applicable. ==== Time calculation We fill here in a number of work with the time: .Spent time [cols=",,",] |=== |Dig hole |32 min. |worker |Place tree |12 min. |worker |Fill hole |17 min. |worker |give water |5 min. |worker |=== The cost for worker which we have earlier filled in is now used. image:catalog_standard_work_EN.png[Time calculation,float="right"] ____ NOTE: in the invoice we see later only Plant tree, we will not see the parts dig hole,place tree,fill hole,give water ____ Now we go to the tab ==== Fixed costs and fill in: .Fixed item [cols=",,",] |=== |Transportcost |35 euro |1 pcs. |=== image:catalog_standard_fixed_cost_EN.png[Fixed cost,float="right"] After this we go to the tab: ==== Material Here we select btn:[next], after which the window [Add Material to Calculation] opens for a selection of material. We navigate to the map 'wood' where we select the 'support pole'. .Used materials [cols=",,",] |=== |1 |support pole |3,5 euro |=== image:catalog_standard_material_EN.png[Material,float="right"] We go now back to the first tab template On the first tab [template], we can now see the overall cost per one unit Click on [OK] for saving the result or on [cancel] for discarding the result. We make a second template `cut grass` we fill in `cut grass`, as unit we choose sm (square meter), on the second tab we fill in that we need 3 min per square meter. Click on [OK] for saving the result or on [Cancel] for discarding the result. We are now ready for the first invoice. [[Invoice]] == Creating Documents === The first Invoice Open the tab btn:[documents] Click on btn:[create document] The window document [creation wizard opens]. Select in document type `invoice`. Fill in on the whiteboard content a short text about what the invoice is, like: `cut grass and planted tree for mister Jonson` Click on btn:[next] Select on the new window the name and address from the client. (if the name and address is not there, click then on btn:[new contact] or on btn:[edit contact] if you want to edit the contact) Click on btn:[OK]. Now opens the window document [items]. this window has 2 tabs and the 3 buttons on the top: * btn:[Add item...], * btn:[Add discount item], * btn:[Show templates]. In the left tab you can see all the items that we want to place on the invoice, on the right tab we see the text from the header, the total price and the footer. If you click on the text of the header or the footer on the right side then the window changes in such a way that you can edit the header or the footer. Adapt the header and the footer to your situation, on the footer you can place a text: `We make your garden-dream come to reality.`. Click on the button btn:[Show templates]. The right tab changes and show now the earlier made templates, we select in the group Work, the subgroup Plant tree and click then on the button with the to the left pointing arrow on the bottom side. A new window [Create Item from Template] opens. Because we have planted 2 trees, we go to the field [insert] and change this to 2 pcs. Click on btn:[OK] for saving the result or on btn:[cancel] for discarding the result. The window close and we go back to the main window. We click again on btn:[Show templates] and select this time `cut grass`, we click again on the button with the arrow, in the opened window we select that the grass-field was 24 square meter. Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding the result. We add now manually an item by clicking on the button btn:[Add item…] and the window [create new item] opens. Because we have delivered a special tree, we fill here in the name of the special tree `liguster`, at the field insert we fill in the number of the special trees that we have delivered and the price of them. ____ WARNING: Remind that in the catalog we can add a profit on the price of the material, in the invoice and in the offer we can not add a profit on the price of the material. ____ We have now an invoice with 3 items. Click on btn:[OK] for saving the invoice or on btn:[Cancel] for discarding the invoice. We click on btn:[OK] and save the result. Your first invoice is now ready for sending. In the window documents we see our first invoice, notice that this document has a document number which we can see on the left side. On top of the window with all the invoices we see the button [Print Document], on which we click. From the invoice will now a PDF be made which we can print on paper or send by email to the client. After this we are going to create a offer for some work in a garden. [[Offer]] === Creating an Offer The client has asked to plant a tree, we will offer 3 different trees which we can plant. Beside this, we have seen that there is a lifeless three, which we will offer to remove as extra work. image:create_new_doc.png[Numbercycles,float="right"] For the total price we do not want to show the price of the removal of the lifeless tree and we want for the total price only to show the price of one tree and not three. Open again the tab btn:[documents]. Click on btn:[create document] The window _Document Creation Wizard_ opens. select in btn:[document type] > btn:[Offer]. Fill in on the whiteboard content a short text about what the offer is, like: `plant one tree and removal of lifeless tree` Click on btn:[next] Select on the new window the name and address from the client. (if the name and address is not there, click then on btn:[new contact] or on btn:[edit contact] if you want to edit the contact) Click on btn:[OK]. Now the window [edit document] opens. This window has 2 tabs and the 3 buttons on the top: * btn:[Add item...], * btn:[Add discount item], * btn:[Show templates]. Click on the button btn:[Show templates]. The right tab changes and show now the earlier made templates, we select in the group `Work`, the subgroup `Plant tree` and click then on the button with the to the left pointing arrow on the bottom side. A new window [Create Item from Template] opens. Because we want to plant 1 tree, we go to the field [insert] and keep this on 1 pcs. Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding the result. The window close and we go back to the main window. We click on the button btn:[Show templates] and this time we select in catalog Material The material-catalog opens, and we can select in the chapter `trees` the subchapter `loaf trees` in which we select the `apple tree` which we made earlier. Click on we btn:[OK] for saving the result or on btn:[cancel] for discarding the result. The window close and we go back to the main window. We add now manually an item by clicking on the button `Add item…`. the window [create new item] opens. We want that the client can make a choice from an apple, a pear tree and the liguster. Therefor we are going to add also a pear tree manually. We click on the button btn:[Add item…] and the window [create new item] opens. We fill here in the name of the tree `Pear tree`, at the field insert we fill in the number of the special trees that we have delivered and the price of them. We want add this to the material catalog for future use, therefor we select also [select this item as template for future documents] and we select in [save in chapter]`trees`. Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding the result. We does this again but then for the liguster. We have now 3 items with trees in the offer. As last item we add an item with `remove tree` with 0,5 hour for 32 euro. On the left side of an item we can see 2 buttons: a button with a flag and a button with what looks like a page. We select the upper button with the page after which opens a context-menu with the items: image:context1_EN.png[Context menu,float="right"] [Item kind]->[Normal] [Item kind]>[Alternative] [Item kind]>[On demand] [Tax] [Move up] [Move down] [Lock item] [Unlock item] [Delete item] We choose here [Item kind] and change for `pear tree` from [normal] to [alternative]. We do this also for [liguster] and for [remove tree] we change this from [normal] to [on demand]. image:context2_EN.png[Context menu,float="right"] Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding the result. We want to see the result and therefor we click on the button [show document]. We see now that the prize of the pear tree, the liguster and the removal of the tree is not used for the total prize. When we are happy with the result, we can click on the button btn:[close] after which we click on the button btn:[Print Document] for making a PDF what we can print out or send to the client. After your first invoice is now your first offer now also ready for sending. [[Acceptance_of_order]] === Creating an Acceptance of Order The document type "Acceptance of Order" is sent subsequently to an offer. image:acceptance_o_o_context.png[Numbercycles,float="right"] When a client has made a request, we will send an offer in wich we describe which items we will deliver. Hopefully the client will give an order for the work. It is a good practice to respond on the order with an "Acceptance of order" in which we describe all the items we will deliver. We can make the "Acceptance of order" on the same way as we made the invoice or the offer by selecting each item and correcting the number of delivery. This takes time and we can make errors by forgetting items or filling an incorrect number. It can be done quicker by selecting the offer in the list and selecting btn:[Create Followup Document] from either the context menu or the main menu. We have now in documenttype the choice from: [Acceptance of order] [Invoice] [Partial Invoice] [final Invoice] [Progress Payment Invoice] image:followup_1_EN.png[Folloup document,float="right"] We select here "Acceptance of order". We have now a copy from the offer as an Acceptance of order (do not forget to adapt Alternative Delivery items and on demand items.) image:followup_2_EN.png[Folloup document,float="right"] You can do this also for the creation of the invoice as a followup for Acceptance of order. Each document type has a specific list of follow up documents. It is a good practice to describe on the invoice precisely what was delivered. [[Customization]] == Customization Kraft can be customized in most of the graphical user interface and in particular in the output it generates. === Output Document Customization To create PDF output documents, the document data that was edited in the Kraft app is filled into a template. The template defines how the output document looks like, ie. by font settings, placing of elements and such. The file that is assembled from data and the template is converted to PDF using a special document creation script. All that is started automatically by Kraft if a document should be printed. Each document type in Kraft can have it's own template that is used to create a PDF. Which one can be set in the Settings dialog for document types. ==== WeasyPrint Documents With https://weasyprint.org[WeasyPrint] Kraft uses a very powerful HTML and CSS based generator that makes it very easy to create highly customized documents which fit the users expectations. The general idea is that Weasyprint loads html output that is processed to PDF. Usually it is considering a Cascading Stylesheet file which has a huge impact on how the PDF document looks in the end. To use a WeasyPrint based template for a document simply create a template file and save it with the extension *.gtmpl*. With that file extension Kraft automatically uses WeasyPrint and also the Grantlee templating for rendering. An example for a WeasyPrint document can be found in the Kraft package in the reports directory and is called invoice.gtmpl. To use a WeasyPrint template with one of the Kraft document types just select the template file name (with the right extension `*.gtml`) in the Kraft Settings Dialog. From version 0.95 on Kraft ships with an example document in the Grantlee- and WeasyPrint format. It can be found at `/usr/share/kraft/reports/invoice.gtmpl` or https://github.com/dragotin/kraft/blob/master/reports/invoice.gtmpl[online on Github]. To effectively change the look of the document `kraft.css` (https://github.com/dragotin/kraft/blob/master/reports/kraft.css[on Github]) needs to be considered. It defines most of the look. ==== Template Variables To generate the PDF, Kraft has to transfer data from the document you have been working on in Kraft to the input document that is processed to an PDF utilising WeasyPrint. For that, Kraft uses a text template. In that, Kraft replaces variables with the actual values. The syntax is based on the Django syntax for templates described in the https://docs.djangoproject.com/en/3.1/topics/templates/[the docs]. [[Menu]] == Menus and Shortcuts === Main Application Menu [[File]] ==== The File Menu [File]>[Quit] [Ctrl]+[Q] Quits the application. [[Document]] ==== The Document Menu [[Show_document]] [Document]>[Show Document] [Ctrl]+[R] Opens a window with the selected document for showing it. [[Edit_document]] [Document]>[Edit Document] [Ctrl+O] Opens a window with the selected document for editing it. [[Open_document]] [Document]>[Open Archived document] [Ctrl]+[A] Opens an archived document. [[Create_document]] [Document]>[Create Document] Opens a window with a wizard for creating a new client-document. [[Copy_document]] [Document]>[Copy Document] Makes a copy of the selected client-document to a new client-document which can belong to an other client or an other documenttype. [[Follow_document]] [Document]>[Follow Document] Opens the selected client-document for editing. [[Print_document]] [Document]>[Print document] Makes a PDf from the selected client-document for to be mailed or printed. [[Mail_document]] [Document]>[Mail document] [Ctrl]+[M] Mails a document. [[settings]] ==== The Settings menu [[edit_template]] [Settings]>[Edit Tag Templates] [Ctrl]+[E] Opens a window where you add, edit or translate the tags (like work, material, plants or discounts). [[redo]] [Settings]>[Redo initial setup] [Ctrl+R] Redoes the initial setup. After this, a restart of Kraft is required. [[toolbars]] [Settings]>[Showed toolbars] Here you can decide if the `main toolbar` and the toolbar `Document Actions` are shown. [[configure]] [Settings]>[Configure Kraft] [Ctrl]+[Shft]+[,] Here you can configure Kraft. === Document Edit Window [[context]] ==== The context Menu [Context]>[Item kind] change the status from this item between * Normal * Alternative * On demand [[Tax]] [Context]>[Tax] Seems not working. [[Move_up]] [Context]>[Move up] Moves this item a place up in document. [[Move_down]] [Context]>[Move down] Moves this item a place down in document. [[Lock_item]] [Context]>[Lock item] It is not clear what is does. [[Unlock_item]] [Context]>[Unlock item] It is not clear what is does. [[Delete_item]] [Context]>[Delete item] Removes this item from document. [[AdvancedTopics]] == Advanced Topics This chapter describes advanced topics around Kraft. Some Linux knowledge is required, and setups should be done by experienced Linux administrators and should be tested carefully. === Using Kraft Collaboratively Kraft can be used collaborative in a distributed environment. That means that multiple users work on their desktops with their own Kraft instance on the same data. This whole topic is a subject to change, as Kraft will evolve to use ownCloud as a private cloud solution to store the data. ==== Sharing Database and Document Pool The simplest case is that two or more Kraft instances use a database together and access the same pool of PDF documents on the harddisk. For simplicity this describes only two Kraft instances. A typical use case would be: Two different Linux users want to use Kraft. They both have their own computer but only work in the same network. For example this would describe a situation with one main office machine that runs Kraft in normal mode, plus a notebook with Kraft in read only mode to view documents, check catalogs and such. For that, the following prerequisites have to be met: 1. MySQL or MariaDB is used as database backend. Sqlite is not supported. 2. The database is accessible with a mysql user and from each machine for both users. 3. The document store directory has to be shared. ____ WARNING: There is no protection against having both users editing the same document. Because that is dangerous and can lead to unpredictable results, it is recommended to run all instances of Kraft except the main one in read only mode. This is done by starting Kraft with the `-r` command line switch. ____ **Sharing the Database** The database server should be installed on the main machine or a dedicated device like a NAS. Networking speed influences the comfort to use obviously. Find howtos on the internet how to setup MySQL accordingly. **Sharing the Document Pool Directory** Kraft writes generated PDF documents into a local directory. Where that is can be configured in the Kraft Config file. The config file has to be adopted on all instances. That is located in each users home directory, in the path `.config/kraftrc`. It has to contain the following config value: ``` [reporting] PdfOutputDir=/data/space/kraftdoc/pdf ``` There are different ways how share that directory, ie. NFS or SMB storages. It is important that both users from both machines can list and access the files. The main user needs read and write access, read only users only need read access to the files. A recommended setup is a NFS share with autofs which is set up on the main machine. To manage file access a certain group should be set up on the machines with which access can be managed. **Starting Kraft in read-only mode** To start Kraft in read-only mode, start the binary with the `-r` command line switch. === XRechnung Support Kraft supports the XRechnung standard. That is a digital format for electronic invoicing, and it passed as law in Germany and follows a EU directive. The XRechnung is a XML file format designed for that purpose. To use the XRechnung Export productivly, a little manual work is still needed in Kraft. Kraft creates the XML file based on a template, very similar to the normal PDF documents. That means that it loads a template that contains static elements (ie. the company address) that do not change between different invoices. The dynamic elements (customer data, items etc.) are filled into the template during the generation step. In order to generate correct XRechnung files for the specific company, the user has to adopt the template file manually to the companies needs. Note that this has only to be done once and should be easy for a person with a bit computer experience (Basic knowledge about XML appreciated!). To adapt the file to the needs of the company, it is best to start with the https://raw.githubusercontent.com/dragotin/kraft/master/reports/xrechnung.xrtmpl[example XRechnung file]. It has to be downloaded and saved into a location that the user can edit. Open it in a normal text editor, such as https://kate-editor.org/[Kate]. Read carefully through the file without being scared off by the XML format. All user strings (ie. company name, address and such) are user specific and should be replaced accordingly. Find https://www.xoev.de/xrechnung-16828[details about the format] here to better understand the meaning of the fields. Make sure to not disturb the proper XML format and do not change places where the template format `{{ template_name }}` is used. Once the file is adopted to the needs, open the Settings dialog of Kraft and insert the filename into the entry field for the XRechnung Template File on the Document Defaults page. After that step, the btn:[Export XRechung] menu item will open a dialog to pick a filename where to save the XRechnung invoice to. This file can now be transfered to the receiver of the invoice. NOTE: There are validators for invoices in XRechnung format out there in the internet. It is useful to verify the format of the Kraft exported XRechnung. [[Credits]] == Credits and License Program and documentation copyright 2004–2022 Klaas Freitag Documentation copyright 2020 Ronald Stroethoff kraft-1.1/manual/images/en/numbercycles.png000066400000000000000000000317031450127457600210260ustar00rootroot00000000000000PNG  IHDR"qK pHYs+ IDATx^uX[ ""`ctzыM("`w.,s?v%dy]<>̜3{QXT  ;ð   N_,+55N30IHރ$kژ()*L0rs}ЫG)+q0H//;?aaaaaai1+6t@% ˢxg㘡kά=i(LcN) g[uǦ҂4Xo͘O$~cjKP㰄 yֳݎO}bLJ\cu*Åa.4>@bwz#ǖ85e;f:꾯]71sQ>G#b6}.TpsKgPԝ[6 }qFn*Kڳ`ї{ař.,CW/*2PTl"-T}ѡ,޺JAe^v{v 7v)6.lOD"*1Nߌ:N[;vN CC/,$\[I3sCQ+*1S"- Ͻ 7čؘ^;O>@M7t)vYQևdSM[k;;ڙk;GȍKRn`^0GdX':͟Ɗh$)gCzm( GGͰP%@DhޯB)FJDDh(4 B *F=i&"@CVs0%!Vp3F 1Y?:a)I=ev9G^mi%ATD{I ahU{MrU5O-K~,2b"J O)vxB4bRuReEl%}%nYB <Ʒ;8ŨJ^y׃*eɓTA~ȽRIɢViA}hT- r$A$!-#]AI(6v~N~GUUI0XM6!?k ߦL6Q A҄ĥeD8i$ =\AWC%%&f=C;! /u#$'_h deiPI1y@ @*.,A3uZz[e&;dbWYr( eg+)Iɒy9y} Q/NUB4h&ӯ[Jԝ̄fE g|k\Ea*HwQT\jɭA"@2Ə-dKiD-QhOETUIzvCx 6F\D?ɈJ̬s9ؤJ*u= B|yٵ_&.Q*zwooƋ`4ىOikI^tm (znjRDhtd}Tk1-4RAw2(ٵ deej&lY J.y; gn}@P}2K"m|2iP]9cöV[ ymцnuPPSso;׎ݗEDlZ)[[̄u&Bb*:s߁RzՎfPCFoI(X.ەkJaUㅁ5:[ϟpr79eyYM+O6-vaEJ|{w{6oR#^^fm5 9guҬ {-u^ke%žFD/q۳p+!*[mog؟ *I3'(]wz7;zVFl~xjn;[n_e!"";INIINI3=K3ne<[d t\wۈ2NM1+@e O{ #^??lӯjUI1ff6]yϝN?9k% k]yzik>sFo1ݴ{1!aI՞=%0F!wٯ{,/@TS+&; 70r_[~Ly=љU~9țrEqx0>oba1#KH3*~~nȑ=e#w)Mȋ*?~ζ֖n>!fzW,ZXDL"7-88Q.ܽh79gEb):.`JyK7Je^v{v 7v)6.lODrVCe}"1h!;Gd~._:͘λثd XՎJOi׻~E(Vz]8D.+dEuGȝeXp=Z}y}VL!e-p֛VzwŅSR~.}*Z%<,|Ij r>BTG=祇.GxE3u\ V/]zz~kf  LRRR̟?xX>.NcuaC4 U e\]{K@JVME6LI,܌QBsΩGzvUsbQqa Rm ,vp;{v.+$$E^x*âi6SܺJTQ=SQՒ͋:ω Yz+Ѐ&;}*~_yAj8Q$oXyaDԇ\נRݤA_~>8A^\u) G$I2eH)IHˉrˋ*t*-,،ʇ;F 2`H LHIBZ3͊Od|zeEYޗׯs]U[4RȪK")`f|^PGk.*d fۻW'6gQ@}r^)TJPy3^k3Rm̘ [h=u=e5M $>,,aSܩ3fUk-2h߲jv+YZ1˷wWi@*Z9*zb?۽fV It]g' HmGʋ;M[l,bkح8Rf=o;׎ݗEDlZ)U)%)Er2W)^B&_ur_q}!Bz~wWRwv\8PѳF<i1y]grB2 D((u3Q>D!Bjk®g,V5hwoA(,*CgJ bܥMڗFFFS1{no5e$L ?p⿒1IErdN8[!a?$fB矋;~?_UpõYaFc&!!;5sr$%+ᘵoz|301kuu{WVV!A3~Ǭ}#II_0101010101010101010k[QE/C^S.R2p͓k%Das<}bH|d؃OU.kwy $mU%i˰>>?qX{'0c K[]g[s6k$C5t_qzJ\c%w"@WIUݧv|!Ttw-I;Gڻ]]hffi=(,;#A)vd}0mǃ:a?MnR}U1dj1@[F6]N&5`T-aQ0grqh-A fvWAieZiH]b\0e9#?;XɤI}mC |Ol_'yK^%)rҽ~T$A*mM19wdd3s \;_Y/aدa             1c7?;3(/N$tsYkpM]m1iY^ҋ/4[B2L?@/nDJmggc Y>n$[*0T:7qVwǯ 㹴~>cFHu36-׺oj7)M;(%AWY݉ɏRS񫿵YzY1zzRC~9t% vqoy5'+K>j:P28(nl7ܯT̊ #MLL}mp'g~jenbh;q[3UTtp PkcV*6i54 ŠC& ഖY/#&% 1mWWlRz} UFEѕo4X2=Nq؈7}w$ hwG,c!#/Uφn4@*@SPPPv^oP 4շbcCW4~Rd&4^TAn>TNV.!+W''&fJ 8 gwdD 3N?D2 I)DwgÍ?[-?l+w %|h4P -F O/$@œ{;0L ;ۻ72eޭ!c; ijgCһ26}xr@k}L^z_UǜRGNS@jY:<<~W@>w쌛g2*b7\q**,UTȸHM.j~1>U< >Z(JҨ.Z-ơ#*ES,ZIe}P" 5ռ8jϹ}-U9=E?b(g%ː+;¿:q'^ξcwUm6 qH _yTl[SSy%p*F~3vf$k#c˂7ו> ,h>54[6Yagjhl/Pp׸[ZztڴA'7[DŽ SVF4'id_[sec::NV }{?qz=N7y]hBN Y8믫S<6[T j7V>yL93W9MsEآ7_j^H.]jBոuКᓖuV%O. vXM 31|kr-:Txk,n^]y҂wi}v4OGp!˲`0ξNE< >r_g[Kl<-ZZ ڏ k*Fs6yu\>>AD{ZՂG%TnȒ n9c= RIgOh4bد61101010101010101010kG1)*R7Z;~%>c3} e/Wv32; w._H}oݷ3wwtbt7sc#3穛B>p:BŏzX36244TuZg-(%QJIX` N \.cwh$wmKs/:G)~hOv'9k|%^vpVREjWlK*O{Ib\ЭGV~ZMW29{"w̥vvՄ/+y\mGX=RuhMb}3tܘy:ΒahAu2 -7fdO1֔$ aAVC}΂''kʆc=GzS|Fv/_7cY=•&vo|?ri}HyMC'nݎg]+OV.@e\\ڼ1qgh?vJv?K`3n?f頲?/ݿRS3749mm}sϾu[hAhEXw;q9l{BfؼiK:IxԃӃH}m! $)dsMtX3*/):N-=jVK6/~{kPÃ#H7yd=_4q  !1/4bb:O՗-M L+=-o9V;]8DeoÎ{NFV6eV.QQa ZR~Cŏ-XduJ  j)v%QV.@I**X"Q)&!V}9WeYtB|yjp"fbNd~ȣA%p=_':zmy;[EL$dQ~^j$P% *?)`T-^eɇAe/YN tXF*kkI|`C*IgK=\S4S|/@QolljUu7& `Kk֔"uK5ۭb]&6T6LJ+$VbG*{ccXAo8rZN3LwSVt:=[7Tܤ.ciDiE\4LN,Ta>6c=pb?Yf6;6K`8kFSnZ3SZJLyk.R%0rھO>Vl?I"&weM3KI~k׸PY K/s XtNWrw{˝ڀ՘aH+qܓ;/\aaaaaaaߛqLgt: UGNN$p~'OivPVVᝁ1>~޵ @Uxߐ.2/>!Mk j#I*H9t۴Q1Piυ,vQbv{:xl-.I3:<;Ѷ .G9ݘήbcn͋kݬ-ͭ/;*{zwȑN6^㎊ Tރc~^6.ޫϽ,EPaɵgWyY/,^⾫iĄ%U3!x# {~{riD!VVI&Ɩܯ?.+#5l,w[+{c2O>hcmi'a'I8f *mur舳~{RQ3~BO\va"X,E:yQyK/ݗ"N ]8$L @7|vnA1Kib3zIO'}g0+3޼d d#x8 hZ&fOUPUQZz^lgZzʛ"bROҊ2iȰU촰yX_gv݉htڬMh~NF74Y`yK}ݲgN$x=Y!Bs|eN7D.Zo])RS;5{ !`Ye9Y ciWYO!^ԉ9/r*ĻW!amCs\Wj}}ui53V>uԮYAJ$Zڽ D[{œYt4`iݼ6.}`JJgڃ3;$e`Á&ʦS" #]N2(;SXTL%b6~$J_˳)E6L.dDٟU 8ѷxbQ駦8FA+{no5=N7ðERja[3j4ưw-W/Bu[18>'"|x/шacvƏV,hl~&X6pڑ֝,3 8h$$ijp7m_vN8тc͛>I mmQQQ?c/B8 DEEeeeygG$ea ~acacacacacacacacaW3 Iܼ:0 k\I:]@ߗ[ڳ:aѭIa10L@       `#2QIENDB`kraft-1.1/manual/images/en/pdfpostproc.png000066400000000000000000001037351450127457600207030ustar00rootroot00000000000000PNG  IHDRM pHYs+ IDATxwtU̦JHA,)J.WA (RB/w "5;Ivg?@H# R9{<3s3ۻwg>>B!Bؿof>>> E!BqPwB!Bh̲A;>zB!( y1 ɑFaOlmm"B!xbbbu&@A9_B!xR ~ne9O!9..VB!x%tB!HHB!" B!B#!Y!Bt$$ !Bd!kFwg1=R%1ku`eyWz⅕2 ?❙ 'lۃmK@kz6bA# %R=vKa㩩꼔ibׄiGR"*8.oY˷qR5KӴhzTsN^Sۼt*XRUoY~{2nfغlӽ1Eł3쯗٫qϗd!^s5eZS#zh!Æco `[VcH],1⇹R"5;5c7T7O((IZqUvO7 +V=*K\85cƦa!g]U̸^fбB<7(iGv% 7R-(ߜ~ӝm 67eFsW Ihf.K1?ӻCJ(vH3O3L!鬻n+~?_h]c{o᠀vu#c&,ЕÆDJ[@|3V0ij\[I hD ~txI*D*^$Q8}9wvb.݉$Nwl2NJ"{7cE/(qz1Nk^j f{U@>qcY ڶI9ؠZZ5&z,~E+ˆur4ڏ|a=.br2iesn;CH/EC۵jm)F cˬI| !I渖s4MNֹa nĘ\}&|ׅq\Z7qwr9Zťd#Nh7f: "^3ñ}&|Em9ٛ%h=`"U6gc]GK= F1v1ND"v9m\8!AB %_Gr<9(^U5ԑ$>OO4u0]bmmgn,4y`֝lL(nE<_6n#`(*=[P˄~uqhˌu1%x?Ce_N+8,_yd23wDg(\ٳ:F.6j@ҙ:%C+G6ۊ\355 C}H={tZGadƵd_qTktN0N^X>Ge޹D2a-vuٷt-u+#R~9nW|7? [g}Wngώ[&ӿơXHܯg .Ɓߙ7%,tbN`L^KY$? +&cnk;t'dm¯S{ѸM&+cc"~5޶O?.MB}[ŏg1Z姐m; A| dVpՖElP1'Og-y]HoU7,3lE?T{JBcu$ F۹ UXatKq;Ӻ jG6M)yy7{u==05&R!o¸`[QGY(7bUSӒм1}W-ƟwPUzBFXH~- scR+:f; M2._|fA'Fm=uN'74'\3 FIx Er=8p ǦL4 AZ!,̈{y4Lčp4:|T-F{tG#vpv|0Yu&JtD$:ئL '$ʙ"iZTw%q!,FXZ!C #AGXY '=ۖũ̘ҟfy^EwO&xPJYK-p#3Wgd!NBTԿ4f|-WWܲ.[+r;lKAIdpEc%z6}W1VJ"4dNeeMqW@'N.pI Ίf{M:~7qPzCQ8lIp Rz/hr0"fjNpPpJHΝp\\Qե -{Oe@!v2R0h8v?vT k-hwl-ꈳ}8wCP=stxWP5㳖֏;/r'6{^3nhWhVhcՐLλ7ӿ-j<[43cR_:& ]4 ]smPBŌOYqG{? zU!5+=Z0 z>$pxtN;ˋ9{2+N$ :Q[q1_ڄLXy~oK:odtv{9ɺ{,k͒/fǐ}pܑEW!(h=+uU&CԵkhԨ1*W~[;#G2lPf͚{Ժc4qrrrL&TUEUUEvAWCF4ĕ)kTh9Y?AO֥n(ȇ Wгtʻ**婗;u-/D%1&;|n2R[)Hɏ¶ߏPE<^">)K<, S> ݅:.ٟYԚ?ǷU1XTAF٬祥((DmC(\}Cם+})ô={qI2~й@4F#fflݲ;[[FczUU`0`0(((!x{ʯZ.aiV Xqsҹ5jԦYO^vc eФ.>5nNFfVƝ3V4CzDF2Mc$Z!~ہuPI'|l6vlNTﲂLr׸uнlw@'|jABɁ_QjCdz-0KT ^}zS޻0!eEW?rxGTRVYvGѱQM*WFAȓK߾>jPUOfN#c}ik9c,+=6vOYvsHK?wlMjUw-w)]O1{_9n-U* a7Lw0WjVNzTqLd`_][Rj3:6w5iMg{έNdž5U3u-RާBDݯ"5ݫ[h)M+R}~:NMjP|%tg'1^k4f8m g6Ʒfu*4ه 5nmMqD]Yʧ ~*f}>_fvn؋_nTb:0괪]ʾ+nK U>oeҧ4Y 0w.Jx0,Oz>Tem}:dq&:Pۛ*> x5\?nŲQ YDFNK RLzGU//5ƬCa覫^U>Zธ3}/>Xr-n=hPB*hƀ wѲmY3eVw^i9n1) aYK|}웶 ҚzkPjmZ~3qiUӑlԠRj=t10΍kPۗF]&vA/ݞ}aԧWujcQϰ,ߦZΆm6u$dNf1ωnBZW!<"2#U-K]C{,Y?vv$%%=Ћ%rv^?Ɯ)Lj_kTg?IH^3;~h~۾#jw),ʞsh3~rdX=f$z&&[*Ξ0rviVd5hZHmX>0׮|ve[w2y_4OԔ<ޢbb=zQOv-kOPyAh ]޳.6a-h-_ZŇ 8x=K㲩/_2Q'j/6}:<&|Bz7Gvͣy&o^Q>ϮXU.6著22/Uť귃2fë]Mcq|n `(7sFKj;*=Nf/G3 &ws9Vm0٢m>I^3,',7myٽ;$r`F\X6 Odu;62u>"v 59 syy{@?taVuMKt{D.ªt7+!laEot_i?y 'ֱXR֞9VakbrCKNňvmM)}2Ԓ7Ȏ4^@qD9koXk LCx:xCۗ0o |У\4k^LG>|&Q4f)(Hforv֔ k[wyZ6Gc3wf>l˙0]bAluE;pt2~X\~<_.elT+':CVMg<ʗf0mSui7~1e^Oz޹!v˕8<ز(fۦgXN Xwry|ZQ:g[e9eږv+ī*<d;epJu!#;P*b ì ?9vޝLY[~xfsU< ril;*%N˦} 6GV-Tv5Ŏ|s[& S&6]3&.o̭ͩv1ڋN |^-KhfmpTrЖ32 WIϺxGἶ)mAv-acxsb_j=5T }Sn&m>%%(V$&o'u+KSIJoƿw0 IDAT3"W7ҩ=Qud-}U}ܚxytc6nƍ]X:sʊUY(g %84C?um$4ĥ T'WS{rUAUG\L7su%Oz 87 Jq)B5U#Qm,͚4m3 D{E4-Ӝܹ]tSGfiфU9Ws҆@=skGwz![hHXܞcwB#u}Τ%6~AuA\;CDFXNr}){j ]ʄ?2KzӱWtȦ)fj-njiR&+|i"SO-i/aa(fA ɾ-gZxyɓiTqvsI JJG#_fN޹*Dߌ⽴/w=NH8JcٵiSD8Qvycf 7wǽFXud-dnd!^"Ǐga99WIHNOuMF߾}Xq . 'TGKG #8\HRp!VN8[|va\1;T)&ӼipEcgBTpsMCg@)~ߐ@o`nRW U b]*d̗e_GYPJ& Achfh |Jv+¹}7 J;w-qsKnz,q8znG;jᆫ]>2cJf .eio&mE`GfwI'I KxZasڿ%gG!wB,}YNttcJ {T 6R^Q+՜!%+2s%7mn`H匑|as`+g-rޖEjP!T}77{mM Z]iJ.5[2vfx%-êق>]#z5H;UrT'gc/r7^L b[b> XҬ J";&2 N.a!j/ebcSCmt K~7EEls\7,kY,YHn+ u5Mcʔ)=szaٲE1g/>Y w@9;1tƈ0b *&BnԵ*88;_L]QIc,{<y:~:1x~`?Vh~eIշ%>:$aӼ٬})7T).e{ܽxqz);z$CeȤSH `BhZAoYY7se 9n-+~`ɏUR{8˒0[!)nP!͋ᇙ&br1(.&gorQXn̍$awʿb0z|>?qIҘQK8:1W.uըkHL}bߠL!{TLȾ.iᄳe .Enq*2+Kl3#wR/9})xՋq' ,Cz3¶V-+"$AՎ$h2rn?uZPqX6^wv4hAEK%-5P fnX L׹DmP.==G^Y'+Z[x,W1WqK #p6~z#eٟG o7a&0E_`9߫qp.% cx1Y'\/&`nvfw9INe47nÆ H"߻y_k=l2Me҇ c̾ U>Ƹ.OVuj@p=ڌ>a—>)_rcz|˰"W4:D0*};'I`?[SfY!D$}v&R܁z?~9_6fjpbtI:ѕA53M3fq17`+Sp?!ߧ&`&DAϧ8M.>[ޚU@^&,*өф#ߤ7oV z:>[&KuɈޗk1fT2ܒ˵vtm5ע^-Q[;1!`D LܬpbE2_RXEDdE/L9i+g^]x = C#H)Ha?2"_vm9Y)>:{cn/)arߚ5w/)&C-&6/3$L/^1&Noç_ktiE:{JJ5[׮xzz2g\U|{vmlIKu;N?7.=ɩ5jG&O<$$&BJJKⵥM7M7¼< s8ߛX,.B?i]v+odBBUS>2Dqqq >1chc>!/9ōWy(N.L/omQQX6s{~2u!kO7**3vX1Ld؅ё{Uם۰yW!CB<toZ!Vÿdئܾ'B!ċ_dwwwzEXX߶Z!Bdwww[t &6q')9.B!x^l!yر48033{-vֆG(B1>6$&>{'&&ݿ?˕+ {{{,,,0 _PxP!ŭBZkWɟ?#up-Z j扉\|܇B(J\\֭{h~E=%r#/]&66'wB!x(ڐ?~9ȉ'HLH결ɑ=ɩo377'vGlh4jࡠl0Pe,K~XB!9::( h=9㡞dUU133[[[4$nܼIƍILL.Y!BdJQq|I;2 H:aee-a2[hѢZ"m,B!^I~(afff躞UUU s]ױ%( !BWIWH*B!+'GK 昙.!B!ī$I@,B!^rqc!B!y;I'V .G!/)gKFy9W|8jfB!5lmݭ_25V~yU B!Wl5V.?'!5ck'"Bgƌbd!B!ґ,B!D:B!HGBB!HHB!" B!B#!_Idp?} .兦/$\2?=ﺄB!2BƯ|i=eTd7OrwUWuZ5-夊;mVyB!BS Jt8)W8ľv8\˾8G/Je dh,ƿOΔhO'>J(g8 ŠGqlhfl8K`D,Ii(^ %H[ͶʗQז?W0qEikW xgܿ AMg|t[9 y-X;EN.b`L0b3RqK^H8/ b,X#Ҭڍ%t= CL6k-2U(ĕbn;v\r-Й$S=-;NA#nQIGN bi ʸE\B|i] Zs03ײxwGn(@N-Jsbx>em{ !x$%&p49K[X;[f^j%OF ض}SDM~Kضk31gV:vcv.i,9cm2Mz2緍/=15a gk駔2<~=$s|˅zcn, P ؽ!Kq#8;_.ƘP=igm'*nZ?{o9lucdvvŹoˀ62f0^{xW;;K2jBG,v g1wdznw]˷˖"QrD@SBF/_K9vmI.NLǑ v ml` *a;!_0Aq:/08?-2<S9'' ύOuܫՠ2qqBxQ:yU9 g]3g `pjC<Dӏ`km\AQl)U-*Rث`QN+" \x{')$ԔgtIϩQk+;O1aL4 `(BQ Zڍ6W T 8:j8`^2q/q?(KB,%[z|Jx 0WuбuG8Z(%Lu<- `ٜZsQ7p!WsWˇ*vo <kq8JpufU\В xǡxrg?0I4$Kr@B'P[r=0M:ģx@ybH^Ⱥ1U@q@>|||o ;*&Z4k2k09Ю.c|(R398̎_v߆g]|:,t馴3,O7,n{}Ü]ǚ1=sD`\rŅ7Pr-zL]y&=jBI̔lzK3.+"h \ !`C8R`]W\'fWړ\Ds/669:af+l&H?`]ȏ} ;IYƒ!"!U-mzЃ!Gd+^5Ods%͖QT)U<}!JxyFDx$(d-[vs%b=N /^&uךMg936MhtqO 1G-Q w 68ˣbSꞋ &;T?  1OCگSC7β{"߻Ήk АR:zB#ɇuAL3ycPu,7|{DM#F HՊXkDG8.ǁh:+8AkG0&]')hJQ/xZ;ÿ*W!H0L7Ft]T(_>ôƽ9<]6 ?ׯS N[gbЅBt?%[,p LexsAvz=ˣ[=b7 {˄BAڟ ?j/|rV$$ |V8Wޠ0ACB!$%*i6H 9*HAYBK豂pLyſ.B!DFkjN{i(((EU ~LVA8t]]CKߕ5ɍ=BUB!xq«;F6pibĽwjԴܥeg{8e`) ({(s>r~5(wZӆq5ޕ?Z,! YSaw4B!%{l4в<(d%-Awii~IH~F' g YٛBb+ R wAG8-B<; ҳܓ3HLհ7xm}*?AYB3*?9~Hq_SU*}`-˰pw.g,aX!x~e Ɗ^5r?2FAa#!M0"{~VBqvh8㾦it,h4l w, !Ͽ,-ǙC¥wp0Wi\Œetw5ʩЖq??8KH~eoј֩Vr2U:| !⹢( V%IXYY( b4Qմ2g B(NBS.n=54kFrr211qs/uG !B͛DFẸ IDAT`eePuÐ >=IjQWRν4NNYB!(h=wreI2v"wy"3ZF͛҂,BeemMbb"l#ahs/=~HH~6| !ٗYC9 59|B!-#o5PKH~F5.]˳e!B%k@>Bni IH~5 f4q:!B%eeYY"[<r;wJKB!#gh4rIbcb@<88SbZ gPN5M%U`ϧ[?o*!f]BQ22Gpodvۂ)0]Ϙ~hX//zyw%0{<'zPPE![Ox65LNtk;]3+-Z1AmG^AڞzĈէI8jB#Ci[1u9t NdOB0oD" !{y^+fw] 4IhaNĶol&YGIoo-@Ӕ.HX x_Y\Y=-<9ick0h|-2ǭnNz3qu{6&QS:nI5zF7xIv\6p;C_ƍnsٶoG\kJ{'%_G6M{ϝN ?b"{ޛuWI!ċǘm4 LD{Nr\+s|"TnDpfOע@_bY;Q|Bc޾/^-;«}+Ff?^1?RX@E@usbĒc 1EM{Ey:v":t'5 -I-ҏ˻cW٨`N_Yt/&P,./FդXc{M`yP!nϧ1KπYh{.B<2rڃ=KdtgDN_Q4 uTqv$ZR5c])jyJSk1j9K(4dfzP~GD|(޼Vmsoȕ[Iuͥ>} WbAcdΘѺ%I VW2TG aqPCèi2{Jj83'CI=ȯBWN3f[ឡ?~Z_Nۘ[)v~N.8&D V2\ʼn{XPۯ:˹(_.E, [B`oEC/LxkcX*)QwI;㱉.QR*`Hz1~\i @QȾ9MĀ>잌()B!^@u-? -ٻZ?j q51K0=}k;~/^~ܷPl44OkBtwѯhw_HsmG r${fYm9g"Ҍzy?2^XZXTB!KJN&Я( 2﫪JX^PT2;9:0([3W&uf̘Θѣ0qbfxMXX4MЯU=><$`DPJZ8{Vޫ]RLпz+=4NcS`ݧ<$? 1]lEAQr"]*Bo!mriss #GxԨV`-\<)s*4@F^BO{)u+ulל jٟ)W0j;M&rˎ4mގ1;nX¨-W!!mxzT|ա? "2O3(acCZ|8Ses飪toB؆t=]64?khР1ͺwӇ'ӮcLZNP!Ϯ'?k_#[VxQ`!Y-텧?DM5wJ5i`e>@M_ ߪfx6|ٶ~a~=ok/Y3l7f\"c2arsزs+K.֏&Jz5dp=۶ϤSqH!|nJ#vmfF8&`S(;j4~<>iQ5UݱwKs+ Q?3eƫ37kQd_8œw>߆Sy =5tͦY4(FƫFPqA-W̳|(d!B>*{xwឮ>M=~gaWKH?ws @䯇MM˴]GeGS({Us`M#n:%1Wt8z'0;3.R(=z.f C*kXS%fhݡ 6*Ƿ5.`Չ/j(HF\B ,mY曧Ox5}b% [Y#4J5h s=4^-W;F7ѰZ{erze!BlڴM6үo(8fTAw8~4C6>t**ǞHR~:*sl_0Ur]SѥrP5mc&UJr̖U2/ST&6fvs֡S*,n ǡWUϣ/g3 U3oE/[,ޯH0#WFd3"c>1>M>*Ihkm B!xgrÇ=z Ǐ{,=LĪ7U/ob8Yo%~(*N02sj0=en+xU0فe;}G$xUcg]I|?E4BYWRs؞mY8}x=P[''#%ҏFlrl6Mp,Bσ61hÇ`ȑR$+u. U|ٻ"uvW#c^ u`[wsF!?Ei Nu[}v 360"q.&PHn]ͣ .f@Y}_R{L\c; jRp lKL1ǜ:Ad0a$ބB! ӈ# ݵ]ix'`VtsU~g6],`Cmot\iME4lDڌfo8~-jsaOumʘ)L>m?K?y ťaR\((B񤸻y󦻞qܹ6oބ p2Q0~5\wu0ьF9L&b0\|E&B!DʘLĭ+&&&3H`rg2`Aw✸3{\艹LD!Bߏu.{ O(\[B!5HH~=G'B!Bq֐,B!D6ţ7 Y337}CR!7pO<2É%|Tt-%G *:?wQmG oG8!B!.pXuj eYC]J#BL355%%%+%%SS$$ zH{| hBQK#!-ϧk,CRӏF?c[!VDnHɡ$YD<=LiًobBԬݓ8f=Ov Z7'0d9!h;k ?Y>; |В3¸ޭhѰ>~1kdLm *t*}R7>gC=}rpG~. $fN[!֦O&5?N:MnW[ HBkLaŗ~c cpְ])n,}Rw_TJ4<geފ7w'mϨYޙ| [XaAj&DzDU}9oSMs7/)cØhA|\b ߴwE5szwi0eFnv/M>y F}3+/cDE$z.r?uXChlSD7pQpelH.zj)T}<}uaRE#ٵ|>7Vx<2Mި$ P̧pnkkAګ4n;1fGGz5xП[k\sN4ske3BCaof43^GLD鰱kJB C+E-:b≉79:tTթ`4`Ӣjӝ=yw4 c }J絕;w>h,ƠWuG[ f$>&B\PDp߹t ^\CZb"B8-uN-Oӌ{_@ p9Q##m._D 7+Tg[:kڿI贷yD*.C|DQcl 1H{ĕ+(viQ,֔jj 7`hCVqtrļV~_o-B!sE:ZteChS~+%Ǧ+oEH/_I6E芩>T@6F@3  qy5?8zS]pRf@6i 4uq@5 ;#S7"oq1.$PB!ċFZ_D2$%]sɬqpQ Nɶǰ53 Kx3nTЁR'5|U FԴF<~@ɧΟ3+΅C:qxjwZ.ڦC-uj.Lɨ mM4éB=Zz`rkɧ_'1ePL} |YRVMB!D1r6r,8ox{yBI/6-f4ьF zvt*^XZX,Ɵ _2 ==kb ;BJJN&ЯEgbNCa~_UUTEAQUTU}*$kơ_Sf{}6yt !?Ibn*TTBq?b軑k(ũf[:B!d Qm3y8zcLgg*U\' B!],UǓ:~ h=Z/  zRVmjdyk/L*H:7^BȅLl1 .!BsѴi3jשsQQsƏg̜K<ȚPd]((yN|+E+x$] S?,ZyfWw+R"7 Ͱا>B!%gg'zzeC #|¹r=Հi+g,6aЗۗr,y w"_˦6m5*o}*Q'3C=瘴TnD1&M\f=ڀ DN2voSDZ.Y$u_͞?HQ(۝.;QF]mGu6Zi;vsF~Őt[S~+e=gFַ0lw147qRa}_~AHHJd=ڎf3Y0g-밯ԔuXv)_j ,a32!j;#9OYu~IօB!^DL6 yB@[ 6r]ڢ:2kןN㫂CPGZB׀t|][TXcكv*E9ڶMݜL߁Z*`k]_h$ۮC5E2(9%J <? ˷-}}ztJNvpfbŀShݨ 5Af ^v<~ƛČg2# e=|x&R_2Kֱ\}U?r?ű"ݿd|Db+i1+Jo3lf^N,i?)vy5'±bfoוN߮ct/lc쀢D|2}FGgQxi^~3ncw-o%Y!xæMٴi#)r %9#?oxoKSItXǑ>Q @h:PYƵh{!n dX,FS0hƛ_3P˝8GҕǼ]- 1XGO`FV0/!Evq&!|7Lفr41&U\'3=I>ۦXWW֤ZsNġrS IDAT@u%ChX3(ٌf! IM[`8QSEY /$i)_ \;B.u˵cJbix9z%a{Eċ%vCEr5fh0'bHVTpKKj&vΏln5[z3rܵ3񵙴rS!K gY\.|| ĿK6I%G;(g4ڍAsٰfJ Oj̚K!iz+>{}'3|F76;,bov-0n&f-6܉qw\mF"0?L2B!ш#iҤ)5j(j 0$o^j9w%P)Ӵ~-pDŽ s47۪=ne3^r3/^ M&65 M?`҅L݈4{FF}6\`a/**NEн;^Ϳ8S&Zaҍ𯸄mR?8puQ.#$kܸDU)P2Dme[h;z7(vq=ã'Vun$S*؛rpT=QUl>Ԑ^.`瞋+(jGM/rkg#9Zrŋ`PŬ٧L!Bwww6otsΝ;͛pwwA߇#] BF@܏9n>MK< ݻȶ4C ,߁X=0:y5ebh+\s_P)k!s|#mՏNQH9O:~@2E(ݝ5^ɳ SQ9d]A4(ˤj=JQOs !qߏdw/l=Ђwhx3GNphܾ-;)_ !1+`~fҢ3OB!SJB Щ Ԍxg †K2t]F4 l?؄ncp2@#Ci[1HeJWj.C:4g=F"7C\65u ߜ|9 A~ j?nO#:QF>%v٣sh]JP@կ `O`5̯DsOHN|ַ>x-I׎GwWRB-Chg@Y΢Q!]%qbxz4 ?`Դ/˔47-h ;ry*ȅBkH~ƩMűL =&-aی ݡQW+>lC.|uK3qu{6&QS:i4בMj^)/L w-颴Нk=%Z㓎pl6_wb Ƿs~}ũSXenqh0fF0g~7Πե,;C۪KT@|3Ś5r#p`Y(?XFX^֍,þTھTJ aoLƵmR^?IGYjzƍS4*Mgl@z&#rc2Z0k8Xg-Y!.kHR(|fe= (o qrL>T`݆Ţ<;xܩXc{M`.t퍧 (E0+4An(ar¯Z ,HƦ_4% }6Mm'вY{Lc徭1e, Kjnqu1z)LS5SӻWS(W:%B!ģV*&&&TUKn fBr/l2 Ȫn?ޮvڵCs-|-s :1Ai&G5jcR`j{v8{GGdt1YΫA4Kw[)YC7Z hFsי7Z3Zɿ7/*Beȑȑv"hI¢Ptso6XL ]ωK+y#u3d >jsY;J]"1rv洲ymhqlx=+&!"]Rr2~lIldiI;9rFڄX.v鯺ed?Km!& ytc1"B =Yqխj{q3[^lG=% !*>B<R.n/xm4yxP<6=?g)Fy["ne)B0$$眂s,71njO~WJfYB!tB!" B!Bd#!Y!Bl$$ !Bd!B!,B!D6B!FBB!HH~=- !%B xⴴZ^A}ᬁKym4έ-ͣ{%^KD 1pێGҼ>FaB! Ť O[0LOK|Jߕb@oƷq2v2&`kL{{LҤRN{6ry4fG7gxCj!ʗa>p}>V==9 ?0f/f/d}Ib5,ע;\ ]az?,0cZb2!ZQ2 (_MO \.Vt(ffjW9Q%ffO: l֟ȭEȥ )R ʙ=cZܓ> 1\8{͑[ܼ {9~E$6]{b?+Mwߴ +J>1OփLҳ|:{ec-;93B3{HɎͩl[o)E; Ʈd2Fσ xܷ6cJ'֌G@i ^HnLi*SVeHFx{b3дxvޟ ;b756_n90-sFиQ Ƈ&fy?j-J 敖pkѣi޾~oǠ|r C.K҈C7khX_?u5gR2ˮ-ƳHO?mQ 4 O!}>gWt>Cr5g֐D~56.gg3M}|:ǓW0r9t*:5#?-? =snO#:QF>%vǛyMhkZ|Տ:P,qR.p~>]ާ]xv=D}.-wH/>q3ۣ1^~}kgҫIZW$ڞ5GIr>R*h붋␘, ϸ oOش `y`'糇?TJ4ż(R5mʲ{3h$:čnHM ʸ?kɺ=oE uho#զlЛ[{0hULG,tfv+fw] Bߪ\K|&HYLh] 6_mFۭxq5koRM>ϴ-ǞSڠ2F87[}뼔̕vp`/ϾKF3^X .Cac sr0_ˆCq{gCYay~v }~~EuVGM,35~2ϏXQǀqf>s±L =&-aی šØœ 8Wx~IG7~Kaq_c/7^霿0^\Ϫmv^"v̡Ս:94-*E(Qn&ln`?pTN0OD6y}1Ywؽ'aL}FꆟG&BkIN $'E~[|0)yv'\}h^ד3=Nj'13o ysqEJ;Iƫ6$e%SUefkhҲ T^͜Ǧ뿘@Iee5H9z4No]Er_y㦻i6+)-3hTuU8u'hDGGC q^mO"}Ľ[v`nQRnblcDٱ3ay e=Oy׵mv(7LG52uܞLL\11>Louqp:*P(ic9A[4v6\oFzw{QDcYڛl=QDcծr/TbǞ((~?5@+N?]ǩ5N\B4 h#l? ٲ I+{ѩP~+b4:]1_IDAT͕{gi@R{3?/n]$פlTрD'tn]=Wl[q\= -ތϾ F%߼QS۹q&Jaȴ<29*f|*r2Wྰ~|ۋ5uy3 jcѳssӮWx_i=0il "8a^E TF>[-:0Ĉ^<`:%_Gt^AV_}\ fr k_R.oa㿛5 ",B {Pľ3g͒f;v(x[Rf41ibit:1 49v8 訨fu)p~[RZ &՟w l\ձmxf!g%,'g'}qGCA.#%'}=̤_d-~$ 5l]:wF44]'""MuMB pz-CEH8 wF?S!EHN#U27tO.gU3~Go%'=8XрS{xgo`˙4Z8KuʓܠBhce-! ߗiHE)"gڂG7e1YHg4mkL>>M|~w/[LB!hָ gDr/[k^BP(?4<qǭ 6na&ZIENDB`kraft-1.1/manual/images/en/taxes.png000066400000000000000000001763311450127457600174660ustar00rootroot00000000000000PNG  IHDR2c pHYs+ IDATx^w|{HT&^lXbRRDDTAA+xEXE@B@ dݹdf[zyyfvwƻٙl"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""DSx(?j1$"""" x!LjJ26na1 """""ʉt^"""""PbdV?-)NJ[WP(' -uš̯א_CDDDDDTW_'j;ODDDDDTuuEy̫W%"""""* Ϋ溢Lsͭ+gn=O* \n=ڏ<)lχ+lMa~?zO(̍VN[NFN#'r|d[o1r}(]NWNuZo&CDDDDDESn5zod96O-'''۪ݗuo9_CDDDDDɯЗ:od_96W,'#'ۇ<Q~Ԁ$.-v?ߟmd7˙9x&rfq}l6 8۟mms+/RKDDDDD%/ /6?MTZ/mK(f]:"""""*mչ˩jbqO|+0(m̈QQLp<版ͣQ(fĨ`wm|ϑn|}<_mԘ:c*F1<ngWc܈QSq_o٘XQ<͍5=:"""""*m z_FOs8N^%5_'ej׹SތQQ(Rk|ԜsOgՀy8 jsSdF958Qs8&9]N|{mu~FΗR dw7Ws2:L:zm(Z\0k*wuRKOeՙ5FyXfVc66b7 d["""""]N9OۚYk6՘ef5FF1#$/-om]#7h; RYJ6P{ ra3,/FFۚ:e3jtձLčj\ku,Zun$jƬqU㼼vmUFhn&|M7^gְuXפZiFq`爈pF1y5:y֫5f1NxSM)v5j Nͩs`7 Fuh !""""ǟOƬ9U(&յs:Sfr+yєyOojuFMZdϩ21o֞bX[q_>(w5}$n4v3[ fn:unƛ:ojM7S*uh[9OQ!rFku,ZulKDDDDDy'' Yyu-"b29nTcW2u[5f47[5^˛ZXԵK2Yp#""""]sg3ͨ7zsQh_4Wbյnil&jTUymSsEyu{VPkԵhhySxj2 Ul5V䌶1EyIs(Թl,iFpoOku,3o"""""Οfm6ޛ+ӢFյh-ƌ檜潖M FͦQLkoƂ({Ӑp9'bbm71uDDDDD|mzu5sHc5#{.'ތ嵠>;j| ٛVunV۫ Sq5fVcX]cAy<剈`xjԼ9`lk5rj96F܍`7qwIn5_k^m>ɋEc iVaw_y 0ou?f13rDDDDDTp5srqCir\'QL=\1<ׂ7˛iޣj<]ެ4j4幼V\q 5Prh-3yQѦ6xfs5dωYkAZ.jZcׂQlr<=o3Nm8V^D zڬ^mFZ=]q9'jc.չoj9/DDDDDdΗ]7͢Zm"֩_-1"&jӤCG'kYyyl?fqQcu{M`PͱP˷m&s {.TfyuirF׼qA΋ٕj٢-iH9h{99ԱYky}JyUsj\m՘ʹQ5"nY 7S)ͨ2"urlWE\`WEbxӕ XF/F15r\,Q Xmvek PVyQ#?qrv2u[)ǍRKDDDDD|ijզWeWkuis Y6Vɋ|Z8HwE㪵j\ej\ݧ;FyO J7͡)U]ASrV,2e*uctDTٮf'"""""";.^c㟫$&^a8{0k5\9V:XqwT'jO bcu-l,/"MCqs;_,[/v!tHf+VGMuNO܈s D\lf;Vr+͝ÁT\MMBjj `d-ҥ 00H-ǎhMڠI(ǁGy0GKk,7,ȉL}9.%z|Z Q\hw9y,> ccNĬ,QgZeKMEe@%Hfbѡ]j7Th:3Q~Z & )TRUTƭ;ᣘ"=/۔oы+FM8\c`T/FF1 kc,jd6Θ ;I-gN!Th ܮ[EFᾈ[1gP:4TMeӤa}L~u ~o>ereXȉH4ҢS"Ґ=nszrvG>8\1^Pk8Ykؾ<*vjv Gw7ϲ}_N?O@ڹ:wUT=wk7nok7"--M٢xZ P:4c^xx gϙ^ZTM抉~M "n d֩5~yϦZP;V4bˍ-1lzXܥ;#KbC>BxځP}o;3j]XbU+WOEq68t ǟbA}s| Hs1Vc\^kku".kSii6:[:CZ ,,#G)ʡzf9ҷϝx޻2{WFMDDiwckL|e ͝/>i_E뚪e~y޻pq<69kn#lߩOgf fMȈ,qoLxnlR-#"w7ny8rR^Eի8r>3i"~ռY4oD {E&hҨAܖ S#z>)z>L26J~F 55{.L]y.ձZ#3RmԸ:LWEyv2?=WǤp8{\T:ª#"*4Msе4 pq2zw2>l4j`P/n9~&""/Ysyێ)}dd fM#jc%Hz+DŽ_*GaƜyjT>GݏQ_Ǡ!66_~??ʗ+O=_6cݻ'k}|^OF ڸQB< v<3j<5!>*+!6.-Z{g#Yhռ=M/u g}waxb< 4m8sf̙ظleA@@Z^mǂ/Q9fjE]а~̞˂0gsL͚`axk~=ТYzI>y`anLW͛eidkeM54{-MhRNo5&cu_y*j|Dk4Z.rv6ԀٽL.@AW;v8t&_È?s!!!R#pA\ 9ܛ7|9Ƽ,BKRSXr,~&""/]׬1liiشm0j0:}O<_`!xx烏CGP^<;z<`/1ix7CQL8Ǝs?æQN->n4޽7ω?3?t(_,n4' L^sEذen%ƾ,085jX# ws礼\k@za,Rm6ӱ~V|4o!1'q=1s|[RE ǬOg었^ ^x $)ӑtZ`ڇ1zSl h}8ɒםre#z;Cׁ_|ް3 W0Y\Ή`j^57|y j#Ȍ:w7h]ȉ%.:p舍Z p迈lQjHR%aߟ:+_u]|]2}&^yy: PDp\3}OP6jI|- 6[>[̚6 Jn?ZmlnlO=.oΜ= 9v6oC:i[؏p| ms17o3hy]Sݸ%sG1lBCKв>8t3~=vދo6}:'"*he1xms۷,z3c6;)3#mѬ F~7tЌ:1a 2pQc6\}d/r6;r\>@FqZ'blOjy Uk|.EA o_wuk}/IKO3K]Ɔ($&&\(e_dx"4MCˋGzZ֬2KYrqob&붚 12 8r8ƽ>9c31`wШA=<`Fp/3|O X[]ѩC[d}_&탈0(V>O{aꌏ0Lj–I>p{x}4ҼzMT_J&h//WÆsv(R!!S&J8pޏ6fK;?/Υpڹ j ׷R":kϜE5]hڨ!Ԫ7zvfjsGX,X,ԩUAAYp֫;zvwmepIl -ۺ}PF5X,s…KA-Wo-K}xexeۈ޳/[p?tG7Z6l|wa,yC- eۯWIcѓ7>M]DN^ r?y:m;v 6o{oĤ+s6n|<ǿ|9N|C{O ݁iڵT.sMLLĄ_z~54wEbn#u`zXnhEs?ĺ[0gY눈=9:עѴd╱#,X2v$xw5NWM<֥cUqۺ\!w<ՙfv70rs9',˕iex}[v1]Vd@\+JiЬΧ;tKK߳ZV{ cNDD$Y?'uMoWS%ƙ3g1xeH+W1q{8s欚ɽhnud^VS T^6r[)3 Fyq//"&X5 R-~ S,V+JtXxF"j:ku4!p~!$<]3NQt[P"u5o{nDD{|umb0bP4kHMg!̘jg_~9T 5\c{6- IDAT jAlg,oϱlUUS\W2n7ybiP[ň8*qlCgλ}Qq7a{j(_>sc^V͛cI#+WO==p6m.חyAYV鮱ܗ}kr i,jFc\~6FATq`c9&mɶ:>"Azz3H8f*˹$"""""Hu{޽GMC2i ,0o|:9fVo\E^7x"שc}_^i [  """""*6DO%nr/&j̆L͈Tl ewydyED'Me1ˋQTq僩Es c@DDDDDT5"imN% TNJźcTcZ`E='&rK%Zf5Q(R uFQ#Vd=DDDDDD;SY˨O3Z{y;7#?\_T2~:"Nk ˒s]!""""""VTRw9\!߲aZB2}۷+4JDy-qgȬSo; """"""w՘ϩjf?_eSE`Oku,ŁWFMfcщ1ieeDDDDDD ~I}e"jwu!c""""""ڏkԹ7牼naef'('Z""""""D`,թԜVM~5 u77suƌ """"""WT{2VPcjfTj/`y-/c(7h[zŌz8L݇L盂letp<h$ON1 """""*䋕f_eԣ:QP)l zԓܭ؛|Vf ެ՘ TcF/^so[]7'ȭk5jx js0ƒ `f=ڋk]Blk67n9(F5jL NWmM -ѣ; *bbbPbE5iI9_wVSDDDDTY8\cR2cXsʛT#rbG{t6T"nk\{!"""AKdFMz 1&/|1άǒ"f4qux3>\MuAPO|2s0j6EZ^6 ::WOJP""""""򝻾L 2*o|R_@wȚtrQбt*vŦZ mՃ`,'F܇=Qퟜ6uSjՓ 1w'JͩygT?g˘5C2bDDDDDԾۜ g8Ub%/oсrN=nNTb+ԲhjOe4WyO5*w|WؚjroNQds!$ĈXjqW.W o//79=ɍ .`WtZX0t^ S1 Ԩw0@5ADDDDOs {̨w2Fj6G7vEGc/a JuN;8f9WKqAѪeK5lHY+DDDDDEYe֏ ̯(mSF'R0 ZD=԰X],BKЮa'1/mjwc~?E:o&"""*) p+ `zY).«AD fδ(T[<5/#9- R%/!9FdU .]Lmo- *#(KG*qM+0d{H3T$]NU{ B˔1xDDDDņ>,N&1ꝧ 9hwMOylɓXD:: ڠ}0e?Hhhg3 0<0l:-Mŧ7v'|{0.8C52{D^Ɩ">U<`DTmڣmнM FhSy՘P@ʹPx[G5$ ~8}-{HA̡X }VTƧơdt=Ma@̷ G 54j6/?yZO®/Ov".?{9Y3{?GNDŽ{!XSaΆ^;Rpj֟ڇ?~SKDDDDŇuZaNQEGUr*5eY0e;;vL-GCdZ4k!6u:lJvKư}Q'YD)Kq?lP:wǭs4X+^@vnÁ5s0a8rU~ ?8Mf\$ԍB-Ϟ]fo-6QKOKmQTr`ƾ(%%%aO`jJzV|^ͫA u?Gn r܁OBURhxvp֜pU$_!a{t ` Bպ-ާb΀څ͗(f?[uJun C>{jЮh|6A<)) >~+%XPSaP48:׮e0g8COޅ^"K xz\_zo94>u;}=*p*ոX_;I? ԭ5CM}AǺeK͉~4𗑹S؛jYny__r#'ʕ+lK4)lV8x类fYt ^~t~zYb MO5v/LwgafވnG\lZ tz>߰Gl:tG2W~JͻQ%DQZ9[sEZtCn]вJ7ۿ۰ۊ-\4XJ#"",Ja8> L}N,=7i{l0 }{=b *]Q۝"{7Oв%o/W᢫Ԃϛ1[̿ ֽ ΥeD¢Ij+ЎMx2y^T= "h@6+X1|cV]{]?[~,-݆]ovMJb+CDckW$8߬Tù ?e(Ng|V)nP8u&}w vQnzĭ:ފ])"k8vQ/7>A'%(ğ&"""*A]Vj EV2v y 6ŚnUaھ R5B[ Oc\e;Xzҵ- 7uhsY#g̘f#Gpaφ8Dž@Tjf^""""OÊmOV\n|rI-)Dc=o\jRMSQgjU,1;W6,G+ar6-ǂ~TW`ޤ8}l-%za>?>tWvb%h7?ZPCSqx x~<ԻW %-89/H-[ Ǽ ps^vs+4]Q-H?ݿ|>%Ь^%*M5#VmSSTYk:Xx(t@Oއ/_z _*e(D$+ߨ]Nl۾CrX<\y;@d_p6]GJE;XA1bt/D Φ~_/ 52<1f5.i{W* $7yj+'N- :e-H9"ЖC1_]S`44 r~`gA *t޼MX<|Ԫ E}T+<6iO-Ʊ4?y>$z1]m2ܰNClrP 嫢NVh{Kw _3@_W`ȿOM@Hx9T;@{A8j"""Bg&Q٣ߧ xy\Z S^l@/5 6DF1v"لLñtp5=EjƘt-iOQq%DDDDDDD~bSMDDDDDD'6DDDDDDD~bSMDDDDDD'6DDDDDDD~bSMDDDDDD'6DDDDDDD~bSMDDDDDD'6DDDDDDD~bSMDDDDDD'6DDDDDDD~bSMDDDDDD5@yc? w!"""""bM5-:z7 Q ۿ+䓞=z}jЈU0Q+DDDDDDD~j+WRC9v5DDDDDDTS jDDDDDDD~j3C FG l)ϴl-B Ol#ɥ8Ps9+ gZ{:OO9bn\'"""RJ5 :4hРYZY!&Gbq7ހ2! Pxm8k㣰9қ=z5p 518 |`l`$+Ýps jHܳ O]C` i[}Yu6 !QSxq+'?eO"F?~+77zᧉ]Z1fHY5 fDLܻ-^}X:m|4RKWG:y)cKHm/?F1_9`+\F㩘e=w'?Ši< mlQvrm(wYY=>Y>/fb?X^huSgaKb |W~^~@n ħ{oWaJ1˪_0`+GÈ $m_X-v *L faŪxDE~u2~q m&F/^^ C7l?Ē'5L)踲eF}| V5^o ^]i8U|z ~eK#M}_Dԓs߰8cOyߖbK1X7jjl}Hqn&]Uk~‚U˵9W/ǗJC `$;-[߾{6`SRg\}t6J >6sR5ߏ/jyc0e_+d%,{O@[-DDDTܱ&B)VSڠX *t[nŔ1/b¯0|]fnނ݆d`AՖ7QT 4zP+>zJ_TCn ͊7mwɰTjwয়©d hƍfwKe^ ݎ+57X{DXЬOo4::8n~FY+ Gi!@pX`Adθ!Ne4͞YY߆Fx :7Μ:6=u`pa  ?TܝScF:M-@`y=h%uZXԺ:B-%%nnؘ8?A :6n-K5yZ?*""""I ;DDMC?ǂ;q&EE "Z$- W~n~R&t[N Q’ŔK^aY$%Zެ r<9o*ݎJ-">5DdOKWqn(g(pfStؓbP*d3l91c "˕EMVX:t^zgEGrt&+|"|, ܞ+ 2DnEG-^=1X5\9aTcq1._Łpz;RtpM^Jt,?f('>5®/Ojv~"|m4x[mX)4-*CT8"t%Ի {Ik]ޫ~+L]jŐ6_;҃K?T:ږBp4"ՁѤqc5L^#nSXv" VS" lٳwmƪyŭ(|wʮic?6#K-޹?ij/bxX,i\*[!P-o?e 5Q(HF5K(l?a65ۉl@ 1_kw3u#?݆K=q;M[-wb̊8a|;Ξܾg:n6H;w>wtMmۣqvh6]b'`lG݇N:}1h$#q38z!8=;݌6nC~ `?F<O,OgVVlnOÜa˴؝?:CDϞ73el<;C۞1#1~p70h{s _?XQǦ(TB#yLa"hgsf[4V¨%q{}n m۰ޱw'?}/dӟ1=\yd.Vo܈cjc;g2I|1X]e$]k?0em*ĕ٫زl4jmz W_CxmsVƚWwfmsHF^/cދV1[Km- n~ o\`ԅv5޲=hزy\:vbv>QU_EO($_]GڟxGuh@PNxػl%NgU!2PB!o _Gk]}W)S򄽷c@#m`v +U` ‰4VRP2بyX7LyFZʱQݩʃnZw&)it8 8x,9Knf{zӬXK> wͪ09gkԋw̎PA0Y n9(Ruavtp8tޝ-v3δf:ҀIkQZOZ7}qvUqx/L-CgcE^?1mΤcKAQr9Z3{WK4 gЦo( ("XWʺ5DZ,>ǦsDO?oG]mbE˘.'9zCO_'P=O54n`#~-K:F^]>>t̟j(c|:;O҅ a3Lo9R!^G/[U!^-|NAԩH`nǝĖLiՃE70k*W?%M5=etv^q4uvgԥJ0pwTtlF5^%"B3ps Ј<QfmȜZUE%M*b.T鿎JQe2q)jI*i`~3@TMhA>^~KaHa(B~ ĝ^쫵K:0\el)?Dm0,=QhDs`l;GfoTgXȸ]~燡Ax gRsJ6/Kee\2o|9r'z.bljc|dY{Q~/-_æ?;&/G,6W .ScH/-T%~O @̟YS"-k~gt !kDj!ī˺]@|3g>EӚt|ݬQ!W~PcœڗF{;lrQm_>gPp(ǻ $kZl E{&$pfNgԩC:uU3d:z&i*^50CGyu "Opf.a[\tTY2s 895,ňi)+[; W'H?͎=qTmߊbN*X{RmcU9H8Ŧڹ3١u%gt?IATՑML oJٰA!CTz-(+_o;t^U(D|h(Q`[!~p CL.Cq.H!9};`Gcլg*͢Ѽwx2KN;ǧBvX!SS!~5u? ̆Y1.a5+l]/Pø/R:\M4% WwS@{007T%;wT$,4s ZoiR>NGGh$=s] P4{qwqy=2@LH7gVĴE)N 5U;i<7T 'wr3+J\v9gt8F>.ŤuT[B Z 'zp"])e(pkw@w <&ptG03&~ӡ=B|֊hI_Y6E S/)X+JJޭ͋o"oE.00|Z BQ^OBtVn߇{1믫7T=ava#~x6=x2fFrV*qguNʘ T-)Ppuw4)VHLrpbE$ax@S͌kv^S|m 4%~Ȋ}+i th/@"AtgL^Qss5KMu0=L~K"*f* dMcెꂛcwC8#nvo?] ]4p3%ļ3q<`Ŋ>gmLS o}hXA_u4M+\fT^ۦ S>A{/?Sg:]6:Co՗KB0\;p+"}4w$-DUpuQMKlű]:0Dqj.P͙Z' 6eziE!$Dc>8'&5.| S2oH0r܈~ל9xQ6MH97aX>jcSE w1}c/.7rrz W.r;g~r*Ne=j gF0},$uqTб9Hp. pU[rtI<o.N`=.pX<sU _$Z\8\!RSL +Yh\-73wA{DlE-NDN{h/T:-7DE];kH5K=1:[Q,KtޗBQ3܁w#n[JUynk Ε1Gvv}Վ4¨g@i!~\ؖh9T$SkӸGS~:iOP>:@϶s pGu|sqXXX,KfyV%[e5{`ㇴB﫥ziMMQ0:I$mT$m4ˍiȠl 0s]ͳ 9iͳU[:}{%cižo3gRH7zXK6yq$>)h&iIZK3^3Odd6/3h^*rO3:WMZV'p:rηן/Tcєqӡ8VN* h!% "VÛo'~!Y1{X-5=-@ 9Gf}|; Ysr媫By<_)7W@&z ,m:o,7I@3IMZRqXWy-4m^fѼTIdi-Z< r2RF7V}Ӗjy-2/Ngc '?G+GPdZ/6eh}[1UW46yx3ݲ BAr$2RPm e;w4t:N6ɂ*UgeHF~!nAmq*d`'kgZ93/Z|1*Nvd@m-DZ|4--s>!B"2+V< '''EX"ed0gWm$4~!+\s_wnob-B!2@j)a0$޺`Ҧ+{'B!/"ӌiWkzB!B"SWͫ~B!B7"2>ZH-x aI¡ %/Ч?/*`iEB!jI^kaO{mz]?P`O|?w˘>Uw}D\څsu6~e6f6vڕK9j?ْL}Vnk⮬߳d'_E=:{;!ZI> 9/_p_.Æӡm}\\ư8vMrFl>uXX~_UdMT.J:oQ$EyITM`uY.\UU9{yEEXB tIq'V,rPe;;}vx_ϐï3{( ^ROw1iXV8{^?y\gn */f vEr߳a~l.D^_y:_6t?Jk(wV3bVr AȻb$U^~q%kN@Ot7_\§R7O2RgA&ְKTPuo#e0=[-MEybrvv&''4+2ITW Qvph{:>϶]Iݧ`1U(G3u-*TL&1}=VkQ|%4?ϟ1a;&>Ϛį|y*6Ɍa^fnFJX#Rʑ|P*+TbZ|:15oF/TmZ_汧X:# jT_Eʋqh!Ĥ)|Z!O_]šP/{f֣Y %/w2ĿNw$ժ`WLJ^T6&yç@h[v ]nkUn@}.O.SqmGcYsՓ 壪yq)Xg-G ^ܼr={7q(KU͆bGh溍UNKizΙCfkb"bZ͐53p7z٢&^Bٗ،z!QQQi'''숊JlllӦ=֦gīAǏ 'w$TEڶTýu 3Jyl߳Y7h+o ;Xwu~6Ƌ '0}3z@){?~۱:-7;Т03M^}پ>4B}E_U:Vy6OYMVJ5ܵ[طg%|2nnbݪ2!8>AXRQ=|6xrie++vE&-V~fSܑJ& W/q=kA;˭_(.fy-{@w`%\\Χ7ߢ{udoB O_ nD``-O`+E{è۬W ~~Tہ 'Bd",g>u޽{ܸq#yvZyOFtT(g_O{mfJxP6ᬀ!&X{Rp{{{&&6 ։I-1Oėo%nݾl0m%[6.c ޞ*Mٸ~3 xl-wRzk!NӇ4]b'OTyxN2<#8TtJedH*pQ 㳳i0 q:J"HdsH lT荊;eZ<^f1oW'4HTI-%{NU7O Nl½NYl܇A).:5!7b&ˇee _R6AICPb,\6p|[jzMAU@ )jLަՒ(^5iYisן_ BLQ=q]J8&sKP K/n EqlNn/W{S!q<E*C78Tϑ8R*'yGq/,{$>[u z=r !xffxC~rT,tu#PX?c {Q1P ?.zݿp-ZC*Yxa:˲w% 4tiT nZ)smb7bG<^е X{58n^B٤ƴ܏^86E 'ILŻvs¸7ڸ*. @s;*2͎ݸz(zX.4our󚄯h\'=wW;nmDGCԜ4(z$bߘ.)wGIF|׍vDGG= ΕC˵ sN%bo']bǴi>;]Q6>ǝG hcWQ^u7!"ӤZdio#J:@́_yO\&g Py.e+P4Kةь3 %;5ۡ$;/QkI4vޡ)s9Eax'Lc`",MtMG;,O/RP4ƷWG0mUFJj]hYǃ%}מ]pp*Luȳ)eseZTOKj"O8”{=>{wgMCS[w; &к"zU"u *mf4ԖxjXN?O5=gTf1_u?G-xT-}c+?#t>'=m1a4k3 1vo%:|7c߲2Wِ|k&jB'~0ʈ7y]IoYB!^XV1t4m>{r^!j2I'NƴUd:o,7=#$=MXJ1t@ɒ%qqq ,, ۷/5UpaΝ;gV\sWpa<<bRi)`vD%6]?XNO@CM#|xe܁*Bf}{fe0$$Mz ,m:o,O2h&iIZK3-i>1ˌ2TLRm gkgϞ*67z 3yx3ݲ_'^9՞)s~vG:;CL2tٞ%&Ngc -!B"S4M`Hyiٮ׎E=| 3݉">>پ-Fi-/#A"ݕn9}oi3%u-!uL*gB]糩U6N^W@[uOJ֘oɺ(*x^j;& `˪xhїOX,_GVl-C޳"j/{N|=eNVNivEr߳a~l.D^G>2 a"ğ/?Jr=S_7!x ֺeɎw=~KDgZb6GFhlҌi*#;H!3j)i~U(Ҡ_>Λ0%[CWC к~~ъ~sЈ }t'jW{~5i=b5Ѭ!}3zѠekzZ Ǟb頎4Q ~z+/ơЫRPt-|-Vh4-8jwW۾{zTDYt~p .hGL~({ _]@&߱ud:.O醣v'p?(OWS}>ڋ.XíD=ʵ4k.(D`$ IDATuVtkK?װml>NѷՎ!d1PPu:t7?/=ɕaRsУC @чr(7ͻNʫ"zUUVDrtpc5 ҡUieBSVhOmÊIz($$Pn>a|%ҟˮGhDnXžY}gX u_W?nU|MJFv d^M[5Z>"d'-'l:OPtNW6o%nߖcfl] Kh)̀43&p}q&:q!x shR/W?,Z1\;%rc̛܊e]czY j+Cą Fh4jS:Vvz= s:7!'A:%׸wx&1'@B!DWDJҔk\#mbfOGMhXV.VO;d.'|O]:Alָ~.b8. 4=bGhTȤIJf.+*.Q~ci%{l9oP n6_+VYv&kz/<،Oz._UNg% +Ƶ|P@Z 1Vٛ\Pp%:FM=)CL41I-)7XαcDAfA.pk 6xr&ǘByox^<~Fw]ͳkK# &'JsZ]ɞBCǙ:xe+9hPp̖,ᡄi^x$7_*XT  Q܏ГwJꉷgJpk/ g.aPTgu&4ց©&BN؜/jUO=R)1ܺI/43-&Em'mR_*ƺT]㯲jHO9fv߲8*b}1 Mb=-vdWQu$FLL g!y'kD\W6ᄎIZ1d.kU$g_ͯ[~21!Gj̎=ʃ̳SCZ7Ojj'OP՗&A#'Qo=[ǤRoiLߦzO>qjWR$RC=_襝Wǹ*\nuhNUxl:^RC3[Ԏ>/I6 aOhڷJ*^T-Q3zukݽ>.[RԪUmr&sVWSS';KX?MxJ)Џ3V%zfz;,ze^Np^iESfDײ+ x7gҲl{ͥKwB58USwu, z (Yj7q: ΁pK T$B5N"T$B5;J1jz;qQsףFdm꯲Pg`,ɺs$mP 0blP|@֬!ͦsW>G;]΄OC qmQ Dz|yxT/ipzQ1h~\F.yOFj5-;wEGhڐ Pf]ԍ:Z6IoDM:ܪ/^c(TW5 V@ps [Ո;yO{먖Vח:rS15Ggo̤glц#Ezm83%ѹc2ݔ{*9acIJ͏u\H'j&RMks5KZg o{>ՐIeܺJ:jcHZ-/fmUW5cʦS;ޯ1K+bj}9^_Cho3sTTqYz~|X-^E[5?FݩL*sٿO}4CU VY@&c*jG#=Ɛd(~7f.NٯTSFi&j}Bkұ%z(s=V0W:ӄ> =Z+0 @ӧg8Q[ Qpzi^Fi* (D{jз3f mA$PC۪ϛ}K>#VV}Т2.РN+|PGM5' Wh\XO?KbbP_쎝W:>q>ճ]Z(?Pz]$J'V߮h]d=6@wT:|| k2óB_}>ߠذf4Ϛ>FFzꃵ6;wY%{fk- ][ncȥ\R%PA~Ia*Qf@f]2$mOkRk Ղ a@3ix?kC "nc|jh|mhbQّv9=ʨ^rںyFTޢqmRosjKv+Ed:|Ըs{*brZA5PZ0RIjJ7wEnQ~jgIvj~oßQgtuWkA~r7 s5.7+/L*SJ:u4K~~:өUg/Ժ5_iĨ7Q5:,*U-+{(?"vyzI-[Q'hՉ#K"g|\xPXj)];#(-y·UXJ mksUPAjXХTmSI&JR;v_J}֝iOEx*r̝zTKI*TUΝ)dcO^z53~{UT530ovK{U$9RP dRVչ]4}!YQHH-]RQX=ǚEڜ +vV~ UY5,IX}U"Y| na-ÞW*USysjn__/ d #Yo&bT~5۫d=9ӖEd Ѐurѧ'YˣsEXڼC.ϫZo?/!#.U%r: z EXE VjMMԬ4GRjqɦ.D+JOnB1W=J.aTBWњdYeHEG):9Rc:5դn[ZlJwogL_hTɲ#VcU?c_+aݢoχn5aHukفZ~YMъ˘ yOZ!Z{6TTI*9>]?We3TH>>WT)&&yKTR0+6\ָ'dj4t mT\}uiNJ%]MFnĕahm xޝB! NOU=_jԷj]z;+);k>IU{pg!T(p4 R3˴pUB^Wm$WXvUVp?eolGzG*:Y5.VEF3fR*QY5Am ;J*QO݇OQA>yF,zۢQeL8[b3>-h/j]լ00tcZS{uwaURsͪ[H%#%I2>JXKDIsU'+ڛ|.=/UqpFӈY#ܭeQ^^$Y5se:TgER=1DW>G*4[~mnT\.\LRn+n]՚Ĥ._ ʫ3&_<voU U ˴Z$UY'>XqLqVIdE9,w5U2]l5wmչ6}>eN&$Yp怎KRNdZ5==Ui*,^HT4Kg^ Kb <$#w-_\*,=<[zFM4ͼJvΝҹ`ٿIۯFEvZʖ-e˪fjrnEV/[%%mbnwzFϐ͐$D꫗k_'խbKae|8=FWш=#A*d.=k7L$YuijmPY5\0^`YjS׊0u6O5N_?hEud7_z8vp syR>pef35)/s ݓ\L'._ hup6=񽚨ah_}|&U/ÿ0k}u.zָeێ[K&ealvkgmfe,jenYY풗cb):Kv,@^s,IFw,ekpd7hd=Sc_N!u&v[ [}OR{ #sɨaȚE=}^jT̬$Mܓ#6Wxp$])2q=o Hҳ;Sm(v=VMϳI@*຅ԨIfæSQI'E.ekoJrw!XT|ª{(Ei{a Kה)6L]^Mq:hkzUO}2F)b]sj7*KiVhU!icȷI&Iֿ5M(Qܵ{_6H2uE"%@dXZy"]%z.:`Zy/51bx=~ 0S )5B5r,мc_9+1 9 wF\!T#259jB5r S@A\!T#@rPbF:nO;VΑM c'p'p'p'p'p'p'p'p'pc~AfIp/5[qi+*З|FSC]2tV1S}h"=[zp~I[M|N%ȃi}:V } ovbRiz.}MJ$tizO)Uo r2FiM@F lfʺ }]Ҳ_SA+(zk=afB(zDN{UP;ь_3BQ[ Qpzi^5Ӗhip5(A6^hί|EmZQ ۔}Zd2bbloKvUedd ~.ՄiܼOl T^׼#9d]4JTA! nS=GoG2jնvDpd;X Y G[ˬgbSV >9f/ֶ|Hl'hnMںxmx[<6i՚>h I?4{H)7T 6lֆe║wSeJ4SlњۇiBQzg%h?F׮֒}螮T}:9ǝ_+V_VX*i~P V3(r돚ƿ8U;S&=?)b&;VϷk=BMW_0tqJm[϶(/Q6LO.^?I\N^[!J.SKnuԵJIe(*yH-yHf5jZ_ΞydcO^z53~KLm_}E6l@3:qZ s\AlxXW)?juJ uiR,s{U=odU(/Z٫цy+\KTW m ݖ dkREJQPL*Z\Ek/[O&CY%T7&,{r,YÐՐlQNԘNM5)ۖ"[hbf6˷tIoJ7Y6 )Wg7L%պG>h?bV,K .TH>>W*-bqɖD/ΘӿШ^eSG<֕FYOj |Dw[̊+]JrVmRe$?wN %->-Ce>$l2˱9.fe5R-̪ j[ر7r,\!=n›Z>R\NweDIsU,?}utZᓇhȢ91UL?[˿o#F_:{g}6M>T#h,OTYiN*ɐROf׽[څ*nɧ`*17d.SISiǡ$IVW K\c>^'lJ8s@GeS3}+Lu"\{ܯhK\>(b}*Y/i3tsrJ~=$$/?ժYFW_@ m@7xS>ekAUd{&fz8Zp%VERɶohjxM"a񿉪\A ] }ʨOU5o"ǯ~\ܥ+md=rbL*R~{#*oUS>Z}bFkM`UE?2#'}SxvMTmʤgUCᜋ֚oiΑiҏԩDf^MzmFzⷊ(9X$(X|E-mX!'zpi.]y=_.*jE钬Y@l1]j62kY gٲطvn9m?@oҵznn>/47Wո͹EXvXX\a7N"T$B5N"T$B5N"T$B5N"T$B5N"T$B5N"T$B5N"T$B5N"T$B5N"T$B5N"T$B5N"T$B5N"T$B5N"T$B5Nrs,ֽuKڑKgIT#WgK*Ϳb[):by3c u)U~MroTeST,[RVnπ0S Mq1͚=[[#"tIR fP|ciܹlW ͛@}z֫/Uc !T#ߤ鉧VDdL&={f͌YGiy;o{?~\_~@goFHi_i[o{uh[oi_O3na T#_=vLsΕdҤ 8$[&'ɤc@@F5{l6z)ƍsW=d4kln([#"$I{r{}ztP/nuQX(h8P|QByIʭYP|(I;Cߛ3o+P|ѿ_?f͝7_۶9vm_ ٬9v@@FY-0҈#mK#F0 =ԧj ?9Wy:~""#𣏩WӫwU=9j2 CAze@AFqwwח19s4w|͝7qf>^}yPpX>5klmȾu -Pf[ep2Du ӚkΚkXJJiꅶv"V|gӜ#Y8U ֨ _;G)3Z T9Z wΈJKޥe֤B}kթm;}xG -7TVsц_~NVN1QFaOVCJߧˣGT"Wu t(*UZsࢬ^~]ܲO\'yJCcY,X}Yd65QqJU;_&IF.\/ٮ &YLI:{֪V!Y/):W5Jgh]Z%=Lh/Y3жTيtT9K}/Ft"A0d.#&N+0Hu,Ur y]-T^aMۍsd>TYAd#=7>ULpJG%*UʊJH[I*QFǬ덯+* |h^R+?Q\p_5i8ݛEBUl2m)!9=*vV-&XMYW wOi:hHXne>[=uPD>mSdPz ?-StM2U{)M\ @> Ty (Dsc5}3lLM8Hd(ݩWuW>u!2 +x=Utkvk˿hLxv~i%} #Y/yS=?4LmmTُYjqqW˪۷`oƾI끳4۵YY]-sj;Ni];t,#RϷN ԣxQQQs,g{52α$IPܱҋZ˱|CfO3? ]T7{>#%]Y%9mvmkf;]a׶ڵZr͹eo;em*ԞSJREmz"K7Pr|(P Sk5qP".ߚ4tSw(ȂRGjVP'p'p'p'p'p'p'p'p'p'9tY>|DTv-+Wa\j1z-]zkʻxP.6.N]w%ieҭb!T#߽h9sVTN;m;mխSGtY?zC@"T#_={6{n:lSzԜfg%Kٌ *dԻWOgջWX(PUl\lLLbbb$I>>>2Lc "T咓| pvޝ]w\}ܹ#_yU .T=նukyzz^7.|JMZʗ/*[SOe_LoߡwhbMVc~ן'߯%KfDK\֋Æi5Ţ`uQMBCc+bbbqf-]Llj5h`h\+U73gJ 'S*$8(zjK=w>+???9cձÃO?Ղjj]xUc{駕+@~ T#OرC=RRR$Is&5;+2eʨ\r P*%I~~~z5 1Bvxt) B5̱cuNoadN -]ԭkW OQ~7[ov}4 T#OWqqcr5a$m~ZJ ƪO^f^}6'B5ĄIݶMk#sY ~q&L$&Iz7ԶMkIfB5n؎;4oIR5vhy4W$eNy}/_N9WK&ܑ>2UaH5J v7._iLTH;j$0 }/ո!Ѷ%I!! v>2E{tEDF귣GqCGhahIG^yYgg@~ Tle$b qu;vhkD$Ih*V Ie&arj8?Oܹs L&ǟ$I&I2~ aRj8m]v=.|]-{. ᴳ2K-I5jT~;"# s=}QQQQv}sW#Ti.]/Q]+V{uٱoE] t99܊q^]X&7KƷov-&&&{\P +Z,{?>>g%QFjԨce+Vܮ\pZҥb pZ2e.v3zsW#TiU*W߳g]OڽgO~esW#TiWa^gڌ.^?C/NX, k*I:o:u;u~;zT4,pB5nH-g̜iד?1#{Ev=zjܐV-[Bɓ'Fɓ' ˫U˖#ո!za󒤴4Mי0i%I_$ZjܰN;wKV^}ՒlWojIRZԱCzj0٬'OOOIq&QygM3➞zwe6 D'֩}WdZ5h`On/ j$~=խSaB5L駞$%%%kah0dIO=w P<5t brOO]Ц͛FMԥ{Mg24l0cQO=j֨aÇ+!!AO>uE͛7wJLl֯_+r۶z"E4i5on4jDfMhMCZZm"mbQ TF .-???IRTT.\бcǴs׮Mgiۦ^*W|UnB5\Jxڷo&L@۶oq!m۷g>lի7.W^=};={VuھcRSSJ<<<ԸQClB-7Wr@@F)W~}0 Bt$I~~~+]Z2LPd2WfMn%pK-7dґ@9|)EnfV3n&""""R:xsM5QHL{쩳1o""""2l(gߘO9^o|#!j* 6̛Ӟ=CluԱxxڙx|5x/"b :Y{.SV-?W}AU(DTSv|O כ2?5;E{™1m?T"""`tdzⅦyX| G}ܚ7G8#qUXC]S|RMh8|y@b~30pp'V"""~ z|z?j}pMPZs D#=[gC{^P@Fab}A ,DzQAqE ˣvo6zx#v4{0W >^)`Pe΍X|lىH1zǖw"9|$z'޴K#u(nބUV-;^I|=UOe>{Qw'F|''`u]c|]0Oވ3K+57<[/ t>nD Gʼnmy /#?= 1x9x/ǣW;x/gϫp࣏lĠwVo1z:kq,q5EK=p)m勱õ>xzwsw@z }xb]2h Vh>}qq-{m(? %kKJ_O\s//μ s|4je[Y'qQ )_b{ \e{Ȇ~ p6dİyx{IIu%1Ͽq6FM(EG ㌳ơOp7cwď_f0L .m\bʪ1اy:DjbQDT==WƝ0ĀU(x@Yr EtCPi=% P ҨC'} a@MKj7ax~(jވڍ%9UX҈^> ֯/ >a_tp cVC vVbXėƨ(R+6Î8n#nqհ %s_g O_% tœ WvYSm)\h8no{ hFcS vn| ʏ$zEЫ%"DЭ[zMbUTz]%(.45Eг%ob㮾X5=ؖF4lyЧ1aɀ2Ǧ$Hp֋yOm DЭ(Xq\8'}{3/'րhO״d5TL|[?.n<WBEȯm߆z ϧ0J -՟H7C1nhͫDJJQRhq'Q>DkPS:ml@K0%%(?S3垂Bl=Zt|Z|}7-Htex?}{MD{@?5ĚаHYOWmDcZng٧}K< Rꚞغ 5KHj،ǎZva{c\5(TSvDz㨯5߈Fݮ4nZ?sWՃPDIz~/ .Y 1 G~]hjQ\#x~A?|K#չH_s8|=ԫ/°׮7e|{ 'n<^|F(' Qb5Zn}Fsa{‚^ OYYtL/vĆG&DzW5%1hx JԈ֯x$gVKzcqQ`SMy%6AI'X i!M0s0۲0 |qf^]І8Ĭ=6DDDDD!y@0S3&""""!)cO̅`cSM(b[S]^!"" Ÿf"4XGڰ\{82P.;h=xjQ8lPݢ|ep2fOyy9jkעƦ(uPYQaDhܹee6E)؈,cSMDDDDҘѣ| *+*0la(.N6nĶmRPZR2æ(^z1c^ڊKP𴺲H9 o j""""TTTIg*ۿĦ(MlĦ(MlĦ(MlĦ(Mle׮]Xj6mӧbSIDDDDDTTS^b1훧bNP@yyN>D9S[wΟ*:ߞT{fPlõkO;{***R\sUvak]][=]jfongPh'L.TK1ax&^ԛ v۞lwlw7ill}u?k̴gC44wJO=L}U455U&=DDDD]JWy0+g{Ld<9WMu6 $zѺ޲eʤGC7ֿf|9Q֍ohA-Ussu ^L9R$\AA|۽yPLrSLc8Һ&""":tJmQHM}QƌO>U/}?mY(~/Xj`3z """*lo@3M&s(ca{u~2=>v'aoh:ʂH$nnֺ:Uֺ:pӍ=H݅w0Pg.;0BSM )|oXOa}\p`544 >[oO6UDDDD]9Tޜ<OeMg6޸I/OYRTT9?YZx1e-÷s:-^ 'nPTTd*r>x?ʈbxg1u4L>hL>hL6 >,bXz؛w NK_̦:L+FY2jH-())oO>c\744`S|`no%"""Jo~8mŔQV1>/LQ0+֒%[ Zs'M‘'⮻?)~yk~/xmZgqy=L1 Jgx,}SLi}j-lڡ.)))S0l2ԄgEEEl=o;^s.6L}x᥅XG7[ W}4)q$CcS#n3?5 Z|$睇X =\ۏXE8g[kᩘ_%С>OX%ۣT3'YͲqy'UUU_iS`xW| lܴ зO1GqN8xԘ3uUׯ؈.pM7[t.|8kli}jܰ;z31(F+p% $FO\y0i0a=3ggc5hg|tp f\s&אM{cջq y%ڌtǿ$4 {W('r6_ޅVl۹s'~p%T uoCWT9HUoTyuز]|kpkn$(W0NE#Q i'[UE_[^A 9l<oY Q"Ƹxm h~[=v6P* ؉E+4'hOpqKX&/Dz'.YSIuOͳo_^'S'ر#OorMgjL?\=w}cN|Яo_\lDB^;*ݺ [bgؖM酪7: mqꍘH`s7 K]Il7;3guq;bذ};=-WGs5V.EtF|25{ooD=/~yQEc׼VaXߢ!V h/RWRЅlO[6Tc%]/]'75^<[``V\ 7b_߾:t&1'*s&"""wr {ι0[Qݿ]{-E)]A1z?!3&,y"j/>Cf\qՃN8kĉG F7;?uf_{ |Ax Ȏ8#^|<2ɶ`c0_0疟`lUbi﷫^]76#ԣhTcwӆurȍd}=֥Β(r`ǎxGpw&? <^ ^իW73>]~94-5Q#~f /S5E;^᩟^ [T1^US7/8 Rֹbp<1klu8ovFpUmN8E{q1k0㇗'4ѽ~v&2ވl;X[ԡd(WUĶ?س(>Ucxc. ֈ X&w ϻ,݂f^\uތ Ӈ+I6grCǧ.~urCuεoEx׏G͛mUѿ?:4αX o-Y,}η1j(DQ,]=:@\}Օ .Z56C11aBKUQQ<GM^[[o_0w|-qm5r9$>Km ݓ+fb:zos;i6'aoB:`c:>kMiX|9L=.**/=HF 5ax<#qŭOWZ)SƲM5QiT[c:>ֳ_JeUg5ao]Z,dR>ZgO{~c8sYlF8s{c֭8{t\TO@IQz/t\ϲ;<']O/Uccv/\7u=}@֒5a=9]gO.6l P?; S}c}ްa#NkךJ""" H}~g.{؂Im)}bzkpǬ05ez6fa7βsfa͚5jnEe}:Y>o~sŀxD]q=x%"fbEM6ozBkJ#vt{F)ʢ<8= uuuuXb9lBٳBqqIz֭X{h) xU@3⿰Lfx,1{4<_0mvۼ5v5Wk=n%gtYٮ=TO]jDDDDD*++1bؾ}MQHa^z1cx3>β9;[~uS-_mxh,qכb1=%f[CDDDD36+}I6Y}jE5*oo]o{jDDDDDDmVP_09N_fw3\7CX7fZ7Q0WLb齬-W 䲩u<ٮeo_i5N?~9M1fv ʧ-Mnۛ:D˛-CDDDDDDJ[Re#޶uvŁ1W>'r2헕]"o2""""""J~xr+6W0ru3غd{Y'>rDDDDDD>_/yi5;ז54%qŀn}pE=.$3Cb齬mp]1KdTgK8þzozlIĉ(5ѱndH*f|T{VX sy[k$ĚR m}}J-Omt ۸ suLZ'z-OԣL<ɬc6.(AAP !1VDZϮs0sswL Q8A+oc)}+r!9=Zt[7H(Il3Fk65k'ĥN֞Y뽎 j˃qMk!ތJ7oT| htGԬit\je1Y'ɱl]Qq5w~ 3N3~XbkiL]7κf5ۜK^_gyͱ,1k_FHӪ2^R'6:&瑘=VR'$'u|5 WhILqk˿\nAF7{%וk$ruv-i%IZZ$ֳ [剈(۟X:{-tsjhukZcY~KN/Qkk5t>k=$.X~WS-8]_k-t/NDDDDD^F>o];t6:6KLe18tNzm#l]V仩hi%C/׳e\,1K\DN?9֯%IGiPyI~b-OIN͹f&""""£{WO#lcsK+Mm:&ulC"kۘӳ5zo:EئbsռyhnYp͕Y@Mrvo' X{h;NbӍv41Ck:Z]]N t0XA1suk_J똮%7Rou׵\IbzvMi;lSD.n4,1e$f_XޠXb1k9o 7 5оɖsuZrnD){f6nU+tkdo%AC7z-T\b&T6ܒuBeocg渌d?b%no>I̲OcYǤfZ]Ez{GWۯؽ=?vf$bR/y^;ٰu۵;Ej7wc &VDL>&ZDLQl4k#ku- !esp>&Zzs=Yiu^7:'Cj$h9Nj$֞_ۘ1iWSٸks :A[s+b,Z>fV`/"ZxOĐka[Ay""""".WټtO9Ѝٽ+g@Zv]Wzcsv/Yбɓ^6ް?5$@Z|u4r~Kbfxm璼^>ʹbDDDDD;G1aJ;Z'v'fF"d]#S'׺Vzk[b9M ꛣoo4돂#sq:/e`A2\Oe踝uJ1DDDDDԑ Wi=_jtֺNfܶ5ACqO&ڬgS}'{1fkWRfXU7Q, ImZ^>:/\#""""6sNmhYzł\im}ҭs3zPku]j\1>gT{HQsջb@ǛQ19Fq0CtġbQS[9I^c]1-('""""`}PYW+1$ֶF76c%v%fX2':w//Iu ˛mny IHUC# ĥegJ2Jf{k=۵kfg=U#l:j-[NsxN仩7y6/{9X}"hkh^[$X>ޠn=$a~=zxُ_/NDDDDDŅf!{OͶBPq=iFb9W=^q{+(jy骵ټll$еt:Pg?_4ET\c$/{:} 5ZuNbvIO#""""Γ/Ie齮sJl^:1{; wl7_Η,7Sw\9u_NlƂVP:GPhA{cmrct\Z$'˥$W% Wٽ]:nO%'1] Q~zWcik9:N7g6o:o[&Y.%nΗj>o'ۜۼٮ5Wr~9:JIKv+f=ۼFvY$;Fؽi>l7UaΗjkmavv"j-tl\k>]:͞tڵMbvs|Y~k?٪ ~QY:H*Ԧ$_ X넭>սN\9{'"""""rkmwLmmNTAևK[Ti}{Rݻj\1-('㈈(?ms]1֤l.}\ק, XF]lM a!lCNT.&hc>-nR^{lOWGDDDDD+M\q{W=ITVdyj3j=+60oj.KDDDDD"Yޕs\\uac#ĥzTq]1?j崰uDDDDDg 4&K\z5Je:29V :OPW#R%""""" Js6&(V&ج(.דɱVsRDCDDDDDW#uֆ #serlVjdR=o~u"""""ꚲ@zT伙ܰe2=>LɱDDDDDDV& g&dž52=>'Bcט)CDDDD+&0߯'[yr+5Zz:O6k"""""W g^SΓS]yvgj|suެd_wODDDDDnwh5:DDDDDD _ n[Y_Og](vunwn k+DDDDDDBlZ 5elOk3 L"""""L1 `GDDDDD'ۣ l3{HDDDDD] !/o"""""6DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD}{5TbIENDB`kraft-1.1/manual/images/en/unity.png000066400000000000000000001635711450127457600175140ustar00rootroot00000000000000PNG  IHDR2c pHYs+ IDATx^w|SU_tP:){#{Aq "C_"8@@AQQQ e/Ae MGz{4i}?WښG]_허,W\ij&}u]}_ DDDDDD/O_]'_ǯJC3UܗN]"""".К><_/*u+f2-(gQ5Q"P\l늧ވCDDDDDIOiYEoQ@k؊r}Eq]yCO.l:3lSҀze[jOj4S]ެ(D 4v^oڇP<Qqr׀%*gv;(ϛfrFqu-n"](g\f{ol༹loUO񤖈OHOjm|7Ûm٦Jr=$3UNf'ͣ:W9^^ <yZ_d%yzW9}p7>Mez9N1Sg44UfMfUP޶r\ݟZCX0ʫEٖ( Qyu-h"b29WW2u[57||ٟ5f\ovo^/u_rLW͝Q(7z-ύz1}i\]Wׂ_՘J TUySsUyu{VPkԵLoXo-_퇈q׸]ݏ&SPYu; Φ٢1qPԊ63&_Sׂ:/މf۟y1{PsX^iFpowku,3n"""""*̛fm{6̙iQ#hSczsUQr?W9Aԋsymf,ٜ.DL.W0SxZODDDDDӆNW^C+94Vs 7Юrbmf,z\qU*_7`*nZձWXu,o6jNV՘Zcu5nr'""""ᮙS~՘g@ms5ׂ^hUU#jӼ|ɋEc iVw_y 0nu?F1#rDDDDDTr\5sr~Cr\'^L}{cFcy.5n7RԼ[jUިk4幼V\q 5Pr/Co-3ʹQ6xFs5ΉQA=[.jZׂ^hr{m6j+/"< mT6r#-fc1\uNI-9sUkYTkԹ [:ur#bV1T#cwh(xĶb2"/ncE1VH1j9jm"_o(ܰ9Q^'"""""rys5.y16:S77ZԷsfRN^l_cAΩ1u(o7g᪩TW5ՆXmD^Lqu-WۨDDDDD،:wM6?,A ^Liq 4hR刜q:`(oG/&s4qz3rj([s Rȋ2}wy8ǓZ"""""2IgT6*ZIͲ޶rN^Ԣ4ܱ!b\\VLtE/HI6 R,Jp"׊^R]{bVέ'""""""9Ϥy/OLO?)p`!箑kqyw~aS^okA4Fcyq3 u.=D.KDhXxч ͯʂ9WݗߔԙjA=zsyAVkE=-i!>*:=􊎉  8{- RL^#Ŗkf^TFwSr,rb,7j,ZDDDDDD =@~%7ۻX[rczs5ILeJQj{CnL4b,ۻX嘜wOX:rr,̚9џ"žZ/snRŁv1y1DuqO.^D}?GEb`I#,w틈UZC݃)TVիUE.{̜N/6dEۿEOoы3zM8r2˩18nl^^ (3oVjgL}FӜ$;"{QGNn=[~V""""""*nM5'CDx*iX{ؽ^c-"'#H^Nʂq+ֻs9.zA[-\뽭AL܌@ն6KD184eT~}!"""""=ޥ#t իU;~k֭5됝lQUVtC-Dc쓏WgEo.3jdɍ~M "n ש5~ԹgS-Q+b\YΉSܱmzSI뚄K]ςp13 Y㼈#[Sk5MccMDW>* Xa4,^R--;Ï"G4Y);Q*zW\'MCVVedX0tнy f)NCHp0֯p t/^x}Q_#*ܱ kH91F\fW< qjIPcu.jLˋmrs-]Esm(;; B|l@#!*f_KH;@8Ԭ\ݼH;n7㖾y 6ym c`4|ڋhݢZ;n鋽!O`ǟ_aß[ԲѨa}|2ݻI#:*@,V+ڶVˈݕm L9>y<}SgAvVvzjټ)Z6oMkռ)6$oqoNFRSddIg6/߂ʝ=^_.HDNUW9X;j|^AS'$!,ޚ[sgq2uRGhh(ժQ8t`ΆEA8ܛ3~O>05E%0ԢydegM< #GO!8(Æ ƣߏS *ǡazx|gFí7>듦7^_}-]CCJxz0;k.~'ԫ(D3&i;n /1 iT=ޟk7l嗶O>!Ořte/N5!1n;8rpeO>YYȱ9󑓓Q?nwgӽU$Rd$`^~Ec\f&^ys22ΞUKLٽo?&MÆb\PO>/q.וh5 ~}h 5G8{,qZ ڟ圈1rWJ#LsW9w91zE )I'Q}B PeS?Tp{3 G[Ů ^),qn9]0fΆzb6DDEQ)2RN>'WCƗSl|xo %qm6_6Z}M_qi=vk?X~"m!b?-INWCRr ~[ ǖDufXnC@1|`, phޝ5v{%k[xKtt9QIqϏϖ`m߲1q <5|(&Nop[5o Ƽa-*M,zUp 2-h z"|Tr\>@zqZ'bhXrոythB.VA/UȎڏ  bcD8zT(}/]E_.eCMD1|Nq~Mff^,99*V\^J}dg#f+O+($J)KI9&ּm nk8C>=7A)yۄ;Tvj4^? t1O<'y *NL=Ǟ7Ezu`8Br:U9ʜ(@\ަ%nۉUMymێ]\ͮpLjҨȗn? )SQz55nj߅JYyD&Lv7(1MzI,@kh-ت Է1h48U[)XC,^{BªOiբ> <9 ;3=۹gpycK/J=saa k4+Wi8u:1η94G kHM;ؘoX1"7!nj-_F85- 3/ƈIIXx)_?2o#\/8^}YtN.ooޗI " #ߑ>~Jܱx '.:c'^4Y٦n= 5򗒉&Z˄{]? j-bbc+ܟ[ ܗ 7z&.˪J8P"9'g9&&[,hT ΓE_oiռ) ;}'ޘ< CW .\xNMòaұ=*!,4Fňp;~ǽnGpp0BC+;nÚ둕 Ms*S{Qp.5@sǖS.54MC* tU;h0=|6oX~ygɤdnC\3x|ߝxa;1~T\p1w\uMO[+qϏ)As<=kq?:w4?/ou0sG눈ʨE;;owaמ}h3Y!x鑅~6 p6/<=!w<ܽy'kΩ?%5i.XKk\1[p]Q^>hFkWc *<_s V^$܀VNNyK2,5#[;X,hA%6Y`9`A]кys"""Ά#<,.DD7-5AfMΟ8,jT_{ jʥa_}$Tˋ&!䵜SPrp3vVwb?SmDnչp "͚/rcd0vsxm;8zɽhn5䟥VSBӛʕ(6r[)3 zyq'^^DLqF\,L,@6"*F"bd^,5κ!pϽj]u ퟈ʥCDpp02ΞŊ~o'/'߆Zر{F>y͛6Vܽf6"""""""b?}#7$[68 ̚L%F?TAׂ1;u{r%]zy5sjڳŁ/ln8\<DDDDDDe~('2yձwyrCw;BV͋ޝJDDDDDDS.o11Vj^BI40\cE/)3ۗ \f&n4.n]Wm /C/.Fg~L};:6kA!/TateFw^NDDDDDDdDCg,թԜVŋMq5 u57su@e9z3՞LԘڣժc3s(Zz]"y9DDDDDD`A]/e>dؔdSmqw y,rRQ OV}^&Tzh z;AZ@r2;GTndd9ube3.r""""_R{,R󮸪s+~̓(Sɓ'51Q V1":v젆HFٜބ"j B]hDJ\̝FUAl^ >O?9F0u\_)gE"""OkNcz{Oj|;p2ڗ(Nؚ#TcxG0y93o\xyV8; tQ9N.lO}ݞࣷ`W,h<wހi\az((`y~6T6) Mp o@p=qC]ߴDDDDe^m.*ֆ([QNռC8y`MjXzv5 !}"ς?[Oe}916DDDD+~LpmpJSSm)bdB֭ѳG5lk*iA{{, $Diذ~?DDDDT^?e{sRI6LՉQkZvOE6KH%$E@{ۑGVBd={f 8?S T@tXA>9p ;Y!*q DD"2OHnʼmq/j")VOO,84+bkq+յs"""R]O.1bA 5B 4Ee0[G%5vq/>zbn({Ӛ"N܈%S/a8T*Бs1H7Ԭe`Q5'gS֟֟cYV(Mf{/u-Pۛ"JL܆'OaC{gϝåm_~ְA4h@"*,gϷXeu|K%4UVC3HJ̈́]`!<&QDU"lJWl-V+,cѧo 6DDDT֙ۛ9 wT'w'9b?a}!###1YhժU"}VĴW5{ v0 oLei=~}wEВGe#ynzK$i,{۱sZ;˭[q/vPqQw ~;C~s8MTԖT`b_T2220衇X)քxq:R+?1lI88þD)s^Ķ@+j#2Wռm߁'_cb?qvZM;~CӦtmMLy322aX VTj! [5BВ9 -]|TPn-YËc1ZENKH' i!Лj/y_/P߳>{,kr#}B KӰU>Mcvh)K0aRW2\wc_s LJUjUڏߕNRD4։`bdD?9X:a촗ѯI$5Kgݎ|U"""@SzT @MEsY zueA*GkGN֓~[?z %lR'_M"]AqLu5RߕП>Wj ̂J:Nd҅ٓO IX]gMEiG0~r|3M -V;u= Ƃ=pQ9RfzTCDcukfEQIC[؜ 2w-³/YԺ{&Z vDZaMu7u@&"""RM;w@V1}{*w2` +O_X7>g[F<&ݾk "ݕQ)3DT,-pEǷXr 6n߇N\!H-.W/f4 7.X؍éaEmѻci3 ۬οq49 @pX%lwF~}Сoj (={];հ#F`?a*5BQ~x~xTM`k2 66W>`P2 __\މF]TDDDDTN\bSMDDDDDD%6DDDDDDD^bSMDDDDDD%6DDDDDDD^bSMDDDDDD%6DDDDDDD^bSMDDDDDD%6DDDDDDD^bSMDDDDDD%6DDDDDDD^bSMDDDDDD 5@d֜ybJ5gk65DDDDDDT&%&nC$"""""*Go"""""""/L5ygػk5|5LDDDDDTfL5xŪWCEvI5DDDDDDTTS>I5DDDDDDTDDDDDDD^j BnPDd`55CDDDDEaXЯV+^֭[5ZaAԏ,oٽg6iɏx}ǓX0NzP+VrP89h|;/Y"""""""/&""""""j"""""""/&""""""j"""""""/&""""""j"""""""/&""""""j"*rv`1~c!|ea=q=)_~ @ױ!"M50;1ANpUp#C--/\{4,>./c&"r(H  7{IDV$<=uW>ƈTQrD!BF˫k;9̝1ݯY ?<_ 0{| \FwaYρ"zT?5_﯎Cjb-Hޏ[6U@d1J} *•/CUC2<>iR*AGP'->یd-܍lL%ʉ{ea7cQ!h>JMpcbWd9Ga7/c08ppnbO^ǦޡV,Cnߍ owX9dG4B/cD*~n1N㎫pezƬ|n+ ~]̸tAǣװѩV$BC`[_1 5]:I8M+p\qs4dlѸ2u~W75C|x8*ơYHh%>u ""*7o" hKkxz(Wמo,ض /`u8 -2*w1UPi8QU;@ji  Uq& %&1Rd@shp:ՎK+EXS^x1 ".ZcP9ފthH uijSg5¿yX5)8hox [-;4+fLW F+kBtq9'69fil* ""*H>~@ٓ'q.2b3Ţ{{`@L Oos8{N.y9v*npdQ1Qe iͷ kކv[,^PMnA]5Pa-))Hʨ(ZaC:jłG"_1q,yi||`>ϝ "rJ(`8icDRWXXpe76ށOmDR6fo@h?XP)G5>ٳdہN7_a#Y'DAmwah ~1~< +C@`>4:pdįsҡZdMjY{>";R7aG\gRR)DGv~7J`{C U7E@lhص5OBvfWpdK|nr ,ZHDD? :cy.&]߷ dA&MpsǢwaM1H5[17% k_ ɐPϩ99;0α8;z)mWՉʋ{`sH]5@ /YVXܞ;_]"\ˍc`乚 (79ز' ‰? жEZJDDo" o|=7 +B*7E/>(@EK)c;}8 YT},, ߦI$Xk݀ޠ)ӋI g 5JDDlfčfe1h=F~}9o퐠s! uG8*hpiW#6TSk)&|f09!f2'""""!]amصu=;V`QX|WӖ.cHrQBK͘evm 뗿&c{)>h?v'B6XBB˯1slaS]B[74߂wfE&=оUh9{N<OWmWIpdg;݈s%}b3hn]\{޽3ߊk:e]㙯A=w[ѹcGt(hH_:ů=eÀP`)?!vZ!=õ]._3!<1=4 3I-'RG{ =1$~p IDATDhgi ZtzޏO8_ +W#:\w;-ؕwcS]Yڞܟ'pXgF|GbF-]ǖ'q4i~bulفϾя~Ħ5 qm F7gaغX?q~9>~j,~6_Y5 QxsMFYd b]/ah L ܉)^0sÇ;PFl:Cǜ1]P}j=Aqmxoۺ5P,0~=\)oF)a7xzDDDDDO* OK|WOxb#v;u*Y Y fPrxPL9c`A\כ0k@։_GѬϵcJhsp&F ;64TcDGkYDǠI^t;=f{ߞSp_H˶ Fk |q*Wuj֬?>o)5O,жKbbGѧI<>܃q=O֛GTX,Z~=lsmB+˄ho,!:cy.lUglcbmA\,V<(w"/qigނI}Ʃa5ٍ߮s,&>c ^VoflK},&:j,9@2"|[iȭѤ]k1X3Xyo"""""""/&""""""j"""""""/&""""""j"b#q>xgoR=˚B[fd\Ev"c96DD%r\cXt_s ey>:3>cSMD%' /f~pe X{f tl˺3_B9QGoTq)֝KOu -j g.=pUѥp{2Z*LxVº7o5Ƴg~^6݋_(c&"rM5GlZؖ`}Sqv,nVgsꆥV'nK~I1ll[&4@#y%^xSX_%rKy\T̰꒻fi*KfEK-S˯Yf_hJ-[l65\r)~ei  3sp|<{>̝;gιwXnRzRvϿoO_Fn\n^F[(ci HYyDq-4BZt> m^Ti߁2qx陑2,Uٯ).\'pz _L]l YW&wFH@z'[U]R|9| F({ci HYe\vV?e,XV>Ya4r/\ߟo/Ye?fcWv'I}.F3ԩ<PVHL1,""ej@,epߎcڢ)vZ z`!($Y }'fP00.6/6'9?Z ŜК㮺իWZִiS Rp4i㯼Jv%yxGֽ_xҼٸ#?3y_PZfA~ưưH٦Z -d՜ls rsq8?re__bJ(p#+Х>>NmYw uuD[:ˋ^Sl2gBn?{'|$2Y" Itjׇ{gm"8ÚF3b/|MDh͈RTv4uoODhz<fd;:׿]ƅ)N3bz3g.%籯ybGXn5Řp$_+zO7 4\΢v烱YQ>[ xo צm>_QH¼βNc2a(Z-➰+q6|gd9+UeZ'֯ j6"Kͷ ԢcT^rah*;pUG:w5ߚˬ1N GUg5䮻[l*]ɟOVjؖHu3cuwMM ˱~XfchW=|'HkB3;mmz >؜ri`]unˮ5o@z e <7XjnEP+_[GG0k_'u.ϢZ -d۹sgY&M8x ٱs}Ou^UF rܸ5S-%V82͙•gV?e`ZʟmVl8K7qv.y_0H_*W8;}Bèd1A֌`ۢ]OYYNdʵj:3cZ eIU)*`B:bf蟹jf8 'I}.FUi`?cSNHqħmbZLG^p2qKL|yZ mÙ.ϢZ }&ؼ*unwy+Wj;GmXTxddlO8s>ٵYpf]ã I}4lޏѽ$> lbOJ"Ũ+γcޞH33a8y&#?o eZ99u՟Р\y|n8` A!71gb %bgXK ,Yg~Z|`Sr$cXDD%4~U?5*X^ʐw>%3Ȉ׏D+aȤ4R{_p4/R5Hy/抻ﻗ͛kVr+6+ \e}U*$HzYsHJJbԯ_?kʒs|ot||!X,9Ohh9T |wDFFRV-S#..ps8ۄMyFd~x^:-N`qg5Ec4hVv 4=n0 ǢEFz騯ED.9Zh߿ 8H v20]Kznά6[V6b%K}#Žls)h,w&bNgu6+)>W]QpHqSR-JݗZ_.EDDDDlQR-bN=j8߭0Gb_/6J ڵ:+Cj2미 r_[) JJZN'N3..=\_ KEDDDDPR-R 64 |=W}AODDDDD((B+Hn:s `ZUyjԨ@###l氈%Z =vv%v%*Vbɳ./@DzX,&EDDDDDj)Y^}e2228vXv|T\٭(ŜHa)B+Y5Zm֨Q#RRRr7WR]Xs).JKrTTTv\UV$s)NJP<=i5'""""""II'~~"""""RzXqV'N3G6)e[ՙI25ežAᴸ#: })|1,""N3R(MX7nhW ؽ{&{wMBBBvA ~~9O/'yGO[X.-aKQqٳ[R"zq\)ư]J p}/u~Zj$\%%Խ5H1#WP 69zv:37GbAYK+)5,q I})M˿P ttf3/.L6@ŊXbv9%% u 9s& y?9.%ߵm6<ϲOۙu[7:u'qkYzwv>3p{EL1y*x L{s/組\˽۴iÑ#Gr,6kР9bȱ~W={:QyC'/pǻ-)<2_ %y罕4ϻ#ne2앹x9o&0xt}~'y5 S~}sUZIu_k]]O-? P:7!ˬ-q-4U}*/J\;3I9a !,b|ŒʖW1:k .UέWnݑk+-oݦ `Ch470-Al?SIOK!8aF*l Y1 /Jbp̟O5,D_DZFqGT"0a%TXqcXDD')!sKS8=%vxd?W,G(3;n#P ^Ns-u{}72C$gxQrz{ja{:>z, r uA-YwF Fw_uTZ| +1挚 )!\yC^U@V q &"rU 5}/en7K>EDģtR^e-oln?ne/kne}U*$HzY꘳ߕ\9r_-Zd};..???||2?~<1q]/}ds0;?`Ŋtڕ Zqqq&lJ6`e8ŝ 3o4+S""""iζ-o*8 S}Ut+;v2qne#+ygsq/\ A3Rh.h k{>@'"""""RTKK7*"VDDDDD"%"""""""H˿%&&d\rlyɥh%rlBRR9|YC""""""FI\0FzzG]OŒ׷=%R(˻+T@*U8r[ a"""""RTKR^=N: Q>.c˗/OժUa"Z jҨQ#sXDDDDDLX ZDDDDDD)@JEDDDDDD.nT&"H;xU zc Σ"}X^'P-qND<׎Yʎ >x6S Kz=h?EDRR-"O6viJ 8}œ KnӉ~g뽻#ݾ u'0b7^O)kϋVAytp7ЃA"""jl4sdVڀndef|Syc+w?|ɴV[xwQNq=UY{@}^?YlŚ ظ]&ن6s\FZD/ZEݟUh3d"o} yÓYϡZD<}Ɋox%i$Р@?YGiե Ǘ7vmEY'6cS(_ha)ݾt'X+Rq=B-ؿ_)[D<3jѢzZ|fĽyfD?WBN ݔX1O2hR+&\n R6%&/=fhq^ɟhSiY4KqKD@"""]AWʫ]~1W}߽l\<-խVvmVۭ앵]IR@1Xbx8l6%CL0uZY6i<Ьyli%sb͵OY{@}^ԟ""Ejζ-o*{2Le}Wӭ*íp+Y1n|6Υ[DJg.6vT?OOfMKz=h?EDo)U|lF;Aa7)='=ÐֻH EK)""%j)Ul52pU^'P-tZ-""""""r4S-DZ{~Vm\sdrT%,x&$]5<ӯN:Ns qmpwTe4Y-"""""j)6Fr<o~aNnη_beNg웪c !427N[VnGtB!ishz*#L׳b17)VZ-8HbZ ^Ay ?fן2To"'pۏebt gw/Sgtҋ S-3npW"ӱHfm89[hJl;xsRҙk;"KcXDDݨLDYh,woO1cKybG-t6I|*7?x{2SNe1,""w) ^Ⱥj71k |-6B"3gVn>yG MVUX>Oxa)4S-"R"9?Os5Ne&$j ѧ4EDtPR-"RBdNҹBPH0-Agq9.ri HiED<8Czzzv +-Z{ןa%,:=ҿHv4~HJIeggˋ1\ۼ͚Yڟ8ܛXt]T[3]$K2ۧ#՚]6?PRj_ww/7Wboc~Z^nef^YUI<,*1!氈lj#<<6aS9Ԉs([ ,\(@3M9Zh߿ 8HY0]N#l':!WV6bW4l.esKAc9hZDDDDDD)@JEDDDDDD.j ZDDDDDD)@JEDDDDDD.j eTyz9T&tvaE3rY^^9,"""""R("MI\J9ۏ(KTe4 N<]X똹X-:sHDDDDDДTex:Ma)[;Ido奁4KjkaʯhUm`4.-a)[Dr2V w+t|==wi[]zz01,""efED3懖@F|0f+La TWg&m07$;|0vzwDd(: ~/f}+}L(9#oS_5ƊưEJEcc>~G)`sC2q*> W`lu}g5,YH>k$ƈ9|6m/ۈObΎ3Syc+w?|ɴV[xwQ\]0H\ױrB}*Ӭ#;6q578E|vt GSuS ]g|ƍyf\J>Ybc{+ټv>پ`399d.+֯glÚK,Sci HrIhQ: 60W]֧09,Êq+)Uǿ ,į[t> onoɞ&qK,MFNqj*e-?W޴1#[ Pǝ{9?R#+mC+ӶmC2őb@WiMP=:W|hٱ97%[hoj1/90UUq.em7K?EDS(be‘tf Q2N/H⛙/cqS%%5N'b LXV+!aXKAS7jyb?UcfebfVl#A V+V@]abHcMcaHU~ {~GӮYC7o'x&̇֏.ӱUY'5Pٯ`IIxPzjiե Ǘ7vmEe F,9Qr1V4ED1x+KR8?7ՁSDLdCNXgy|&>Ղanł۱y%y'/}r&Ûf~pHD5ZQ7ovVG^JO߀ݺSka)R&Xq j_ww/7l5} `siu+{]v+{emzW9$DҳP̪4VDŽå͡RivsT#<<6;y)Ԉwv][X4Mf7`<*%/üwG6޴91Q_hyaB-uJ9 S}Ut+;vp+;FVuygsq/\ A˿%2ҺI 8̶Mf꾥[G&]l(3~QV*ƘG@$⹒!Rhot3Rwӳ CjM%Ƙ'@ITV-ֈa~0s\dٗi5\4<ưJ%""""""Zr1tH(\:o͡ ҧgwsHDDDDDRR-Du/b9/Zr)ܵ(Y)JJ%.c1DDDDDDjɥ8rע8fQCDDDDD()\#y-c1DDDDDDjY kQ(!"""""RTK.F1 1""""""EjFnEq̢8y) cX1,9A+%ưv\mOQ(!%wX-` Zfn_ҝVG~HPss{9ưr\31M<׎Yʎ[uG pRNIbFnMJ ^Չ?-N[ѺE Zq8<^zE#"=ëOu80AFtf Gfmed׋4Rع`2z-imuI[gDFcp i˴}^Xqݟ>{L˿%-c1q~|??~+dPßبeV+ plz)kk׈ p|/+Q~$U;h<ֶ%(n) _$ƈY6s!o6@cXjp[>co{5NưqORWJYl5w1Vrgq=o"""jɥ8],cHIagK1\3ӂ_uw忯_}OnaQZ*uUPBX#VF{pKHp6#p/ZWF+`MKVQ~m6 nM ~BU/6O2 &&yic-,1ܷ~/""ry)\ s[nQNBCJ:/y > X«R4j{;;omspe72~%!e䌏#>mb:+]*vg [d'I}.F3) jR_1VϜc [{LIRfzԬ[!Jǎr s{а'#c{;aFήұהAWbV\{@G1o,|sa3ΣlV\cXQFo;FzJzJݸvǼ>N9rydLxף~324?l'>I%^7WpppN8b*ѽɋfoI8p_HCyq_$;gq`r+c"""ri(\_=u[aRN=jԩ6)5 1{7-xog*΄MziieZeжzC2:_IVm>eVB=wWb\׼5ŦNUbl{TkZDveo؛f~2>Ɗ[1a#ߋEDDIWb{ټ{kVr+6+V]rH≤g)Ui 1K&CeDvjkTJӢAPGxx9m¦dsw.g_{xY\lK`hݢ}.Rx29 S}Udjc3Wd7\:rKqn\c^kgPx2%ՒKQ >KR """""RTK.EDDDDD DI䢔ZDDDDD`TK.Ne""""""ZrQN-"""""R0J%]R-"""""R0J%""""""Zr1VjE˿EDDDDD FI䢜ZDDDDD`TK.'~dN}z#""""""ZrJ6EDDDDD jHhZDM?b9{vs3LIx?A'QVf ak)x._9norRcEa]z0\FWapKEDD\LnI:*'#]Es[)KưY""=m; ՔLO }x|].+^6oޚǾʮ x6}Wx"Y (fUcBaGxx9m¦dsPNX3L1o4ߔHq-uJ9 S}Ut+;v2rne#+$ygsq/\ A3"""""""HIRR-""""""rT\ %"""""""HIRR-""""""rT\ /s@JB~ðبZo>hY2k`3՝ZVnAsYd$*R'z ?no[6\\#CAi יNsk&no۷kn2e>F  %եu:e7^[G*N)Z2{gѯkLiXl6l6V{~?}q}ib2]0:Ѻ ѷLd94r2HDd[n3ُNIuidLn9n瑅<>3|x57-ØƁ1_?9^˼:o΃^vڧ:B=̜8p烱YQ>[ xo צa_{ڰϵbK|~=\Xr9ƶ.쳍PE,;5mtۉ `ϾwWi7<~K3͌oq:|2;סt-sQR]J ܩ4 ~ڃ޵:,S qMKVQn6֭IHrjjB! *FйX+Ѳcs{Np_]Ws}Q{w 6Xr v,E&ذt]g|z/nw.poXޙ~Zͷ, Z}Q ߳j\:uvr$z4SH)T28OZ`N'` LXoB*K'B|X.`BlaY ?{,a0G|&tmm=đT[ q{63׳%n_}4~Zn}(/OJgۗ#?Is5< *oσ/@[I80AFtkJlLڐ 9sScXDD.]9dTjs lVBaÿuBM+Aʑ# P[EmǠrX,XqbdIInf)H6XB ؙҭ6J8{2RMtg㛮?4Mݥeod) PnsznDܸ==ϭ"w A)2dSJ^G~HӕJ>#$5~wi~Ǎ\P,d%eGsUઞؾth i-L?&f(ѡ-;=$,{FD~OTT/Q|:4䌑}%SN9whf&WZ~W {QūouZ_A]=YےU(*&Ryi_:.^x]K[syB֧;%gVVSOU k$;%$GDK/Y#T7E?ܯ'UtoicǏVךpfx,UQKG&Wg_|78a«M|iMH}]WiN4Bg%T[49h.;Jlrux{gj[k:©7Ҵu=us7`UKhS4nP u$\wu\I5+Z=6M>41TC&L%ɽ}4Xw?K5}z~SU^*dk'5iX 2R>%4Mm]S*5MM:Gj7(K,Qcs!T&?&j]^^jүm-躧?uGʌ}G:Y~hi4.DzjzU^p]qzb&jqz[kTը-qzE"Kk_Q7/u pPہ QX~|.~]1fN7gz8moUt?Ô,m(X^ԛ Wkq~}F=4nV{oJR1?~ kJcn~@ԔƳ|jksy:=ةLzWMmOޱvYPC9=YG|9/۫Y?.rtٷ_uiJ'41o xPF 4q%Z7"47YQ[^5UȮٚl2\6يS䤣}+PKJWlz{nzޮtAoS|ѿAZmVP)?j|RS `x60 `ikRAtWߛk*]ooݩWfԤI[Jh" eJ(-*\}b*[ɼ^g5ϧ i2cD4lFa@o-H˔CouI,m{([a(DmhϿ()I1 jW핯_סEzYZt6ǎ64%Me3Vߚx60 P0S xȾPº/]ݮ+nןf< {]QwS̆;䫧/>gĄ(7\gv+]-=lː%8DmneWz3ܑB[==T8uC+RNocnQyv 4!Mf3Vߚx60 `T/S}ۻl< n[$ټzʞ*U*ݼo{=̧䣉h8s5p9XWe$I4W U N 1W ^?S%soW}zc^OhnH]iR%nNIŦmO˫,-Ƚ*uC̷J6ﲹ׺r8@@W3s@-p"T'ΩXُxsT'B5~"T'B5~"T'B5~"T'B5~"T'B5~"T'B5b]ܭ7' dx7u yb<9B5~"Thm8c ߬P$)[o\~x-'WPw酯R`]zA}M;^XBnпw╫#x6 hS^D˱KN $kWK6q.BVIk/7O_,atgo74ƘԲs{+}.Mmzu1ߥb</B5dS)/ImگoV[%ɕbRؕKb^,ڦtzAcU >"?oߨ 3[鴩wK+O2@@*>>tg=VdJ,,VRRb[*0\Gg(P,Iu@8c(c\MV=zblh^M 8^\MP7A%_ּsRR׽7(H!j>F{E)NI*Ў_hMy?MzA}K7hWF ա:E;UTlmO@L5&Ȣw;;G_>Oxb$䫧/>gĄ(7\gvʴx{>PtK?@]Ug >!UwobIJTR9%޷=.\"GunQ]6yZW3ըڶ-UPg8?1S xPiҥ^gJII-{XTFCHh0ukUX,Xvқ_'XXSOiUJHHлo~AKv]v]{>w?%$$hUz⩧ͻAFؾc̝+ŢyZC6w)3d`=SX,xm߱ ?Ҥ/A2x.B\.}fj4+WJ&]tr/$}  <,J O_}  m6ܗ򕧯hhÆ$drs͕thh_vVDV67c՚ɧZhݻuIdgZzպi2 CL|_ R/1MvUtSuEjœV޾}̛y|*04lP;^ p`vޜxi}h&52bh-Z\p-^GNQ#))zGGQJJT'۶l$G))ѻG`KcGРu/RޣYNX '鮷?M+KgYGhȨ3tCk{$}5y!Ԥ_03A[ǡI+KӪ#뜱y2sJ)'K*(]Z'0,e3KT5/ީW/ʯ^ԟ}9<ɸH_UoV)8Q*٠ S4fm%.p,^یHu~ES IP *{PCWWiLK;dNj*ZK=GVE-_/h_E6Kr4ÐiJɊQ-YZ*..pj~wzf]ErYyy==Mqyz2|N]3\(CJjlR ]xKX @ T6:$^yAQVm>V"e4LJWv: tuΰP4gt]4q5zK'kp LCo|Iߢ'&ՀAC54Fv~.;LGܭsP|MS}ۻlUg >!UwobIJTR9%޷=.\"*;Fi]v_ûln l9%$UkPZSZX hb=vPŮcuש/PȂ`Qi`4s4OjDOjDOjDOjd@-H5WgPs L5~"T'B5~"T'B5~"T'B5~"T'B5~"T sАB*Qr"2تO /Ks]l@hpvf<&PKzcL"sB5O WbM-é~sj[Sf'{ *!Z6C-é{ pOSfYޡP> ʳ($-Sbs])(+{@DjA>z'BYZUdѐaOm:C'T IDAT%ϫhZ>D:C)CE*r"8BFS[zLyNw)#-jj-[L_\ ]Kr"IRچ۴%D\@ T^ĆX;sҚ#ZPkUTq jP]shPKeU "u®Hi/Pըs=,]eH_-{RPqUw BŇXueP!DV4Up!6n=)\W~Quo\`N=svg/Ui'Б|9XrS \k>UD[䱇:\uSDf>WYrUcgw_coSW(Pln1Sw /εǪdyиN5Dݢ'P.s| aQ}w?Ge2m++@C"TN\;lύIwWzacnHx7.Httۤ<\#ԕ-TB{v9:>! PZgJ'ܯ/D]v]qB$)sܳIS{!Q+]#mg$I.z^=C;=+x'9U4,B5jGgtWWKHwxYӝG.[ aQ+C+s'9&~g=xb%[=$] P e#HLꊍk󆤟Sa>!ԦᷓV^RRF .^*~K(.$ή]>?iz{[ϳ1B=YG;!j P E{.%e+[lmyf_Rq7"GlV-C(,ȷ`4܏Qj P  v2 k7hCjJ-}vqÿԂ6x3ޏV|ER ׇEg2I:9@}k$&@;$u-P mN+QN9#[;L 9ņ^PjiH$I]"mju*̦]uHNNЀըeIe/0.ze>hjO>yb'ڄ7lup&vr<~:5BF -_dZt]0Ss}0~ޖb~hXjڢڕ垭&Xu 5{w YN-_hPZsӿdtzipԫ N"g~ub[SO+IZEhlLr]֡GEjq%W265AFn>>:fу#4gJoX$Mx@m5Oy%&E0 k-Z%'umput,2܏wBFh{rjƀ [MO/)B-O*Rvq'AG[5,Ѯ3;?y%fъ\> @#T^8\k{iLoӐ6kwSiR DLJ밨SM'Uzw, sB5́\Z^AOǹgm\_R5{sfQQfeYJjx`lqA{6)vڐZ8|vܡݺ+""\&))Ya!67ɑbaof 77@] ˯vXC'@a90 aEM4~;|@ƹ0P a0h*8 ԞOcS'Tɗ1|X;f2\wGh&8!ZeH7hԵ3%kQ \wzGh qwm2z ӵfj=F!!!&ɗkqnɠ!CUd,{sV]{q[ZZ:xӧv[_dH*Lڠ)0ߪ587_fPbEź{e,kޙz>8EXck?oUAA$w^7?a=kjGVghU_.9,gL+E6Zbqv+?nMHŵn+7FA3cQQ+]3{t(u=]cVj^+pHi׎ O)ԖivS8wҐx"T#84`kb/$TPޜ5_~=oڗXkZ3OētiZZݻwKOOE4h`uY˗/;$IC ,僰!IFwUh޲ЯZ~(VE*i/gPǓOR U=g3cd+4Zث#yrdSG[b="Q]ztUPZk:/U%6%t ڷ}dqĩCjFAvoߡCrZ n)P/"ڄj/YnS!{D ]ۺHzD*k_O$Y0EŻ]*Y%LJunС*Iׯ^\eR/y/stW ,ӏIukG.^t߻W_>7ߨoܹT!)X?KW[eܵ<\CۄhTFf3 >Z\!ÆUX_W ~Qmg$Iy ^6Td+EZݗ=6NQ Ðg[Mxf%"""{n^RXאaΩ*TQ!Gk?oi^/[#q) U/C݆J֜? Q" R$Ϭ!%DQ%a$,c,RPPP Ulsnz^9T"Z$$*J-Sta&SEB93}OYz7brRTQ{j?KeWK^e!Yݿ{ahՆL=1TK<=.FTK7z)QudfOs"SigeWNrpITdѷjРڹsV\ k:}Z]${EEEJW7U$m }S_-ګs$Nl`K6?E:#KC,:Uvc@ V"=Q?+95OjѪB-eW}Բk5X/8Ju0V$ŅZ6 6^T٧N~q\ZGY;wIg ]UOomyZw6Q$(!gsf,FhD:We$Wv}.}Qjo3|+((P65d7N!!!ڷo_i&0d.͐dUt|UrSSicf ݖcd}omSLإiŒi/硝:U$C*R^v+eew%[dT əU`C(!2v*);J-Ȑ%,A;]\rd)ez6'fQG\ZXK2rESEA6 Ņ{jW.2VuȒgH}U9N %e:&?p0:P05ѯ8=k^}+v -JA]8/_4su<0dfOv)ٽG;vTJeddh csUYc{jX N^i˴RX|Gn4s2$YbԶc~}]X}58W4VثV(2NK;[? 5X0y5,ajۻ\;vj*QlHE2c(^z?]2vү+%D 'EpS:OFE*{.7ĦI6^ g}PTy{qOG/0WE=:.nĥG ޖ\+/7W7?z֭[ܹKqZywn;>~B u󔚒/]1Q$J*)ݜMe۞vWYZ.ӫlֹf]6yZW3ըC՝s ee}5&˷ڹ;[%mԏ4@+:sŕW5_З> cỲ!l8i T2԰p7G\wzjia V_ƹ2ިB5p*ȳ`[d0@S9 an3B5pǯh>C|@ƹ0oqvIү%܁S7j8d!:$%$$Ɋ0Wj _s|_X`GsuQ;jfw^oھ} >P]dW@Z+%5U99&PDD8@|oR޽Cjf###eXZ`/!T4|yns`Tdb 8*u'B5~"T'B5~"T'B5~"T'B5~ 2W XQZZ$)66V:vn7DFr\ZZnʵk:tYgj` Pr*=}vsS"-_BWoMא  fr\euC}zV֭%I-[TXX(I}vMz6]{5e@AF z7:tЍ7ܠ3&LPhhWO)?@kڻw\.}nu VQ,\X.PO"-b?c$/kտZpWOh|c6LIfVXYySCpx#=WO)91efe j7}s7PVi4hNS}4h$wH5 `sXd1T77),,Ԝ3OXVU3O/+ϙ;l!3MNkefWjڵɑ$ 0@={0]=4p]N999ZvFaJJJ+778uIrJJJiАPuޭq#&5Pm>fÆeGQ#Gju&Tdա};%jen֞ݻձc'EDDlܴI۵UBB >8|vܡݺW9I绚۸@o%%ҥWvRv{MAvN[l>o_ tnn.W83;d4jC\ԤްvhhWo&( ×TϜjS=T"P^-އ 8RWwOՋ@=I QnomWo(͔?UScXO P]5E 辶$-^]1 CWV7@/j!@ I&# MлW/kN={hwin>Y;޳GԮ]; _@k9L|ZLm_Lk?ŢkYTfVWdfe鉧,+pݵX @#|eof }}|!T;p_]ܗ:xnfzU.//O7t<$Iڵr^Mw:dCͩ]Oe_iPzy+kGlܳeZn&_z籶&_z֮['}I{V6il5|aH2J/Ur?הS5j3FSN.uLfwV|&:ט>T5UT:ҳGzKr/Pw3M˖-/7se˖{ ., 3q e}F܊/ST6C#%%E7tz3}O5oI)))5 j|sKsI ʪSW7{:n|-:"ө j…(IRF׳n_zI574FEQQn.9{+U漬>] {U}o%'ǹg }~Yt\e{Y%h/襫z}be _:ef6lܨ^ *k5rF W_{M?^y1s;zswZ#IPŶﭳn cX|UY^-4LuMWJסO |)W]U6k푑yL֔_jH~l6~ ssyF̺^7}wU IDAT.?i-9~6r7Ѧ1O+!P13Wb ¬Yo Y\b _/˥_?m}];kZ]>z~3G/qFu@*b#ߌV]YMZCTYf UV{ݣS҂ b m߾CiiXuMÆ sQbbiM++,,-ݮ=Ӳق| ;u3ue?2L~XO\)/K\/҆dМ{}W _;Gy RSA35} =>sXjK/ᆳ=幒ѸGGD8u0Һw+٪C*﮳nyPIUZFCgsm5~QOIR} z{ѯڗcSlKD{v,|IϾD;sl9anvNmk/{n5Q1,UQ*Uz循Րڐ3荑*7ceԳD]{5kMX~,((Э߮z'K|9mXb>*׮cF*5Z}Gӗ?cowU;ww^V{](+W$U1JS{ڜr9chist[/Hz޷kZ3\Yk_&./ݣg67:\vC9+_ݳSt+]m9`~ұue7z궊Ԥo4թW止.Wԋu{W [oSDDWK9YrE*`QϋqыkҕWXRqC5.{kז[ H9.ddɈS\CmUC#.v@uHVJ[5j.!?F/%l֢%3j i"#Z:ˡJu B}?K'Xe\۫RUECTPųRŃg~c*}2A~{9Bϥ2!A\{ޜ:w|-͔f 53M.0HWF-Qna)mQzrʓ1^ܩqF ڵn٪#G 0@|Tgc3euҹ}[BHSPNJM^-y}z\VYSws6dQt\~ lV.%J͌V8[ґ<. sZ'd5jp˘3UEe3s{u}̪jkp؊>Vf*dsy T}܎e˖e˴{ȑ#Bu˖-N:j5rM{hjzzj^fZ&Gj^dujIR.Y#=U'TVvĶ4ϛ( s?PÇk6zzl棺o#ONuc9E=2?AaV0C3WԬgSh\{5SU(DdHjk*Pue31!*GUYaޟ|77ЪV:3QλjҥjQ㮻ڻwoYݻw~^^}>_ws&M֛o_kZ4=u]uM7ꊫRb=#٬n>G7ŦO_ڣ̢eӚOoT2vc6ѧ˕V]Мͪxb}Y{WO>O{+^׾%I?đy6+><>;z+_y`u|;ޡ _z\]oUzmч_;n8w~ᮏr=X>7/ӏ\o/ ߢSk~|7Shw;ueio__Wu=M?czߝwH:+_w?Q)}w,}E?w]Gڿ_>}#߇ԩSם+~W~C~_'}By/7N[?i~{p܌[|rTkV܍jf+U]+1Ocn'^b1^SOH#]_vy'>~ߞ>s]W]yr9o:cҗ'>lE.H?s?SNqŭ]vo{[u}[n9Jp⡇`wtNQyO؊\6not>jy^LuxM~ ^?~w벿n ~㩧֍7ݤ?U.ñ )Qyr<1omg笻V5unju;->v皱G}T7KzoH:h>o{ߤtc &=V 7ӏQꖻxۖR<ϣ3ZcnLhnT/ccs轷߮GyDt޻^pUm^p~w ׏<{V wtOTq,u,!o6saUv W>KCZGcjךJuZ7W:/'y?nU\rIخK.Dzo~:yd8^]cɣvVNE,s>ul礣7ߠE<ƘG̫z=uׇ3H:ܿxuV}׿z[~7M]wYV?:qg'~18Is9rgG|cɓ:w}.t:gU1ǫ#֌b"U<A#u'%;1?^/xSOT#=/}Ωc{πcqzծu{gyy7KzB:e1шG, 4~7޼WWCvNux#F9eɗ{h:s?#ַ)4;Q g{+b:9]+5n &xH{bLjWogZ^1 yuW,b:殊M6C_tk>i5`-?Z,畡6T/1y7=s\DǛLUeGuZqpoĦQ*:-~YYǺoJiKƮ[k[Uja}*&ME5`U)zXg9<{MUױUu9|מS8`'uǒn}_S?VN?˷nf7"b3+{j>|0)u<^mlorWo7-CuU>ǢZ:xD}_ c1#ؗrI8"k:rN6j X60P#W=M7.#ryyvn5(EIIߵV_˯?Ӂ+G];u<U,oIT7vuܔ<ȝA;K{'tKcns xX50N*c՘7~'#X{ys._c|Xʷ+dS=E|ul=&%*}L5wfvD]XX'b7hQ"^rj[MuPb߄,bfǭryr}Jݙ*855Z Glo;hy=5 <il;r|;r\Wq5xsV|TN976>Mǔ3->:ב}{g:k!*8j5xɢi[1iX~y1u9<|[n[`rcyxLjG}7)'̴x dy >o"ǐkئzj:>wq|sc70\u~BG"bޟJPx5R颿ȪXA|OuntttX4LG+-Γh g7qb9s{\9UV3.uU㱪ns|jsx4_wi"Ϲ*vlh 曗kg1 :?Mu1f=+hx}u_ǼSt'̚Ǣ>9vu}c.ߜo`4c!7D:khG#y,_w<G:cΣɹ*ީnf1\QDǾh5_{?XhXfҶTw=:\ufmhxh1 84\j?εyG{MV68N7'7Mqܱ/\<Gt:1]_e=!}{|VZ5J\Axۛ\3td|)kͦ&.9cJk4_7QX57:9no}bG>wUc·jOk2@͜}1G+6F;bGzJVMӴFbћb'0+rMĕbZ3u#* [kz(5b>jt#kru珸ҼZGU*gj}u7C: __h+7NZǛMw:_#6$<窕DuX}=֔ZҼyOk^jfgT4ئګ4*&:to<97ߴ=-ڼVub7;˿,o};~-|+`3Z]+"CX{/vBJ|DӬ蹪^=nrvCXW3tΪGy>b#,[=o6xM>U<vCy5y!7UqwZ?B4UG}{;XXʔAxR/u:y޿"&q4u㩵:jPםk"1ј[|--b1ǘXȿL1XX_z~ 4>rKDS=E `S:|}b]OZ{yXj)5Ūܱ8ӢJM{x{Z4]5S먉u~<粪a(/)ڼӪwϱ\E;Qnrzbcc{n]MUq=I1Ǖr1Ϲ,uoι11Y<7 o[VX/=|} 95{sb|c ^s8X̼?D>y.ι\1q_P.=-}97@}jsU5XWux+֊*^ U]6[j<}VєyQXƬZ8ysZ{\:y}kCo]_N:' b|A{)*yOc]ͧזT[iy\|^Z}9ǧ/I1byڈ{1ϱx>fWrRμckԜckG Pj=?61y^yWpIDAT}ռҗM|}P5UysU"cuPCخ WHs:yy_W5^_Ml|SSs=q{zU؜UGm5Uǐ목Ƭ_WU3&1S#P}yo̪\k+>:`=Zīys>b}̪eLݘ6T=uU5R/S۷'|^XfݳL{ZMI{k}eul)s15ѺVsuRV9sV{:^Ťv\8s5z\bRݴV|̪\ Uϫu˘15m){eZׅͫ3T7vϫue]5vߘoVuRbY_]U/յ>-뮛dMs.Ӹ5վ*_ŜLJ֡j =>US[ŲVڟyZ[;nM7oS?k5UԮiͳVMk^i[0^ӭ m[jd[UӚgUIj't5Sj}keSL_q5qS;>MWھ\6ئ/*&MojʎIuXy\fOh]W2{2qRZ{cYq6r2{\+.`S;e]pfZW9{gK2M4J7 PTqCAv n!" ʢl* eMt-MY'3w2s3ii1.3Лys@DDDDDDyiC_' DDDDDDD} 1i DDDDDDԧ1QvLZխQYY٭툈z믿kuw;puuuv"""""ŤIr.rW}No uuuyۉeee9Aٿ bw7r=QoF]/0O4Iq3;_(p<PQQ"""""":\Drtp ܫqee7oRa[[[s2 EEE9AwʕD":; ?*k^"R+ǽ4Cq]]L&²,v@lvo{DDDDDD{$h# {u0ԡPH)/r{qJqyyljjhTZ%lh4*q~m'""""":7n H`0-rq_`e8 F$uEAA:kW".lxqN؛}LP`&I eY2uB)%BPJu}vw;"""""EJO&> xL0Z3†+ */[ Ai&7=,<߄՗ >lٺ0l`z'1w,x],˷If&,Ƥ|[TY` ƌFaA.:[B@k-H+'HCoض584дEyx*xYM({h_S*/y峿pz&$ў;g&~qݵxmMlӱ օǟ^ ]w}'nD~"̙9Ϳwh'p=G{<;eՔR1mS+&be˶qïnGY[T-_~u;c17Ma2SdcYR 3cW2rZgP; D٤Qh @M1p !}$8 JWVv/Ɨ>*y) ѣy}rn2xZkXu>orhSBs }?f465nM1Fb{KP[oSJ>fZ#L"ѹ̨Xq0aQ,>_#S+&? ~e+Wؽ㎙'!ZTu&_^=jy8b-Ï>xeqO_p)(Dvzuhmk5W|#~kW8~RnW1tmK1ϟiL87vgQ/*G?}#.\c{$W1d 74Gՙcdx)8_F卷n';M5[qOw?K.8&C(–p}/ 41m$_.y@Dt¤a̧NĸFق? S+&^n{3b"~p_y2q\G3mJEN8)(g4~\NcuaPJekEz6 ;Kj([_)J+Zq-1䈑(u^ _1О:ZwПp핗 }O93u lo/z׿*^5[pi /6n(XK1GW]/~TOƍ݉;nOzhp)y!]9z$~dيf&ih 0g6466!گ?ś aiᕗ+EsK().<7zjmZq0L]C$- qK/q*ywРrFqP1|\yhkoV&ݲjpᶻRP|asDqJ&[^sEP oTtD".գn{t4kw`WreSLmBC'oBaPо&i1P߅u\@ ? OhoFsrRL?7z',ˆe_݈H$ɿ=D25Y˂w`Թ}5V/o?vv1Y%f&:ѡjSՊ↟\[ٞl7v.aWXomw=\S0Ξh &\[՗ʎ@adf~@QMoS+&˾[UWjJt]ouږ>??^e 1z`X}|+g! ᜳyo·e:+ߋ:xgR<̞1 Zk T{ t5[b̨Ə#2=Eaa RJyB`vRcܑcO*߿mIB0G;f9#S~>x/^Ծ/UW_܌~q3촾u>@5kn=ޜ0uO^6oΞzڬ=7/t\5/FN>4 Di8ZދaG[RRynsw[~s/0U-ƅ>{'Q[W/9\rymk_߅X 7~7.<;,,zo ~y;^No؄n }㫸 qs $ݕXRo_;n-V쨭o-x<܂Vomw"HwH֖nkre?>.8|SGK{-|cw~[;{&}nr#":LU-߻*Vիb҄-Unu? +WIGr+篬բNʑ#GZ#BS)AT0uT)5lx e.s u:aa6@J0#"}/k4\/fc LvVf}H!DDL4'M_I>/6t~JWRk[Öw2ZLBT:N$nyyqF]^^O?}&nmUw{W ^_\WW'ɤ;)/`QildR@EEްarys? ƻۖeh4*u]tDVaMJ)4?y""""R^~ Sr?+@Z=ز,!B\PH(Rjf^z5ƎUDZN׬Y+VbiUDDDDiR\Nm ˲D(㌽oy49'n: &ܪuX,&KKKE[[[nn״\O?~o&""">,]hi u")Bz @97nH$'Λ7or_YYY'MpWU0Aqve ɤ(--e qG)%ҳe~R" D"!*eY4***ʕ+srX4ݧ՟Q9W8㬳Β+i7L&E4e ۶E$dRHu8R! ÐȺADDDDDD=I!B)%"@j8m[@4XLɑ#Gj(**W=^<묳O?O'`ދ WTT  uuu:f8K_`mmmq/P($-˒J)$麮BHbLDDDDDG 8^7j麮t]WP(x4\媮NTVV}Y9`U@b{|ȑjjjÇqc'CDDDD{B^ ɤ)ZkTtAA,KZk RJ > a J)U8F0555b̘1 *= ƻGQlD"Rlg0 p]׻4R"{IZBCa"zM!8D}ΚcegڈvEJ)R ضP($Rn:8kZN? tڽuv]WZkBYD"QSS/{_9i0W)BeYRkge 0 a۶RCaq8 q}t]7hFPk D}W)ζec""""6uM!(J) 鞾R)'p IDATeY6MSy]J7 m,dRK)(((Pe)) @B!d㽭w x]]]J1WBP0DHJ2 #$'0CQJERu0PCJRJ] I)WDԷ$IKaZ렔2( R¡P(m#"B<񥔡D"B y0i!tN3fb›rr⺫J1Ӷ`( YB@2},7#0Mӫ&K#5ZK: !~mk;vҪ*s7a~,BiY]K4nGcBCb PշDv4Sa *AhSJADzLε0 u]%Ԇahq֩@owygꢝav۴W=v]WPB%tN2@F*ǻ Sb)eHJRJ@ڶ- ÐiB)[hV& ۽%RA۔RAu$}iiU.Js\zŸ07/Ra7r/υ7|@ ~U_ڌ:w=`LDDDt!BZkG)%֦hn:g'?{:+cLԮj5*-R9]0Ψ !Bi U T_uӫB84 Cd`#tPZ !`( !SW0_bAqq2m$^YK:m2sXX܎x{;Oc˱tDѴ٘ Z!֦2 pRJ"JZ#=?vGz&߲GTTZR.GaMLXU帲Re]hJquu7RJ4@ n}g۠N5Ttβזuwu.hoo~mL6ߜpܷLv&,[ ȍM,@uqk`&\4qtvbH&ϞH&DDDDPXX! ÀaR!}=eFB2mrv `2b 4: j!NqFuuuDw*] (9rpXJ)͂@"ԠPpL /$tȷ._uiO7wq!A[VVMۆ e/oМm][ ިc,fO/ެDDDDS&r`7%~k\} WhL@'s݄yϼ^w!o'+AP߀.HW]ehO0$$aTq8㞧˦v3ѡh_氤en']MZUZ 43ԿMOtY1'3O eYBJ)LYu7o"!EPZ!5_-6cʔjccсqo7嵴 =Hf9|zEfb9KmUK6A2l>GcgBŦ{pĚ%XޖX`IhafIYmhiiCv\~hNK㩀dƎY>$g >WGܾ4 9QKY%s'0itjeZòm444Bݮ8+sg=0GV)BxZoo6p:'gnRYha~P¶M1RCd`flڗ4︵0!~pehHŭCQ 1i75~>*ԥW"0Eç%o/Yj[aw+%߭X,7 cQY\ZiЉڱ{ ۞g>Ign#0|&xn7ϟSn!""":8tc57@ !.d ukM(/˟ TBd2Gx<.Z[[sJZk]'X=5ci5HԼ_֦8Ѐ. ݩqUUj̚^>ihՋt"[?9sǧ 3] nD2]c,,:Y/&c&Fdrq;ϧB1`Q=taB7cԞ',AݙP X|Ul2 *cƷ'-ij?'jUju/˗bOM}g6ZbRbat9[? gK$9˖m JԜG0?p>wVn~ܵco*ׅ--xw;xW[oaH&Xr,:G$J.^8^ʿz9pfuy;&ΝӐsFY'cpfݸ^d51P ֘'5ܫjXkWbms0cxȑꅋєon1qcOwOG7Aw{X2ߋ#""":4ضXk+E%op%P ]ufr<Y d]856n܈%9öx!Vl\tTߜX-FdEkk+ο3v>qc0wNy@mcgazvvc@ >xoX Ydf鞬^k‹KN47{w&F,YKo|L܉8*sHېBq@ ӓ7dqwnm{:_oS> ah mR!L!AAf^uٓ.[%p`it `̩(|UIJ C|pm<ΘaY0ت4r7u.FbZ,ǣߖzKw"qgNGĒTse"|ih-Y?cI` ?Nʩ8'N ^ɹvWqG+08ay+r^a̶x[rlO8rh)6bV㿏<ެ[r(Fɛ`m;hkoCq~yo !Css3JG(ϸ_?0t̄\]u65G{(?w)*Ms ) C^ }`@(dBkLLK׭z;: ")Q:g.=gbֱSۙ{CÌYr&ދ%ša}"nŬ-@Xޚ#ĥ_.Hj@]s7ۥȌGg+I hky7x) {͋]"O)*!w%q1[ sqG(NOUGcSs.աP=a!\R)oC(cb܊.n$α6Oɾ3-78 '⪫NAy "qc*#R R(\vnL 4*EԱL%+<ZLrhl@ @`@81 &J$p쿕S$=ӽwS7MJdžDV.D 1 r6("<sw}’ms,L/$<8omB!<S;_晘 k11WlĎvrQv70i8 ̝%pEӟy/%Jى`a7e>O9#S'Вqʋ൅Kf4p0Ja8̓'tqzP0`0F}C#l4u"D}CcNOP0VM@{|L5r$֨ݹ[(PÔ4R,N-QoOƚ. ʫfL̸9,9moC.]_6<1k5\s+8XZr(}v w|Cf!"""ۊ>51 %]Z,%%}[??]1#F`!hlX,uOı~Z!0\@6 -Mm84HQ+DD=ڎ5Rgf"""*`0M/,y'_3b¸.\ׅR*Ӿr l! ? Qw=vˈu<8gb/O*;}B(;GېP0Kܼ=AGp<wEJ 5;?vꚷ ;pm OwON:Laf|΋xbN)㣟GFѾ0M ,E"D2ep 4 Dj?`i&t+=R+VoęsPh(j""""""Q0.--mmmp]W۶rܱƺqԢ `GN.{ hي(/.D{[""""""cR"v!e{4({&Ɯ#Ri"E.I ;?[A)@&"""""s1`G"p]Z0 0x$L;c""""">Jk-e/攞ט*!ÇqFhoDDDDDDDzŸ .V֯ IDATX5Q`,j8݄+EZP*ҥ)*AAAJ%TT$FMٙB|xܟ}εY69seG[]|\vhiX, x'ȧ, 2Z!B!DPj]וB!B!#PB<iGfб'f"YiǘyLmB!x`gCEF,\3;#2ɀgyud]<ֽٞIP;GW|iP^|##jyZ>j-B!c!}wxHf ^mP!gG+Xػr*3 C[\QQqs۪B!%Xqhi*x~X;+{W ;qڍ0~2uGc6b^5yj(M̜%1z?A.JA<ȢO L1=jK]Rw@orv{V?^૥g,Ga\=93f8z=ŠV^!dd B!"~l[3Ös,g{K cɦl_3RcG[ҁ,zNy[ኖ??>odV6~m8f=)[#Q^Y?)mK^zz9NOu1Ema؟Pz~-X6̋?bCDB!'Xq_q)x~V-k?._Ϟ[:{s=5]յ6=✱9v6]{gDgo_\KiM4# ɨ#hު[B!/z@_! LJA.{qf")ܼtQʷ}c| '慫؎%i+%F-4+W#>cܬBVoJh$^;ř2e߸Ⱐx<>| +2Z!'ga)/+_^!>g*>mfg%bT'ZKsJ޻ fOsȜy~M,o}TR2b@!@=^z?_߬>ޙ7kB<(e>jmCO1ࣥ g0U_w}b?iKI)A١ֿ e8ԦhWa?m^V\}=BmJ9'2n#B!(5E {~ tGy4iKHR7yiWٳᖴ#hw)W2;{S^0Ͽ*={p`9=~Ps=<-9g| !B!_3IONϖGB[G<:>]<_Gؿ3ިɒ^7c,u}T[B!$AQW ϤSwf}D4nQ=Z؈QYYoݫ5Sin@K͸&Wv57Hz3 A?yn@n<)Gciָ1A!t5Ch2j ?O@fhؒ| X|ϰp ^kݒ_q"ܯUg^/^+}?3n=>h\e2$2nM MЂhBƁGۯc%7sfD^lۜF jC=Z !B!47!Nv} XCEeq8+.bx{ sz{~&ť *nЮebDO{[8<'4\`l}ص/ґLq6W'n2jgu~E}3sk,*==%ne{ljk[ǒ>$=ӜbͬxIbz+{vc#k-Ꮜ_jnSO8KSy 3#YKMFk=)TVr-7#n ڕ᎓l^Qձɋ3|F{yem{yQQ%()s!( Wm~yd1@Nułi$$$vyY.aJj ]e :ׯET8z "5(#P :XӴh4N J>O.

_5;PN5ݬ5uϭ`$h`I`OGZӮyb}J4'Rk:U>Ă\J W12/Ӝdѿ+=G0{(C˜>TS>h܊űlMצgε/_;?2Ǐ]'Vm !B!+GQJyTGJT~p?Tt`!*c1Uڮ-w 77oKs]kjEΘFk1TRO{T)Rf71T>n(um]z^;Ln~To[KҡKwWNǠ8q._ !B!#F>PN8DFF*JŊH`4>550 g]]t]wkݺZ]u-K/닦i\zooh5DںlXXtK]sܬmYNDD^^^,6n-v,Р~}rtafgǒe!BQ^wudTggg ( l0%cZfȪ '(fضzYQV^IQhEQ5MK)!YKIIxzzjΝ]\\tOOOf͚ĉG*C?lv!BQ8$ ! <;8zSR.eM"qc@ YţJ?#xuSn _x[wM7hP?ˮ'Y1^v ˙S 1pSa3ǾlG!_`,( jpad=f.F 캑bI)#l?8bMx{V:Hf,7f>R82o4s#0!~0~ȘocA'>t:#W_#~bVFOXOdc!B BBb3pş503>[y_ FUPѸbFhE``#CCDYt !Mz5a63 zaxttb~˘hԔ]HҳS 3YvW3d}|O)OLj*Iٳ'a+#1x̎za3'q o`ܒ.r> +d*{ g#81 3fJT*q2_!@hooj}hִ ^MNb-\>+QO6IM*ߝJcToñ5?VfTu3ařEy{O1Pйs {2UWykm<0ZlKŻԭߜn3/4b(!>@i||Y&ZzVD0dqh¨%`N"1m'G3IwB!f{sX!(G'iANK*I9x)hg!:b>8GGqSOW2V>nvk #|QQ$Z@o2;R;!#`\YI(L =K7Nnaθ ]΂ǘ4+^Mdb6I1hɼn6c6(f4dJÜ8IL6lB!(8 BBܠgxGufv 'h {zkР@'u^Λ<>wiQR;{faw_5;P.G<<(܇{ƯŀgpGÉOr)Q/Iu i:`!.oN'jQ|Bn`U]߿I,;xµLg&[jV]X'okXbxq>-C:T$oXf¾uZK !p АuͣV k<1VՎs,gҴgD^ٓ,I{hL.>MOG>a ~Vy QS" ۠,#4f8V?.8*s/Iq=:a9vxy#0$$Gh 3 ̇AL܍WL!JfܦCJ͡k86Զ\ћ`tk|gj:MIFoܖe:=$9mx(NTʦ3?u*֜¯)5 .{׊|55%S3rX>` cٮg搱0-f6܈|/`(ObtFPt7]JŲ{kPs:%xBQ@uB<, HLL-GnbgqݶejA:V;z,G4$u>~=LpeLijMjJpWP7gЧZC{[hE42E~8&wx+A>>{D(;9Q0R%z= =WZB(kT bЧj-ld$B^IM[=^ȅ 9gIᷭ{p8N(4ԋ׳=݄B!Ex`,=ñi\pd&˶S0VFO5]'j*i5@)F2~'l?7vHԃ_1iWy[vnH:TwtLy >f˶-kBBY5ҋMc>`Дo &vo(3ڸd(Dz-N&t *Tt8xyQ<Wl $]|d*WlTg8T\>,VJ%.pmB!$!i3/ê3/--M?tŗvksdk@A~AQc1R~jۣHT Robպ\mluʹ6SέkוਨlԍvgtrhD!HŻԭߜn3/4b(!>bOҰi1g\TT>zR"Iq2f H9$;&#Nf7eB!x 1,1ExZԊk/Y8OJ3#՜7E &R;!#`\Ysբ3% S,I8928v9 {U㉚<.pGVAw濿br¤I4@/J71L3p2aNJW$&q6]!B":g.;v,kk-[62ep%tbg˜-p K{zݍ_4>9S_ݰY0o2T,ҽ-Zæ,&gڀ{D;{faw<cv w4¦ݞ^-1RzT5o/hX8_TLTM-|8*Q N sexc!B|(blCpnE'ڬX?bc{xiإ i?g|cz5bnX&UTk3wDRΤ \I<7R@<;ND}K^ߒ tB\/,rO5-}8{Z 6~̘߿&@dU kSm KQ/çeUTGj߂ XьAWqN+˔B!(c.?VZj/^m q~O<:kur66BYԋoY*G#ux@#zK0#Md'h3) 3Fjv)#wS:QQ*v=*qU@E+" IDAT4Ɋ-\V΁8igG1 -5ڎfj83ML3U9LFiB!(Pj[l۹sM;ծ>zXju*Urplx(n<\V+3xo `Ow%s|{>\>2՟1x4g挵9%=*`۲(_b/ٖ3(4lԚ׳ ><(4kN1g;&\PeǙ˹:///\]]?RRRVŲﻣ( ))܅B!&WWWnDDؖm`R߶=%%5׳vvv?!B!(Lm9mժUK.U>ƹ)uޱ/B!BqI0.blO[?\ɭ_nL saEQ$ !B!8 EuK5lKw(]m Ȟ[܂B!Boݻwjժ*'NmCflK. xwDB!H0.bI2Rڿ&FGSB!ws'1|l]cZ^m!s#HňGB>5k(`e jUֶ*2zy~;[eb^g570 ~W4yHȼ̍WR- Θo+$Ng KwӥT, X=^%BaKN1æh3* .k9~āѮQF8}4 \,,{lLH!`^uyPO5[ˏ) 5kL@63I^!/iJ@`ھ /f6P\ҶZqPqݎ x) G[g=*aolݑDK=b@uKa3,)u.ҩޛfzQzG4!B"a҉6ϯel7Otz?l5c?_%+¾puZCNϚW4 g_n7~N3Qщ;s"h;YԺ3~R2[G.WnmgB o䅽ꤋ,C X2p69P 5x@sU?Y!^  ]~7mA}vݪ:c֑߬gT*# MEVMK'3Rf=)$8f70j$HLhqr4s-I>3BQp}0i? Y44BRbmwq7-{׽Lrg+Giel?EAE@oSrp,iejHtHXӊݙyLKAs@bZ\ }k3ɪ r}"HpِbyA19aR$u }ell0Qhɔ9) pH_A7l$6BQp}0:x@Uf[ʷ{W{~O<%#U~&+NgѲfx;5B6X`naˮ$>H>͛d-Cm[t֏\ض !BQ8qc@k˹ @_c购UfQoHY:ڶ痂[鍏jۖ~WM2ܣkWz)-e[~Bt2+OP|0! x'2{8qv^ tn}p>I2Rڿ&FB!DD=R}ǶjK/}? %cZfd*}rF˧5711yѕZ:1Vl^ה<'1t:#W _.b=5FO(9l,B`\7x9sƶ/׮]iɝoeţJ涕ԍ/Zl絕ۉ `IC-Gb ,Ïx,v)53#* O̖YD(u :GLc𧇹7qm=qoZ:Lel TR}JI?k$ؗ٠L] yv{ɾ@@dRwֲK`e$غ#zR~|f}*8d}pe\:~AF4ԋ׳==% !8l"&?SQR *} Wa)tx ~;$p/,f$9']e'=Kcg%*$Zm:WLUi뾠F?DpDףfˇ3ROue|pt6R }7˥LOxqt~^DmO܋z2 GI2U~*{oΦ379kФ|YfŭJ\ H0B!+QQQNH`0`P!rcEQP P ˙?Ccz2̚cF ELnv(uJlf7˙ cb0634}ިj,MqUZueLq!_TF8b$rl]؏/⛅sxq$1:R9Gtl^Qձ`ͳՇA#EӁAshΔЃL$q,I1h~MuD1 kɔ9) VIL6lB!(8 EL~&͂5AWJJJ%{ikq-2׃eePqAuGW9{cʲ(oC`9M1͉xlOZæ,&gڀ©Gn,7n*s DWޏj»v{zXDH^ޗ S'_%َOwʣNX~ 5P=gL9 B!(8FQ5ww{888pG=X,?҉3{vk=_||Еۉ2_$YժxcBϹNkTCI%wDRΤ \I<7R@-܊űlMצ^ȶۓ$c׉$逅_X:UZvmJca9a ڵLg&[jg_Gj߂ XьAWqN+˔B!(rƸyB磲Šv?V d,NR}G- x3m"+Aq0\*WEemk$]+v(~=v~DopikIf|/)nrOm4sŝb "UQӘ/vL5^ȏ3$d.h;pĹNK?<3$>̄8^ucn\,BB XHP1Jۃ}ˆ|o-߳<~P? 7nbh%kUpY{%OCUvxgܶ'\%m9cE:OXF |w]ȣ/ uzOcUo!B`,B!EPLL ;odXQ횬+[6$&99Fc+Ѷ%!B!}"k&:z()GhB!A`\DJrrCu}l~GB!Bqb=T _n9B!B!7 E*U"!!!c9/9o5LږB!⾐`\ Wn[B!BAԪ_RH0Bo%tv<ȡ SitacΗ*#F37  S燌<tC3rJ9'FmeD<ؿB!xLI0B.BVm a˖YՂvu>vX-A!4iH@|zVhJ9_y@ x.SI~fڙ&ho-?NBmJ9'fMF-hݬ [u:b4˟Rn!́q[ݞ'Kb2[5#g__$@'n`'!I t9{ӫLv̀k:kZjle+rIʏ=ZRP6Y6,u}[׬\a5$Dy?Sg;IS: W=iw[H%IE?/=%=WM7+KUH}d͝4 TQ%pa*};?MJ7z} -L 8Xc;|U;L&6UK x>&J2E?L9CT$ IDAT<-X[Z=u߹Њwwk1ڱ5=F :4t]:~D7]ϪٻZj1q12`|Bm)';MҽO_=  >_]g:N]3uC+5!vړ*>6]dU|]'Fj?sF K(+px全=Sc A'߯nӝ'.^US[kOӨ!{3*<6uz7C1jhQWt G)7 Kgd>gަKOy RqӞ?&'k閞>c+_kԈ@YnrssQoM}$Iަ~m#gԇG6}Q[O7FQo)S]1?Teff*( ʲ,r@tݲ6]R- r"UՇܢOd)$hH>>  Zd D q1:dA8x&^/TD> s$E^{F^4UkÒWhg4tjI2iС4w:K9k+cT(кƝ}^}^F^ Q#PStt5+/P;P7xNM~`«jQiY|S1}e;cTj̠>Pkڍ K v=A7NnW@0GBo[4g젬t@p5SKlT(#W{c>?zE&Azw5N,TINPƟ:S/P ͖%Ivc>r>v*b3'0\#n'!:Kyh Q.en1x\YMb͸b(҂-韯`J+ncoh\']o߬.N~@ǴN02;6kVO55uNat:kti}s?J)}uLM{1}HFF[%6[(,cjmoGTQ@tY&jZfje~d]]m'?:ЙOu5Ojgjsӵݦ[N_Ңyꑣ^nӕѢF]~ʥZ aK?[5ٱ&,Y]iss,:|q/ЫPJ 5*CJIIQ P eY uò,AY]/ou!ryu` >ԴiSeffƅag ޠ촻ò3NRv=FM7.1kcF0kcF0kcF0kcm@M51=ufhʦ|L| UVTֿf/ף >1v˪-Ez5c cѯwh5ZMmwhfhPJ 51_#|oaLvأzU/&U kmB0FLv kh=k* {G@G0FN 6;렁jԦ"R1Ɖ`,_m-ai֐ q#s׷?{wbYRPmT`P%F\ UC0nd$cq#C.!72JƍLM7~۴[&~ U/Ծλ&ȟ5Ϛq#SٚgMjY}@m 72@kb5 F&\ &Y@0ndL-fkb5 F6.rU}@m 72?kb5 F6*5Ϛq#S&Y@0ndj2[}@m 72qgMjCV͛* )GT}6\}~to:wQ}@]J`Y}vC>6Nz@#72qgn=ԩ[Z}vCQ)0ڨ~>*ұkuJ@A0ndj:=۴K56C`jƍLd UB0ndP5FSjƍ `1T a*5T !@Mӄý-[ƍWW*` 51_#|` 51_#|` 51_#|` 51_#|` 51R +!S42I iwxtP4 4Wo|:)r yڥڜ>zP1gin}?.᩺K!,=g,W%){4otu[{k*qfe:t_뮇?U$)Ms_Oh!' Nn6[GӳB }w~>*q^ O/BIO陧.ױ WA?N!jQw!Iuc5b0 =oHRfm|uM9gF#%.v[YڷCۿTmIP0T0TrK?Z.xS38w翡% '}PNAkIW뿋y;tFjАaz$]*n /&CsТR)5]yJ;qs}̹ʙz.}Wd-:ukr'z+tXdWGTv}tNbM}tMgI_eWv>GO^KuG[egbzmi͘5K6@?uauiR'<M^l`U}zy]Fjͥiqh$.o蜧~m߯T{ ]}:L75 A0NBMrr}/svT%m~ f(tDwVr>eZHm҈>Au{ƴK?5YBkRiz}uC"G|J%IrFn7FsVi&O'.MHMU!I1xPȈ tf`4 f=gtTUo5EJmC{th~i>ŷѶ 3ramڰQV<RyܼAC[asHrewQldGZDvl "yl_(duڰsn9rD%E /rڴr}R U6RBV+zuϛZtYʟnנ I&NoFͷ( pa%9 ]zV$Mlٵ/@0N6zy|zҦ4kֆI2ںffڐԆdR@ah6*\PWV5Z-_ݮqM3sw/{3Ulq:kWj-tC}cSvmP(,YL:Bݲ U%c/O^>"]~E3zh@T$aJiȥݿgP,5QW#X+Љz~G;’BھjŕBkEn4Lͼ}nNEhڤ/>o3Zcz+E+5=z)8`|q=+y{LWv^:p5V,{1(ܴ'SGgwOsM|KMtVO Y=bMQnD )iGWGꊧF אg5vخ¦CuڡyLp7U{~WyήJ}@+^7}AC[= c$R}u$:enF0FKQK^x#ReSgx[JJ 51_#|` 51_#|-ZYmN4o BkcF0kcF0kcF0kcF0kcxx mJjVyQ1cpWCFsWzOviJ ZM@mb#!e椳,T!mZA0iGۜt6'}U@A0ʚXj,2$igȨ`gXkTX4h  ,[V6 z$RfAmԚm!\P*C>˒jt{m!7Mi͂jji19HHeT2ZDKi{}KT2Jk?w%bIqS *uAQXK6ٷj,)9%'ҖJB(Cb@"c2쏉vf=ܒ*ar:@"|`]ݒ)QXg[HVcRN[y_H˹薳-$+1vɹVfAe#hg[HVN9R ZT2Ez[J`'`~.(UTKY&Uk|Xj,KA{H1 %ꚕv\9ǫKA b  3F9Tk3  U!  K3M@PUoMeK6@H=;gwNQZemɟPmVIvLWZЎyP|PƖ-[CT6lؠm۷+(`Y{ٻY,K@@,"#kvg]R\w,I@@;t1Pvv233  ^K`\^P({ñ0kcF0kc}󵳨Ⱦ'eɊܛzdٲ,)rb˻o._qy.vm^^˘` >Ժukeff* F  s;yba⃱{ծm[RJqqVF0kcF0kcx_8R8IF,K%˒,(udLXlYVt[e9뒳qcc#; K22&hdn/s{c9u~ c!rB12 Ge9Ö XaI*L@XJI:dI,;<;z(A02bp2dL@aYR8 RВ–L ,˒ [2`h؞-Yec1` >d;&p Hdd"m DB$+ HdD%; SXomdي6ZeHudktB0ߪ[q}eꆍ` ~ViNؽaWÑYb݂)vC0T\kɘP[:U3˭"ILocv^Ucߘ}~H=ӇW ֟/~V룟ǰ6yι)i iN86XNΈ*I\+~c5מoj-B,k+?ַ\%˧dc[oӧp}}'csTfK>=NԸ4F9M=PX?OO=Vl(PQzL?jfI͸&MB%ϑGW첧4k@*YOޢW?X- =S}:dyy-XMwμt)}ɉCԧpB-=_ѐA{?V#ťjiji) q8m^}2,i?y^t.|CPՊ?<}n X{Ϸ*1ٿC֔?ԽO[O6|*Šܮ)ϻslSS ~쭽y UZ4_|;)uZl i_`aoұ钥,et=ZoMa{͝Sw6 Hy˙P>`N:M=[dw׈S3"ByO^WK6*F*}V eUb\5ԾWѳs|AeјYaQ͟J+Ӓd}u;vj›ekڷ}歕Y m}wx}$pLUdOo=o9^/4C8Y;0Hǫt}*cm}V]NAIj9/:+Wo}>s7U:_ϟyJ%)Ͷ ?$9c5 IDATmQy`sueꔾNZvS>G]UަnIYݭ9UɄ%+h/KT7|,՗lQ{E"m@mU/jaګl֎fԭc3Y `4}\:eo8(yv)\eo%J!35'hCBV_6ʘmZx Ò=JTZeW?ϸP1+Z[Gmt=H6{BΑOG?nc眤͚(gc4/T Ijxq gS "{LSS/\8VklY}NV钣Uݠ?Y;JkU}Z 4(ƹa}OO0_to>nS_vi|tj^: VZzd=8c8|o+zWQ*c%'ZWW8u*5+SBndvtT|EBScsײ.ɾe߸bOۮc=o]s[R4+pT ϑ튅c;:a؎eENXSlL$9mW֢E%I{ڵk('#NjccgsbܐQe[ƛoƵ9aUj"@23M&vW]׽Zէcccͨ]6`-RJ l[&Ko-[]VJpc_]vvY,+ \:Q%7tVZ-Iguu>{-IZjn&HƍdײَFh'rDv'իWG+콷^xY?i4I/ZzճgܳF9bD:eE¯"lE Y)vpch֭9`II'n%P\-ShGi$I 'BnW:a;M:nҸBqwc)SW7P=#vի5Kt) q57PIR8c?@]jV{^tSQ,Im[q.xؚF0s/,Iоnf5cR]%妛Ծ};I/wdun+Œd"a:\AuzW  = ]MzFԌ7zK=$)33S7\w$/= Nb7RHlnIUiJc[x3G4|0 63fs}o%ſg%KC!-,W '#cϮ0 :">J Ǟ{S;1mʔ3>]D.d{d^ >IR4|0Oo;w> IAÇc?= @Nv*&e2dTcoEGڼɂ`S\k֬$ 2DVٿ wޕ$YK`|r0Pδggu!Rv&cO5wWR W_]եs߸zּ˝] @UEWC_d*{ڵy$@08@-Z޺khB쿿@퉿Ҵ n6ESGפn}&˲S> *>LM0`0 $-G7ψڷ%#R0P["15^RXe =۰ߕ>V`c]~]=uɧ.=.DoMte* ."өM8;B'rо$^Ԋ+<#jϊ+ /J:oC>3@NvvqIN؍L.o OZ9 tKJJJt;=#jST4 [v n]3ؒ͹]Α&h޽%IӦO\[xIM$i=Є=#Ժ'Z`Gd` Ց}%ە >tM7*==]tSɧzF՜O>4ZNOOM7ޠ@!|\9\,-r_ {n$B!]0yy]Ϩ{wt |g=I ]F#9ث1$I$iǎKu}Op1{uΝ;%Igg?pHu~tٸNyyO=ZvSCgƈ䢋t%G6?Úxq<#ɧj顇dO륗蒋.P߼Y5.I ^vEss,˾bH6:LK^vo߮EO>K1GOѣբw89s^y5h{ff~F Yط)ڕ,Kv IJu*'c31=j^}eM.M>]4/5/ ճgOi\IҺunz-]T_}uM;aؑײyMqS5oUi͚uj4CYY.$`"mݶMey(s$z{uAy.$`ڵZR٫zl$9Kbݖ\}@sͩicI#,ȿUrK}w>ʼU7` hP81\78΍;&m?G,c$1 4f-|몾Da"cPaC ÄRD 1Ir,6;˘V>*HJl$*8WG/yyDǹQ4+oyKv7Z^9:}ZE[ ղdO$)$)ocE7 @L(Z"G\}>՗8ל>{#ؔՂ[슱@]ﻪ/qDJ]M D͛6iڹs$;$7}Ǝth9hjQjN'LKWzׯU(Zwm B:vWN7T$6Hƒg~v5n$˸.,}eT3znslT}*H"ez3LWz`ҩZrΧ{lZ\rmPJj# Q3k׬G$I9bdqDE﷢ږV84s쳧*?Vk׮ѢiQޮ#ZѰb*)K`nz5Ik<~u1:Qzxfl#[W|G豫ZSs6oCqvV&бc]=hMoy"'+-[m"|75/O-9ދsqַ_EMO^XVg)>-tZNeIFN0C,9s oTuQcmiO<=Kc.Zf>#1RQdḢl$5Bvi͊QPFGgeRɣU{N}̙35rԨ ڵkQdLeI (%:칿OlT>QI -YB KS:g++^k4IūE<`60kVjuOݠ붪8ڳw[5ݍte/G"cyeYzROsۺ?*=o_?Vֻ |y&{0pvY>OKJo@J_?W=bM6HK~۬"6ebh_ vV(VYZh.5XeQj^m-[e)_k{yGi(ޠvWv!X\ eR>{S ;d˒ZS!+U;gώ_/~ j{('#^liA{*t~qV 6QN)@VDZyvf(V0;8Ne[_OR-?g鋴z@HuK3yP>zܫJ;mLKꙐG+]ޫWݯ-+ g#6# ĆeS8|v0]&ZK,>0 v]YDb[)ǣw#VS@y5,w$oo/wu.TU lmƴ1m4`Fvu!5D onnā--pLʼnߟcYXuEYvu~kOjR5|Ŷm[ ?3pǠsg'::N@C8k^Dzw=l!&i[/j: IDATcAbwPa2gS3z(Ygc&3v2[W7{1eثZbڿoiH9nŠW0kmKxMh>dr~mļ9㐔]h}xmegODc?4sdu Pte˰v6-lDwV5:3*bbHH! jXA X#%!{:T] HXz=x}o5y5nbl!K# Ξ;x߾m'8c2b=mXdb"47@eB -Z?ec9FB Qp$`&l38ʡ3qnii}N ٱ5n!#%[ёÛ@U{J-Њ wVbN۱eg &ڍZisjL0@k{!+]d'Sf'|.f.H{k)|y?vM] ̶m[_=1֭[۷GCCCXM[<(~8][p&-T5M6thv r]Nx`W`V҇j~ŤZ`6ثƁPԬ߄) :L\@8U76R"Ն֮zHBޓw%s0&8xu+7n Zѵ:k1q:&L7wobt(4@#ݛT93j?c0~q3=iu*لJܹ >`ũô7?o>iFDD ?ãu?bhnw 8vb1hSlS2ごD!B@XCI2! X8*cMÏ 4L"'Y/^Qut!ނՍد1mkA{oĶnԶÑ@ s?yyGu?]#:*q'moӍH<j6iASUFꃯWVNGfgںk?<Ǖu\ uQ9{H'~HϪ^c9r+s<(R$Mʎ:hη; ydЛ<);3*8߽j3Ǖ5ۋ>71#DI!inAhkD}{+Zi Iy% ­k%JБ|,,6`LDd9\_Z,OýW™}ݢs "r+W --hb\hx"oW/22̠7XyjnSeo84PӦi~Ivu; SQ-2!/Q\TCOVlڎ1E"梱ulfPHI$øs|Ioq8n,jw^;wbT7tJWpo`Xf Yb1?6l?~POD @7 C_wUf85SO&\ӊ' !bH]r]_ J$z敽=E"ނ5W%c#砩~+2RӢL>K %)%[Z}Z M&g =H Pɼ":0SKg,7eۄwաQ=(KGb'O.oV ?<>2?D^e),^8<\7@Cz=عqwT9> @r'6mhG/!3;af uP.ӪN.wAv]wf_݈DquA݂ve'q2ZH UOipn:L6 [6,]9f⨃'"<WbߖbaiؔV̟[рIbtU-=ǔ9QJ9iƹ k Db^~c=&̛q}Ě[=$P=~<`LW{ ^ `XY b8ЂdS \`|<c0yl5oϮ@Ī&Qd ~MJB= a`xddKd2cTI$Jn0@Co~woL fu sgph/&g}v.C8ٸ0㛿| $+͑5e xT3vg8ދ3:.zO+g iCXJ d/1*\j;tN6н/ݥU>$|;߳[1*i4> G4==g& sf;S}FBc""=I{j  *8q у?σWqΰc*5& :`!}jDpgk;wVuABC:%|)HJMDDDDD'3o/6̂ʼӽM iZ nӬĈcnIC\8K>D8^9)1q:#Sʟ!?eڦf b2Xx+uRV1n(L7*ghP7L=28λ TZ FٷX6"'XwF̗HiVy Dɓ'c͚59e&= {Zo0 B9q2&TBYcȟ+g9Cg2X"֛뎃K!dqER jW .AJB:ᔱW1nh{y*2""""P7HyTS$|/% ::WQ{ /cݐ85sf͜aW1AoO7`@{{H&<)wSZ[7Ů2.ß)<4&ms z*by괾 /̼TjL 5TW1햚Əǖv촫 DՈNj8N<{,XWaWQjk1}%Ǚ?σS3yh;CGTpNnA>ZӯïnA>ΞozW87 ө+vKuuuB,O,ycbA(gRɹ쫜hOa ju );`WI#dXn<: HٻP#u1D  yU`s[՛;Ku.CӵO&"""""SUxA|i5Cl2n8bCЫTk?฀:JN̮tz͒͟Am@\Q]Gv-NFevR`WrTu~ 7 .e}8z$fc"""""=bK8+,ê`AcɫC6MU/T7RY:o0t:FԠNm͡#?}A0Vpb0&"""""ڣi&f 7|A {+h8xWj"""""=P8 @>a) q,epida PeRrPA!Ha-!U`Lׇa֭qaiǭDDDDD;iUHPXW t>f[?pc*xW£>_z t:>H`y8Sp?GvFN6o0+P77 KAs/hQX2ĵW_j_ ,^crшɾݧK y*`y%}i 8Z]uX'Ґ*!0qxu\<+{c/~jQڗEkx}sꇈTy7X@L:YgLYf] 䠩"=K2#H4^<㟄Kr@_8\yeȏޜFjV(&0Ldfsj2ڜ@k<5AYУOJHi[I1.DO‹/39cϛ_z xcfDDDDV&Uk.ʐL&{%uL-[ƳB(UWrsNX]5k,!V6 *eNƗR#Ou:U+M5"X$+닎=֨c.ċ/@`LDDDիWah02ljmźk1mިCLڊ7ּۿ8jn85 _}A f~ TM1jf}fDDDDhi>s2]%gwP<---*=&iKe ,qWPvIO}z H?:c`x$O+2c 3|9'[#uc,kTž28-ZJVlS)V'>~`ְc!İb^zGvf`>̾vChѱXW)s-1, *Ūuri!AfL'S1 =z +o)+10&"""=޹ |QU21T! Nw**o+XN[uOj'=}aJm])6c}gKJ?Vkm=AC`O_ )%~w7c$> 3D0U ug #] 6r,ژM**sWDEq[k+aBK X ;@pˎ.$-RW'I KꯀRZM@EON9טQn;)\c{J?P7Wodp[zaFR9gEm H<Wfn`ϊh0/Q\eۏ0BTT{G?;]}һnşVuuu~ᄏ#j""""؟D l&gvW"j]d#Wx}7ZeӵA_ae3Jx0.GYRnUK/VY-jċ/@}]]k$"""=),G9睇c/Ʊã>ޛhYA-!o` TI7U76El?9IՙWHh0.V].3pwoD"|Wt393]]]X|ԏ~, ЉD7}F8-$?K_?wEbxlٲx'qyⱟp޹W?Ŗ-[v ~3e5VZlN&~e $' G8 nb`{~b ͷ B׏aqA>K.-[yx)j1.^ٿѳvzWr IDATwJW__+p9g㉧³>ի@֭qᨣI'"""ݕϝ1fLnwັ =|qܤ*LMr 8GqƼ31%>y\s=zj!W-r=8`|q%caqO|?x?N9c\~ۯp7}?6ky U/=-|W`]*\SI~^ ]I8+qi31z7w݂b܌38ƻSk:]4p.Exxcy׊[J`xaDe@12#8Z::A[UjZ:x^!:FBvWOT;>.8|=ҡӃK/5771-^y+%smnj /坟Ĕ.6ڷ_.ǽ_< x͚5obY dzfěonGxXsQ;W|-hsc_q]xbf5vx˷Ʌwi+pk} z5Dsl'o9߿ _}&a'%Y5F6g%GqԶZNssƹ@Ы\u6f P{KDDDDs5r[k^:#scǡ>o@܁NbvaKxxǞͬ,ƼMx{d᷿߅睋#&TMcH/=l8N AƟto|e|=3>}>zz<>ii>'beGeǁB8p\ӳl( aV( !1=+`ҿ~c&Tq6ykދOC_wg}݃]r 76߸ylclߊV;bu$ } ?`'n8, /{W&"wNNJ+p1aټyÕK_c>}"} T[ՓKz?|u-vv@}c)%>χlCzLotsta_0iw"CPd$2BEXG`Wێ:EBut GqP֧U2PDpc! ,q~yilp^駟ixulߎK/Kbuގ͛7㦦&ol{OGcz'"""ݍd|G? G|[nM܌f|:n;'kǡc@+~gCjS:7m*[&k׾U3>\|pMvㅔ?pGY7_]5\ݵ?'d/50S<8tꇗ.M7~s]罞1!g,j;=oLI;WO܁Λw**qUlUفm!TP}"5vnYe gDž븈z0uQ_@=f$n<8 e_Pۮ_{e+Q i r󘈈hc~98Ԍo\w-\kWjq&>g_~~3Hx/j|g/>csxdMXwhkuI'n~]˿ETUpR`!|q+qV˰v;<ֻgٽ/|/~/*,q|nbE2dkWǎFuTX cctqsbu.\A,e1bqb1G<;[x,x,XX,qGUB6m{ئgmB<#8J\ٵkĶmИ1c4y>^yU꫸ǹg3?ITWW#"""ͤSN9SL! qv#pwCg0o[8oK?}0gE>( \sU>30sL+p5W_T՘ݖ.n@SiOyj/SQK}t:HHHYy-|[O.朅nfu)nnvݧpWk8L_tb 6bWbvܢJ|W^ v0.ԾЗnLJ- *0p O^91t]nUҧ48p`®FӨps*$dzFZ}ͻ5g+P5E #0`UvU\'eNE~}tCZX*Ӧaiя gp]wo/ @]|%xpU_1&~#'O:ٮ5 \ cpAfG B!؍e!m#$K!ՠ k0 cVBeRl8Co.úuòy/ d\ŢcŢc /o/o'z xv-9c'hKPz%r_GύjVXS7 nLgs -Xu)̲ys-!TWX]5-H)?hooຮb/*5e"Af8sP.pexm =/4y^n=>\ZjMDDD4zH/4^  I$I$UH$H&SH&HTS1B<@"@<`+n²dgXqdwwt]w@?n *do?O?|[k'kƅ@f9. ᇱ^S=|]jMDDD4JH/4 c I1H"O"O PXDk뺱tiЧ@ީZ ].Dv 6UUUצMpƖ-T(~0wVˡ7wxpeK;9|lڴjIDDD4:DD=.XӨcbHW:J+]a}좶O|*, ݋S+ӦM/}Y?ZvҿZQ1C|\(a8u]BAбK\e!#H H vr:g]Geꏶ͛n_~eo~. o΍hmm5Z,)s#,4 Ae<;`ܹ7zՂkժU"",BֈǥuS+jkkQJ*Bk0q߲ueYzX9 efoJRrٲeeeac!0.Q}Rfls鏃< +W8x|v\OO:ßl|.0qpЁDDDT?o$55:u ]cYXr%V~î2bKf:dr]tYo !~}h)-0|a`|5ȫ ˗/͛nQM#CDDDDDa@gg]Ee%gǎ9gsqt;U|8455ٳgk&r62FTT-sO""""W[[Aq,=Ylk ؆r8/ЫfrEDDDDD^cg0;SrPh3 a ƥ_\@sߘl*gDDDDDDf*vi;lfomLQe 9s:wuBNU *7)f/&"""""3BaPo]goےo"6akMBd7BZ[ef*w3}wjvۇXDDDDDDTMHG>lj dlgi;dk.Ӓ$Z7, Ħ*LhiAooox+n3 z[]vYG """""r4pXa6u]k.@u]fWڰc X'I$ɜkd,.z4} ꧐a~Qhom..'"""""\6.lfo6l8 [0_H`ڃ\ΣG* ׉|cƌ |foBUڐJ-D&9Q}bC􉈈 Q |mعVR5Y Q<$z9>+2 M6ׁk22 {lnZ(QQeDDDDDTyQ- /7L:s,ro`̼yno3njX,VfO+.36&DnP(en8٬eQwa(<G)az\l`YQ붨2"""""U f~]n.v5}BǨ~̺>aXa׬T3o]feu]x>o8Rbݯ~N놯Iw d޶5s,#""""#s]fB@2yG[pp(OT?v]2ݶޮa &!rC. 1zs]?py!.FY.es6۶RDDDDDT]on۹Ůr;uv;\M쫐!B.](/ f[zfz{).Ӌv&ݾbJQe fvـXL?`Uf_3uv{1nbE3 i0BiN!W3_6]͐uA yYnܶL#"""")7kU'Dnv}23LT}Ԣe*no2iC "?,`HYxlc^32)OfYԺ~M&sFBr;u,ZCpP-5̮3S;C J@3E/NeJAf- -u,Fb,uv*vv-؁P\2mE58[y( I0.D )ZЫC9{lW=lMmu]~]^h%"""""m mGu棽n dg bQezҏfUˋm&ƎH$L& ?Cl<=0f z_AAܷPGߵȝ-hݦ6QeDDDDD4|lfvQf[{[]R,t_#5{_ضɮ+mBHXlЁi!rìN\sPTo~Ŝ)6fm :c]nXs6vDDDDD4>:MTYf."wFY35s]o}廓c}=8} @B kzpt9XvYԶ[^; l!9; r9k*ac**#""""9> (\D VͲmh}dtTh)UVHږ#~dIẮhvp0.@u6 6]0#'0K{is]^c7mDDDDD4Zrdd2s)UUWhF8mTfoeQuUq"x\jvqӃD"!Jt%S;TӬ+nc 4j]o"mQP15{_Qؽ~xTvsۮu{.2Ξ%sP\j]Ӭ/f !Pw=== sj__պ~r eQe&hlAX??iW(u٧fmYg2'""""3I)v{]@!""""|rǮ.Vf>Fr; BVh?f7D?Epqooxf_.7eoŔ'""""T.7z6X5K mk}(QuQeXq8RJudFRVYqd&Oԋæ,7ۚ2>ΜE6ۙ庭}|sP_$en6ǨcU#"""" ookܬ/]nfYԺ:]n2/Wm}ߗLF+=ϳK`|5ȫ ˗/͛E*TJX,&ǑdRqy/DL @_|!Rd+Pz^PzcTdV{VFV~]ookf16guhuv6ˣ֣}u]߼K/ǎ XleSS={k X,~rOO ]\ cсXe@qL~o_$ș6},s_mlo2%""""ѯf;nFŮ7 ՛uQvnUoEbuy{WUULXp +ƺYN;-|555C2K9 ,Pf[]fفդm ި,ڣ}h9> /u.7 UVn}T|,$ܲ"2zq[+hooy%%IH$t:-Nx<3IY(3HڡSB;lշnv:>]}܀krP8vYFDDDDDB άۚ.~6z4/9|]?T2L_<x@& ?555ޭBX91{l|ryg꾾>}g̘1~OO~8 Bb}ǩIDAT2mYn>6v_&jfty1QQ޶zomQǨ6f.G8NOJUUUy]]]8^"{}1[\0d !&\&l޼}ߓR qur"?Fըr Vnn}}c}D]VQ鏈J+TNRmBQ3hMuRm2P]_L7=CeW9{첂SW]uܹS477;N2tu/!bcTI)R88y8R︮+97K=Ắ]DDDDDD4 BU!2qq_JI)=!D@O&R4 LooW__ﷵr~kR4 ӧO7ovNuNd,K\uP ł]>Z;*Q! #Ias[?W!t}ܰa$vW7I)]q/מDDDDDD9+;HaSuFm ᬺcu'Q}{Ե#""""k!Ou^uFTVQۨʶ"""""JʶmTuQWZUWU%&;?HuGDDDDD '~mk**ۺW UQ[#"""""%j+%s;Mt^"l[Jʶx71+"""""۟dc"s͉7*V*{*->bAEDDDDD"^xDUvݮZl Wۯ6X!XeTDDDDDnPkAcAu=l_mŖ dlcm[]X&"""""K&&3ڦꉨ̶٦ʶT KvomLݯ$XcD版ȶ!0k^1\$_'풝_e["%{·m lX~c~5?~Ap=dIv~v(K۸55; UU.h~uqknk$M+6VUZwNx< z3sKMϯ ^NU'۷cv"""""R9 o9mXxjz~j+P%z;3m;/֘o̭}#."""""ۇ> {̝k%ۏ'Ϋf?Pq~;f Զd$;*T^e[۸A85/^?d'37)5sZ<'m 4T7RmEDDDDj,޶AAu#(mAsڶ9~j~MJMD<87V0um뷝xاrFP]DDDDD-Aaϭv=S.hܴum$:7yI0+;/m&]L^m#hܝT} <ױoyIɐȾPwU Zo DDDDDdˉ~5~5;^9A5oId^"sV!+}Vv_u@y[~u7mQmDDDDDU&MwXwצnHdRR!+}&2* 8nLYǫm[uՓQUG GU~X9D~kߘ;Id^"sV!)}VfNi߶vݟ;݇[m#hܝQmEDDDD$qU hAҝlvo_]mݚ_OuIXuDDvo]q|6}5w-h,DDDDD kAcAu~Xm~5}yV][w׆]vꚓTp<_3Vwwm۷WVuGDDDDd{/%;x//Σ$|L\3s͘6PRos׆*$zoɎ[5$9F}[m[P=Hrۈl*&h]7dA'r1}w[5 k Ws:DB;=fjfwF"5OEDDDDj h|k~հ"Vcu"m{m#K9ƒR݁*bAݺHݶp1w[Swk~kfݵ6Z+޸Txݚ;7f_I@췍X6Am?c%T$;Db6`w~X 8l~jAb+W<7=Ϯmvlnׂv^n=hu*o?~5[nkbam7ptI9f̱o݇{~cv6w[o~+""""=I&uC+hܝYCY*rẖajv߽]w[7}[w߸_-)[Jr"aψ2j1(yuĞkpvhyx~Wfdf ͣEDDDDDyYW^_}6y̆5kV2%P]LPf?=onHq d?pïfc fb+ iVaJN4lwvM]0w eaߜXWv_5fK]I6׷=n^wWM863f'DDDDDDꎦY݁l`9%)oƪ&k*=N`8ZU!=0.x5wf̴P/ )Bͽ-wDDDDDD-0P`lnA9ݱdjJJH|e^L5mvNmڦn1sͼ0?'B*+grw[Js%3b+&eS75{ N?Tn*䪰wMu=~,(;!YVtvTD(*kټyCꥹ~.PΝ]ؾYӂL{f͝W`b$ڶðpnLroĮ}c|[Q! _Xcvۼafܴyݣnδ`f&I4PVZ;59WоDDDDDDu\ptlhc+zw?,ѧgrՁ”d,ZlejmkDud'o_ ]3'oNn@.x^b),̒ŋH{>`0xƮ⇥,a!ѥl#ݗHUulߎ_LzFP۷FrӂK~Aٌ1vL06훚+Dź_-dT!9}n;o 7'\X{ہ[3{ᅵVD AJ+,+׹vPq_6t05Q[&Fy\s,]xEd%/IvCM(Z3ˮfs۹S!pb,f f1iA3~ѶbZ4뱒#P+lP@!dĚ?#4 d :4${," 8c׫;pkn+WSDDDB!.<Ҁ_)(,Ss/ ^=qg1ֻrIgbcXcMog8K2st^da훶[bǙ ˁ X\-/E.4.ܓ'k`frow*6t0'li- ""R;?{ֶcaZ2ZjqG7KG|*ܕ SұÞ|Uă<=֩I=H;uٻcC|XfΚc*1snc,K퇈~vSog(.ݷn۝cոںܺ۷̠WM\Xv_AQmA2A֯m3c\w5frI@Wx{xx^茒#b"^ױ"oyK6ҠAveW7ׅX`>{J%ѧc[ƿ6[ZC.D]i#;+O!//+WrOxRv۵ w|_LƗ|KaQ4KG^zcp 8?x ,G`R ث};>S<<;~7u"7/ޚ.q7ng<W1}xP]!9u]گmpjv6&DJrCBOsbLxаes?H}:q%pÙ3AۋHs2+NU]\dž KKHמp #[sʶD׌őb_M=vk8a<|3}'9C[bu۞s~A|W\w]U:&""͜== ѷlQPXȭcV홳p)(,Y3oAlH ~e̙7?LV2?@ljf0, _*n+ѐ\A75wc& 5! E{ \ţTqO'uEun; ? .+&-|koMd=qc(}~WXa/_2f@t`q&voۆ99_~އiF-7<8}ԯ_M9{/:%PfΚ[,iW1 Csw"OMr4^ڟ;o?kW/~4'E&BY8v?`=fw6U1%=8Ay`mܚ J2m4x 3k_Kk 6wWfΚ* lq^y>qcw%Wr839<>n sr=wc{z׸s+MͲ26Cx9ìr5IYU5i欹̝N{޴z*`c{3+H>hOKN1\6=*Ov۳vʹ͘}XW-KyAA ZjWW;1];K'C wJ6Vi1zHkٞ)6 J)^ģ©!=MI}کs7rbZ~=W)7^: XIIHjGu#N;T7 v@v쾻؁ڮWCee7(vfƒ?+./Jlhj3X#bhKOۿH%-YW$׭[-w˒%K!LX(쎛cM25~-&CmAuoܜۋne}@}ދom@8%MHoܤւ6%s֔k||]zݝ ?Qswp9s~ϸGl QCM`dl$h<^e5]u۱s~+%JߚajpY8j_2ؾDDDDDDe7Gvt@fY2|4~5'ыw&7EѶ<^hXmqrv05nh:/ggL+WKFQQ! Y2BbhU+RDDDDDCgT dyv-h_X ׊cs~p'o gmڥ{[VnADDDDD2ɼ^̅LtmmsA vͫ Oqd1~j]OM"o 4nj~cFvH=~;챺ԅc """""RaS6~=eoQU o_ ;=~{rW@욈H&K}wZv?hW!w^Atk~kv Oe0e#r:^-~TபwCÜ\3Ǭ@x3DDDDDD_M_19*-) GtL=Ӭݱ:&$\A׆]Oi]vBs,_+j2${~8m}sݾ_(5y DDDDDD&䧠1ӷ}wNm7^iu9 =hDmwREDDDDDb2ɮv96Z%B}0ڶXuw{7wH0?+ќe}["vnw2ھ """"""skw1:n {5Cr"{ ݵ-mw y.w]굦B@cv]5ٽ _^2X\íoN_#j+$q`kGR IDAT|V2Yk͖ ɉ;8 +![1 Ġs\6{˯VԵ0$XkNd`g!/O3kWmR hCٿE+sOj23v~Z?Nw?FO&☶ ҦG4nB6,2Rܠ9h^A-Sn }j[LMdDjn:%rd''σL"|'_Y+7N nN x[I3X!D8+Qav\nIv![$֓WLL0Xw1|zFʽ.C`mCPf׶MdnڕrO}2cՃNp_)poy{< <l(#-3OWӷ) V-geEfu+V>9YdfںbgzӁp( LEk^Kv&;njZ,H}ȪK(h{M'փNh|)(MYs@dS>hש5 BPt Xyx4]9y精ntjӘ0LoV[7h:-{'?M_C=in="xiP^E4ݩ5?s'踷,$ tv;(ﮈȶ.VrFwkFPݕ輤ۭ+#Bx'׭&h={l k SIo'/G'Mh#ܿ[5#OnϠq8p(nDy?k 7w!h'z3 kC{7q;r;So3X,:=-_߻{> )iФ-G\z%'yxDDDDDd[\f fnoQMfnl~jAϮ+ئmvbM;ZB@=곶Y^_,cw;?}%ij(rS@!%)ڴ=o_LgͮCrj֕jߘăXV$g>3dC_Ȅ}ݩ""""""A܌wbպvk[kwb9q[ x=H7r4ԵADDDDDd+f&7?Ě"6Crun*V) j[I>Te1(Xc~[%}UVоܺ9Au)㗕b*?Aʨ}U!<𯉈H0Uoܕ*!b1Sw u""""""ۻ:SiDDDDDDG~((KA챭Җ ɕ=n4ԃEDDDDDwrSPݕ<[ebؒ!٨Ośo\DDDDDd{/#vզ.J$:ODDDDDD$Wե\ٞ%WK28""""""ۺd2R2su5$W6}lϪ3_U~]] Ful/+GUwu=$۪@'+"""""-qSUT~jzOԬ.mm!*.Ӌl꼶dV{DDDDDDL&VBm81""""""[m.m!ʿU_\fm5$bm򤊈Tvǐ,""""""+-pBoH IOoD=Ȗ,,Z]B-!!˗`?W"T)[^YDDjՒ׻ee """""""Q """""""Q """""""Q """""""Q """""""Q """""""Q """""""Q uǚIWpE2⎉HMKu _Qc6{멝.敧fW """""URHԛ![5{'cd"]e„)^7.A;Ϳ3K8iPozIޯ˶/)\I{DYå18~,-‰wӻ N>)K ,~kȹCӳg_^|?(yv'8k9<1l""""""RBrx~v/w_ُ% ]gK2Un9b1\9i=O91z|<,}EA]WAh b٪4JɤYVs_:WPc j(w;ï:YH 7Yfv?a?o o,R47kI"K'rpDb"{3h`_>"?Cd- x{1ڙәs|(9#Spo= 9螬{Q^GODOa 2""""""At%~&.iY1n(=.}| >4mߛ [:@Oؿ d;Ag]m{dY{gq391u8 tYH,|4.eE^/L6FxH/ULn}w1W>bV?% ԳnqoםHg̠QGea}]8-Ԛ̦#(Nn/[}/Z3ouu^b}wHVn-"""""","""""","""""","""""","""""","""""","""""",7bnYDDDjIoED{g`;$"""5$==t""Rp8^{up""""""ܡqm3yrQ%vMVh6N:;/tGDWYI^.oEoVDy#80$+~ȡ 7 wφytr U'Vyܞ\ GM|s`%շ,/}Ƙƃ8߷:s/92B6,ªOଣ#s5o< ۻje=8}^N>5#DFSiNRsʶM_Ujnm5'~:h' ʪYDjC/IWL^᳉|=&v_'{k9wر כC/dWK9<uo :*Ƣٌ;C:^Zۤn8z`_zƥO'_yNVyd&a~X;Cj؋6p7cʒ&F=_2CpS |y ;ϓ߻'^ȘW'S9,X2Xo]0)))%L8Qd4yߐslxPv Ks?7{rB.grg>1孝g1w/z{^׶K|/?A}{cЙzuU̲El;ﻄW4|,=@ъxԷ7ܵox[ۺx*=~}Ϗs>Gy'+/!k]3Ka}=*RLݏ}sikwc<^lM!&0s4B/G!7eq<0毸qI]TOY=W|ŝ'ae@,838y@[OvH.>Q2޳q{,ޒ?DPH}4&~Bf!;!p1;03Uܔ/3;63׹Wc"'s& nݕ'yޏiu|8Nlrt{Eaz4o?wǚd[>"䣏EXŗ~CftNX8F/aiЧkJnOߵ|=<<2(Ø c9.Köi~Hw? 7r7ݯ=ff>vwߟ/MfWpĈ>bu 竨M _߻4&|"KUp듙2^{~vRߣs=?_Gx hwn (_݇{&|ǯB0~.!ixsLZәڕCAv8#_o;/\K>/;KMQopڣ돼4iU܏ aN}tS>x[-Uݓ"5K!xV;3'Mae8w>kуv#\k@vCf=B!kJVW #wq{gB)d<3lz~q@+6 طkWmR hCٿE+s|HjʑeGW^מ6ݤOHC5"nCâlG҄ ҢO9aCRppW|s/&BE?z:Ɯ7*| uԉ{#ԣԥD9~tjCte%z˖Pďo˜&);Po^ =>!e羜1-Pőt K\UlK_N3 B0*K_$ 9دۨGI{5!Lue,Bp&:.MS ܄'Ǽ;}3>eoqyӼa߇jD(Em^<_ ze7%qGqR;1Ȯ ;'3˽ܹMߣRZN}ϻ}avإ=m$hwG1Mւ>*υ_L?2}~iwn{q+ʊH?gardjW3>k 8c6$jHgr&|odgaY nېP>{ʠq'-He~ ?<.q &2`.jf=mLyiWx) s=!gu A/Fk)t &&+Xc{O̤,"Ȋ(E!tc^!?֟+w Cd-Vodٗ#4XPޑ7xHى6;9?C hj ךx|DXփ<[]ʠA $#{Τyv5ksX7 +3!RH@6JK;{*s)y Z 7鶱4$2ɴYjJ/PfSDεE޺LvoQc0MzIXͲʾH!%ţЋ5#篦!MB嬧(=4[Ҝ|r= u]5|GԔ!JLq^o4 Mw(.Nmւs/d|[Vߣ*>۞ƽ5gǥ dx'wMʞb\H!mڜ/{7<)?49MGC`ٹ/'"+&{eW G:?%}WDD_CѸa2lYVs_:WPgINy,uHJf4M?߼^~9Ja(㹍p":*MbhW򛥷q-kbmK _,3YYŲU, IDATid7K'59grOƍ\J8Pݨ+:YoM)qGJ(8/չhTroV/'~SV| T!܏sWW36zIGPMְ:6gyJɌsCa2叙}8ٍrc䋯H>DVM~׍Opp:)ţyI[:Y=t22RYccͺH>J5`cP4=3᯼5ґ=@d-s&_̻BMhblK6<sYx7:iLbr7+6>I0. 2אɺwy^A{âlf16HjOd?/h{7%Wv܁̒_ᥗ|OMe~DD{>P4wOee!D}FtqV+.t),.Q#+(eF֍(*,[NN8<h՗Sj‘gE/GrL!\A.aL>q=ms=}{; ;N?νgtbA 㾚(Rg},g^V;~^#_t:}{y?x&%GZ̳K>'p{rm%-vRKmLdI$LԷ96zg3w?N FNm|<Hw<Et֍CunG'ҖSo^9Osᱽ9G_N_,_9׍vɭ=.ܛ>_k8fm-EX]\lZW_%5F.{"W#n@ n+ܣ{kp^ ̘Q{k{RWF=M?R|B {ℾ< >8;.;bEzd8;;;g?]*{T͹yݻ?>=QgK?qŷrvD9/^sKtsb\A-#9ehwRL8IhkŪ3 Sl^W&Oj4+ə-h301b2mǏB:k"s1.L4*B>2vQ 4kHQ'A^@DDDDDD\ܿR:spa"vIJkR.>S:3g':{=wlc[t]<Obn6fކbG&sQj`lӎR 3tW ;׎^&GcXy3+ Ky^olˉ]$]E!Օ,aƼ{Ex L%ſdhq‹urk4~r-g׌q&ױs:֎zELML94RrvǴ{m7'^DDDDDD~4Q.?bv^P )FxdDrf:^Φ9n@gس3# 55auI@;+)S'""""""1Ȝ&xaJJ.fB:I=_ΉJs>T=c 36#ַߌćk$F (:AODDDDDDw%UT<\vus*&Tvs*'Mfݩ昜ړA7""r VǰAkNי_˵:Y`@u 1ـx|Rݩlséls*:;\{LIˮmIZFEDDDDDD$8(IqP,""""""$YDDDDDDAId%"""""""nrjVȿ`M *GJIrcmvʔqN9A*Is\rŵB\rk%"""""""JEDDDDDD$8(IqP,""""""$YDDDDDDAI#,""""""/%"""""""Jv6 zR32 _6_rsZvN߷I&."?U+W۩VA"Wmk>|JdʎmlqO6B_hwǺ Og\OGHr/>1 YG"XqʔʂiSDDDDDDDImÏh߮%\سg/fN7276#N0ka+3ԫt|wwmL w\]6s! ! ܕYX[~p wO!9?-*Kq$o}vӇN;ޕ(ٳ7)$Θci+~{s3l8_g7pz>N= 1o̧ә1lu1.eNIScƬsRDL""8~ JEDDDDD\)IBCKЩcǻe5yNrUw3Q[* ;qFULDo"1Nk&ϙ nz2eKmh>~g/u^E:EDDDDD$pM&iA@7&D`ϩ9X gՀ[7ˡm°g>d>fnbJ'\PDDDDDD%XRܱS'  ۱6%31W&޴o׎^}g^fK>}h߮`){2Y@,Sֱ{jF4?2qoʴ֏kz NiY9WF-[Ɯ/J9[vβYm,Q"Kwdƪ-lޏ ~+[wle:6ANwh=ůVn9(1Cq^2SBvlM<#+AGI~LSǎӇN;&('%uip?v@_qp+KfXXvZuɈvẦvM(dĚcւՄ)qmD̡(Xde^{5eo?LDDDDD$ $?F\e'hnأv0kܮjX.]q&nbÛ"9(ح܎ 릎cC2^xOT;qY1/?[p]HyD_:1/vgJzd"""""DIc&)Qة}z{ 2[rg3cǴ_?S0C_]t?X09/9}͘vHv~D<lp5 T趘a3_:l2Neh$s:SXΫd$1Z>z%mB4n{O_.s2ݾnjq"{7nïvZR癕fbLȣ |AQplͱKŹCH3~50:fЌ֤hٕmT\c +H*B #%ɏ'`ƙ~16L(ݐrSWc[M)3jJRV }R8$<}> ˧n' _=S7xc78p sLbL@΢Tj\% uҩi&S|ؿ#3oyҚqܽˮSР9y`qiv*9&3TvsLII}cX ȵ.۶o'LQODDDDD̯Z,0 }:l@Ky>T9 T9 GD=$e׶$iKA׮8(IqP,""""""$YDDDDDDAId%"""""""JEDDDDDD$8Vȓi턕)ZsU"""""DZ!.4,""""""$YDDDDDDAId%"""""""JEDDDDDD$8(IqP,""""""$YrQsR%\͵B$uW<.=_gCU wÈbɇ2p Ʉ3 ?ˋuF_aZϺݗeJG25h R.c C b|_VnSşf@$drViO#0d>[=Zt{R.JK<оbx,ucrǂw:nk,o do<b^|x&\^ʗk .OI0ir-IeögxNT̉2l>+8GD;JUETʙ{m'\޴ɣWpb,!ũUKޮiGI},^3Y Vv]̈́9_4~:KJ  9!3a¾n<kR&Kj aƇsM2¸^=z'|HhvOLab13vcZdxB|% ƍ8wVNMϓ'GBvgp 7ȳq:j75ۯː7 xg{Xҕ]c/3ީJѿqD\ lMAc7LxfCo0oG윚}ś0E1ufT ٵL_գ]7#X?B'g!_v8kl,9n)6fř?N y,q-}'q#]VB&kbhK\Coo-)bTWBPR;!/Q`r·$J"۶owJU0+}g}xvRV+9욶c37Q[ҾVn*~IR:3qIz@Բ%͎?Ư(/䑁B ߦBdtڎ2d-iY*#֗'V. Y{vqw 00eGW2pkDy a`"v̦͊ڟaVy)ñCTgt욱z3+_CӮu/B~Ðy8.M'1V)ڔVvf2VFF6R^(6 잶y)*]_1a,.q;1 ] :QNԙ RIJN {XhWlƈN.$syCޛksӔgMw k/C|\=5>d+F繘9!rEgH8rTʚ|s;"'O yxH8Gyə֓CW7OgT8_Wx<`_!89w4X1ej{>"gf B2ɂmFA*9\8cYBѠZpbg%[5CU8 w][H ,ݐW0t1.dvi4֣H%W9˶s5̀U_vĎ*EU4K:3$MgX?}?o J͘(kpm&~1r'^dɞx%Ild\˲yܨ8s+)O}ۉG`kÞ~}2 l!ZKkn*.ƜAFײMwb==G-0 1Xnxz94yU~a jUkM?k:-[0/{<;N αpAyR1b ?&oO<1Xc 8^]nlO[km&?.HIgn/44AwgƕsgN1FI!x^KQt`YΰSDw.M‚boO_AĮLC0M>g;c3|̈́ac 2{6Iٌqlm)'<-oLoO&cD- v~Yy&Nx?39u4́dkV |ɯ7X}I|2c6ݞ7D;,?CgvُmD^”98`[3_b8BB붕O˶W,470bμ[UvxFNxJ46A[f30`KYH8Q~ˍV0{{KlrA5|6{@l NXbI̻hbѱޣ?$"t^~ճPQk28b&W*䝰g+ù!2UV{;WiyScEݶ590;>%^~^v"' 5~ǧ0C/]1$(*>/qK\#?^O~3ѱ7c.ed=:͙_Cx+џF` _9,ԧ㗑% [ņ|߾8B<)-.}7aħNV2,W٦|8~|5?4Z=k'TZ{19nU2ᗞ N7'x_쀧9دjF<wBвYl:;v*fkטIGҩen,n>evCl86\e2o*qwfQҽ׸s)0_WK|(f?'#1:Ir~Ѓ_sڿDYZ-wzyulNeX~nNL5Ie7<ԞTٗ{h:5 \m4?+-3 DDDgGO#(CDyY_=D;I|A$^RvOj;mr`8mNeQtMq)sٵ-IZRxȣfyQn%dCD""",yowoQWzY8YBER0,5&v]3zвAUJ?ej4˩{i8It6e+MZoLjIj4"1sT#Lekw}=x`pst:6}r<_z/9E)ǽUQ4z/Jʎ'tjB)|][ɹׅ z`|K?)XO`HԨFhJm՟gﵽDžM潗Vux&ΈJ)Y,}Wyz"-(IXUkd2VS#ӋG3f ֗c8/̠kLj׃ũu,B: 1kvvT@ŃZrp>%M;&^TTKIvOϫe6_3lם{2I|ӓ%{l6 埾d8 jmbٔ+_e[W]p)?xDn<[6g{Ɛ]w'^}c>@kfvzaM׊H>GG|+ur;Ծ|=dF܌9뽎T6Cs_0uVvoΧWө\.ٹb_;/psPlo:N9 Ԡuڱ oVEn8קUĉ1|z6k}8~[зe=/WcTA@Y hESR;Gg@|u=}Z֧Js]oImE*)S uwVpi=?}ژ*QbnN'H>nT٬ȶPmeт$kВ!^3S՛ھUW#aj6x!B@|['羱{q}Մ9`fGerdj+5[4K`IZWS q")K6Yӯj}J̮+Hb!W2d2aIJ~ ^s0v*!pFp<6`S:2%=0(PEcr:\Ͻ>ڶ}{ϳhA4~µ_̡9,:?f%73ٰe#;L:|8nKszN l/Kux,n®}&1ږ>GϹپq!le}ú_-l[1&%\M%`B OYɶux2[oaŦM,G6,Q#w_f'6bG@iX_C~VlƆ_iŌضu!t0H{I$5=bQbzR=z 1}>J y-`De<;F3'99?y}j[ 7ǎq= 'Oǒ'I5#_)z;.FB< x$/`&S ϝr?x}4_19ƼW}iN^IUk&k\} 5ugO;vk41x'טk4VJ /on .Z\.E2_6ƷU;a'!5v9WI)nG c6XΛo|?" DnJEY|B5MʡI1hȗ35f^}TsEDRG^Y,;ϑK7Lw[NyH>l4 dh!2"oOl'-`[h׳w1^SA¹HwbDq~ [kL&;6K,d2np/&f3f| v#MG=%az.37)+WZǨ4n> ({_ }ʄbq]^fj};OJo;ů6_)ځ?üNmcڕ!]*1{gM-V}1{@5Acv?i]ö+kkv60&co-mꞀ׉Ą~Km p| ߧJp̼{8%tINĵpHZ \h&K npJ<t\Ipp:,Ap{n$,l.rD# =LQHC&_F6C~j-y 0r6sՒYɒ%s┭oxDά÷Džc~ 5*gu`iw{|Y6b<.b`p ^KIWkg[Iy5[?u& Qj0 Kڼ\xSFor<S,+o@#<f2WM_$`:ñ Vd(l{|KB|<þ]~I; y5②tQ$X9}hO/g9Gbgm3~Yh$`:΅c5 f]ܰٹ}7-OJ׫A ,8Mcs T4tEQ<=S֑AKq=Ⱥc NWywXWA`K! `ęyˎ-b'n"K*3,csE)~:v-70qyMOZv?ʋ}f^3hUl IDATVl^#mC>ݺ|?%b& ;5[ ~[t4Vx"D'gY0{E_J r" y5, H$8&RvOj;mr`8mNeQtiq)sٵ-IZRxă$ë/?qx<2ZDػ(ʽM'@BH(R RT@Qņ"^T .%R uw#X((<ٙIf쬈y";c{UF!Yzjo[C[8)$8)$8)$8)$8)$8+6%Wq/IqRHqRHqRHqRHqRHqRHqRHqRHqRH-?u=T&qsа.8DDDDDý r 3%:R? +;~$~L ~:E"KzIG3ñ/3{}=8t@ v OpR4xeZT ;I;_OXڼ%*1)5Zym-$N,͘d:;/-㦔CiStl7 ^ jF/^`&ppFΉ8;,yz[:4͇O1Vsj .k_tG|y'zqmn7*Çk>A6OQ͔U'摍b[ q{}*-&O|N 1jӇg杻N$gy+.NM ]Qٴ "u}`ei>NG; ?j˕y4F!Y!&;OOv€ ؏cd:=W 4zryR8h<=$ob`H.kzuKP5<>ojG)B`%Gj,k Il8Id'Jⅉ#4s`0(^\;[ʃk'4 &GLlۋ_d?}E4)=s}䥠IP"ċ?m/>ΕnY;W_dyɥqaND F a…Z|[ 2=9rx^2v3seAo^~[}uaf%yw㝪!x]wb!w#Ax͖± ,yݷCD($=3N2Z}-vn;SҭH3ri>#;ƾFxDoYȈ~Kr,C(e:+A% 鵘'qxZ)]A 9jJf kɚt*X3ae|l+_kB!ۯ?gڳP+tXVLЬI0v GSzZ9R2Oacwڒ[j9ѤK0 p1ޗM]+^Y f̫.1L65)9j6: Bօ26=SN~9KaÀь_dx. M/=splv=ђq$5Sj@ omreBVgÀ>`bT/ϗN aFqj+ňbX"uiY1}m^ݩoߨcϭ㷋iM} $dE#w#&Fvc3~a3v6 [hHZrSNRNg\1֯JJlEh ;_iJ+`Ʋ}mnԆ7TWߝNgOמnܴ$5*E]M$s~98 /$"i!##K^9V~2yAmq雧uO2al,&,E/a@no9;8=Ƙv|9c9m~}[#*Q'MBZk>t$y?gTy/ȰwUzkE;Д8ٶcg620˷MqmxzpD a/ėϔжqmNL o{0dcxX&0n9:>,49ppܼDQyLa(sgVdbtX"Kn-N,N$6'&*=3`i|gږd1?D;f^vEݜ WFt{p?Pި[[8E'qx2rF`(r/G(SMN2r~kڻ=!)Y8rg;+}Q7I,>MnpyͿca:Ɖ(`5tNC][z7rtĭYj|Y'3`pzz|[1%9IN1޾HDB>.A; 7橶5Xy)zډ,MwtV;՗'oQ%%3w>nUS,۴`:̈́Dg7^DM2hx2G# 5h4ܻ2f ͳ fς5{κ-wRI7*&I I狯__I.72HLRĭ?'QT”?a6Vtɤ)_&x$~Yđ_c9:e}f,yfϦ+o#ě53!d~gc>K<752>;D~R?,v4Ft [dޯ5GDnZyE֐xwu.Ɣ]Ֆ\Esdd%( F>ZOOcpXȚ3+ĥ&^">(0ZA}=-JW,}4+/ǸMw[{xp\&Ư,[3-ȓg`ql,90,wwVD,d Ǽx+7/Ry(y`_8|8_xIo^E{N?"|+2xFo w=Lxûm~|$G%Bӿ)Dܕ/Zu9"-"w$bkɼ6xgf]\J3,kF|ꄧdK rxz?N2j֤LYv$Rmg~"xN:Ε$,%H!%7]eֻ53OufGk'~c'ȬW(U$T¶gLNL_=w72^Ŏ,g3;wg0e߉xG<<-$q`HO9΋I; aMRq6l }˷Q8.bFx 7FJ<[!i7r&$nO=H ùS1$` V?31vC+<|8 xfU^'*Q1 9 vf\N}³ɺv f'.6L.Qt~pG{d|_MŐ[^,g7G61 2f>;Q71t0G~DN>[F|Roi~=7at5C$$$bqқo&I"!>@ʱ_$ҙ 'DRJznD$^˟IveQ ;k D<~<_}] a'#s ^Y>l?ezF*tr}pLN|\X̫7NwoO1ռ OlFާ%'ZKa72{h+q|!mH^Detp{8l~!äwۛ25~QOa}OGq^>U},A NKYQ]Lk 1p^+Xss Bz}ڇ؊O_àWdp2OunbԽox7XL Jxdq%ߍh |Rq'>{5O:#}KUY5n/~F]WO=qP5B}gmfгн}>56|=+KV3{BS_ĬpyVq䤝#-_gdm,i0rVgV2~KN(d}ڣ1}: c]Dnח鍻S-:v-ťN,K9ΧFNdM;~[ ##ű~/8e_KDD] [>Q91ziȽi3/9  ؜#9m~Klۀ_nMg-y)k۽/ͽn(_(""" {C&""N?ϚWgpʃ!"rHBBBBBB'Ynjp/ȿeёd'd'd'd'd'd'd'd'dgל!vH7AG4>PDDDDDA!Ywfg̔t$\1Ysχd-ý*"""""RH/i#=>E`< 8Ǻ39\9jZvvi3b<dr,[)Y)\gqgbuًפ~dqb^?ūuAPR\o0c1,Q?u_ܙ̻Tjl\Ӗ4yK^ uU$p.-3[VrqRڔuì_ X*T,2¿D߰t6L9.".5=gBl_3q[<,"""""nt$!^{OËOe] a \vx#/d.m1$6/\r#  d<Q{wFaNf5hP| 縝ŭ7;\.+{I2r9f-#BAơ8걙O {aQ`F qnTj,5/m-(<{y($K2F˂0G|>$$=6 Wvd#{6q_&a}/I!.>\17VOf{g;#Ǝbd"|ͤϓGR G5O^B,諪.Ae@n LTD-9xNV)gK yò`lsjq`6P k[ݎ=WUޞ''M ɏK5t͵(KQc:b'{d]{0ny']yy9{î_ov;yޢ9EF0nP`KmV}봤q_ѳ-oC@we&U]Cq!4s"`'8@EDDDDV ɏKNf4A_:1˓ Oglz c ipWF|ieLjӦ'o":Z]N IDAT=.|4 ^%fp?ɑđ܏Wu_,+ɘ` `! څ╷,e?t5:whu"ko92}-/3{]ˀ9ف|Zåmwm^)mwiΚT4m4Z7qRHqRHqRHqRHqRHqRHqRHqRHqp/_׽$"""""7q/IqRHqRHqRHqRHqRHqRHqRHqRHqp/ȃZ6zSl,Oia3xz]""""""x E@Q͛ukN^?l^g0л#?)PwA!5f ſr3zv}' r۷%RIO$n֯=Ĺ/(GylㅪRzM;/)eUdHZ5?u R$| qRz#絓l^C ['Q-l6?m'9/h\FL:u")$?hI?)9ke`3*eN=;0B\X2m/䔩}%q31?n%㣯`K31W>ѕ& O lRʮ[̌M48GMd+ k? 9iSϬx>/N(NbMt~ """""|mt/+wߍyǙ(]ORoI7p>w-ߞ95N!bAyi`ƣ筪\=o}%+/P)& 9-uqh|Kxpp68Ξ v[wNYW6//ܩj9g%0v}}iƲw[enM!> PS1o&%dw&ҋ}Bd6(1q 7&Q|* |rYvwɇ7B /V X иK=J@Avn'yr~ d?<9 f!Fa[F /"""""RH~,9媣9NQ6Id}]F&_| HILZscU$&dd}Y-3IH3nF9nK]{,"""""$ X %=ٲm S{U3,muptQ!d6 ia, FLN5WNrZ{w䙓t]Ɍ8Z2oHt;tÔװ| 8?i~Xqfx{EDDDDDa5ɤ7Nk}J;hIg.?-.mvd<]u>?t5:whu"ko92/eܼpߥͼq/+pq6NU]ۮiٶzݥm:kiu70qm-t>BBBBBBBB{Azf {AHBBBBBBBB{A3X8WS|ȑ+WlఓlOO+DDDDDDRH~YY[>w$3h]K&Ƙ֞g'cܢK)v=`c U1Kqrг<^{2`6hkk5 &rf*VF##'Ū֦zlx1r<ݴ gVrγ5 %K^ uU$78=0Wcd(V  """"""e00_ <SveV瑬:aô㷥WM9֯=N>H O3A(D;z'3gq5#1)m#Qy07-fR'aďy*e%^-ZHO͉X%U}7\DDDDDG!>^JWx 7Ӫ$>[) Iiڰ*q\{y]xSO?ƿ aߏ:i^} [gylT2bIg1BDLϧ1`f &^s*| /}),"""""53K^8Yc;czbP>>-[9eѬeC@1ZTW{5&VD|md"sZ&F,Cc{*Us,dyi 4oќFXo-}35o+FGeL|8&4ILH4|wsyd0INJ"_^dub q_&!b"/a,}g%Hm<_ֈ?ZiǍE)$?h$ܸ+q)/ \H8/ yHjvs|~LXlPK yò`xჹرuˍiF8X+кǷpv$K]ȿN~N*S~dD2Fl凹c5fcWu۶I58-:K=,i?¯2-Sdaڿqj6lGm4GxxB3'p Oq2"""""" @ej_u;>)ݴ;ujI^]irr8+EkTؘGǯHj#WSbWƫیGY>982J.YxfU}Y*uaԯ޸;m)0%y=\iti{8'v>AՉi^]""""""_f~- Ys)nm~KlӥmwiZ;Li\}iv G+""""""⤐,""""""⤐,""""""⤐,""""""⤐,""""""⤐,""""""⤐,""""""⤐,""""""⤐,""""""^)c{IDDDDDo^7:,""""""⤐,""""""⤐,""""""⤐,""""""⤐,""""""⤐,""""""⤐,""""""⤐,""""""⤐ٌ`Fgޠi^}q;m?1Iܞu\q0޴_E""""""{AnI1ga`"S` W,Kق.33}Qa֠PaVO#&Ղwe&q6r3o?G͋|(Tq nŽ)Z<1aů_,pl}-3Ǧ3)Α|W؀s'o*u'= ($?$ |{'zڈ;ͯW6dZkOQ*3Xży(+'q#_FAԺ:/$1"r=+\N &4̂8oh^Q;ְ\[ ʆqӜ;G8wP-Ʋu(%CඳpI98bqx ] ̓|[<赀?=62dOxo17tyDR֍?_X0B|H9kPR(ժYw լBOr閵dz5*ng}=$9cbA &}dXT>ʕ !.;(@}&YDDDDD  3$k8 G-hW:ΐ5_2uX1I9żq㸚R 6ԸY eŖoRoJym4t$?B9і6w퇷=OvWt͑tW^,69*~RS$~<˩Y%ؒ%0BNjʈ=xo7߷iǸ]D BEDDDDDt=2mGX9>Y)X׾r}$X Ԥa@Fͨ>p- KldpLpd/OSxMfhج9-^Mqj-"""""F!!^60o^ꋟLb|ܙ2eJwcNȨ?d +W$6 Y8sFIߺ-OS*WRqD& ꁧi#e4x,o!ޛ ۯcH1n@>A*Q)X=0lm""""""n?Νwرӽ;vsg[&WF-l=tȵGpk6Ɠk{RL{3Ǔ),o;=bl>);L~؇ۦ0Q`NϹOqpl4lm2?MkJ[6Iػ !^EtDAPPZvbwm+v׮;bl*]Q@:HCNN<|ޙ O$TZ %ԭ[W=XP6ѣ֭+{*iJ> |Sߓsz<ևGG{u8"T5OFr5y^TW=>,moډ#NؓPZ0pH$"""""RI)$7(95>uezmNɪݙzd鳩Jf6̶\eQzʨEՐGlU~w8DY\uP:M?TȹDDDDDD*3d諯fW T҅.5bTۇzgA6lOuO1jB0Z5!3__Q~MԠyfhU,S*_[M, -עq,ؼKo^e]""""""_U*uݶ}=?%G.۰_g|wYt>=@C &{;7/MߙFpTmx|/ GM|p֩Jdx_=/C$Ϙ >%HwKIn]KB^ IDATw/" :܅zw?w『aBmٿWf'F=ONW'ąp"7=:V}㖇N栺6 £YpUݨj}O9;|-#i~*YDDDDDܕuA5SLPC@ڇy57[b3=6}3on1>}+37p̞3/ $[)sٔrի[J` ߢ@3Ǧ<yԚ{Owl=w{F"t'YDDDDDD$N!YDDDDDD$N!YDDDDDD$N!YDDDDDD$N!YDDDDDD$N!YDDDDDD$N!YDDDDDD$N!YDDDDDD$N!YDDDDDD$.-Hk疊=g{r"""""";`[$)$)$)$)$)$)$)$)$)$.+S&QHxx}Tw:v¾_Y\"568t޿?CNVuJ9tQأ+÷_3~4ڏ>uk܇/UCy|έwW<75Msϭn/UͦY.j4oȊ /rڜS79ӷa3ۖ} W>/ɓ<^.>>iD(-8!rXtcw.`Ҙ8b@_z[YYN;+w8}dwsA}9DzcA^.^3ss{YE CC8gpC{ruUtO<]~";SZ-{zƯb@_>#лGz?+'"wǑ eCt>Tl"47DDUضv!? _ݟZG-{їDK˴{bUkDt֍^֣cYW![qI\7q[ԣ ѼvuwF7Yƹm$\nu+pC:0lAu UlA*"'DFF~8mo#o O3"]S9/.uWҋ>_1{9EW4UX6[zDL䆇r':cc~R3!T/90:cƱUps}LQH=e_x= {m:9=FezmT]Oi(lƋ&kP^V"U _H1N:hӤQ 7kzGzWn%iI6,_y~p5SHbSeݚu7+v71 טciL犋ӡF!O[Yt}.µ9욱\۶>ǵa/rpuPja(U'+7Ɂj5~^/3q{YOu\qrn~ YANuFNc_Oaq[ ac5FZuՃ oVQ3c!_?eRMYxAw<{|g/w;΢>boPߏGD U*P&uI6ǙsYn@X7&[ɲUUiذ&H>!Bic5l?cl5+VF[.lca7/KpA[W7}Ͻ«/r Q^b_(.%>x=~a!Y<%Ɲ/b @f WOCʑm2kn 7%, W[ZGd> Aֿ֭2z=0c"z~=E }'dLg(UU-u%jt1?9f'J/s_U m,a¯-{ynR>?dፇs5[׈̻8y a.^7_%vǯE_:λ>#H!^M >iKhܡuta hx残Bl?8oGY_"?|W~L\M~YǺ hi`ےLWُƙe;S"0MB_ ?,؊xQJG {z}[/&%GI_>eѦsyX. ITl_ r ];w*3WbOa|xjd&(Fh?;~XMnNvh! ˔Z5; "m'=ru^=G JiE y"wܽ[9o zK0+GjUhmg2 ,7ٙjNdɄGrc8EjѢۙD;["Y8;oWfㅫRUw_.VS/b%5$n,XKzC;=| ,ZYI^ͽ9伻WBzc8[yub2r0ZrweR{y#\PU6$=nY=u^-o|>9z<}νs=k3r< נFၱakaXfMGӷ2cx_5{Μe[\>fw5y7/GBbK29 RzHi85uh;Dխs%co%Y55wl=w{F"vk)'I?ED >C*""Co_5ŤnUv""C!YX&onYDDDDDۭEDDDDDDEDDDDDDEDDDDDDEDDDDDDEDDDDDDEDDDDDD_@KB߻%r-CwEDDDDDDEDDDDDDEDDDDDDEDDDDDDEDDDDDDEDDDDDDEDDDDDDEDDDDDD%%/yy-xny;dƝLDDDDDdwdG8eO΁{&E,?X ɗy5n 5dž9Sy?YUc8(#=Nyn>s{d""""""iQH(M|lU5m1,as|mv^v9\c< BrGu6נm.ު1'f""""""I($WފϘq6ޙΗ5bQB|=VףѶ(զ؅hqر Uyc'pfB aӺNbk=~OWf}5}tjjbf>k⣙R)E1bܽ}H"G>d~ޜr|[ފyw{2gT~o=ϖۺ/[+Ӡ-X< p 'd?}b/xlr}ēwBՎ8Oq8{Mb|7j.{n|?]i(/S&'i]/ƺ_pȶȀBl3g2ޡ#̄?;94k|6c ˞z~,A-;`GÿܓoOa+ZUqi_KIYDDDDd\Jz-">`{smPܯ3m>(Қc.Bf!4ɛ!T[ټa6օ y9dgFp [ hMk7)LSЈww?~l1{Yyվ4:v X: 3<622| {UO&mfcnCK.Aa&>%rf(y ?=}Gw]Åsrĉܧ~5nH!yg60٬fLS'ɣ.kS{8Ho?ʲ*Ԭ[-DZdUF5 AmS QDiY]oUV/* ϋ/uPع3^3O0MWWodRA;md YLd23$J\J={7zޛċ;o/"""""[:ɟnq ~;y#OO/.ܻ[ Bm'5F3eg,yWzFX썜~wpF4 EYbrhBu<,YɆ4ro&N]7&9BFx[B9W. Wp'gzNi G>Am2oO4Grr曼/:nL30Q c#x/?nyz5=~ڍS:A J !կLsw3A=3kla5ψoͼ`-%KDDDDDwedC<ٯ[Br3D vk8d8d8d8d8d8d8d8d8d܁ IDAT8"OoIDms<=C@ylt)z1WLh LXDDDDDDJBr"zg?zs ncY%ϟˠ>&ת-_:Y}ڽ^Hڭ2XUi.̣fuLJjSڅ۝T<nA\:6G}+ j1}xm{S{Rg\y.=n UGY?o=8/P=˧7;Zl COƻ/~Ƃ1{"nan[>svP޹2ΣSbMnF9[r0;xdjzY\u]>AYr&"Q~M.S1,x> wxu@n}y ǩU'sSsb'r?O3wqs#rܓy_Ι-ixqE m_0Jn׽4'e2zRM/Ә)^fnc+s1u'i:$zLp0<:-}c|وD|\t=ΜW-Cj2y#wgB"# Lڝg,^p@FG9?2!TuOk%Kytm=nJ&ajHVKޙ<[޳=-k {&N+] eczs6&/'ՇFP١ߒ=ӦofgӧiuiѲU@9zjBUi~)w=Ho-5{(><?d, /Xf-4lBrQqjlXú0"mP&R> ~O#XcÚGװۗok$>Ԉ~QsaaڍciT,Xad;=fk}ɽ'xFollލRԊ&x-qO+Ш_RT̴H!^pcrԇ}Ǔ7,oa5lV*-WdKnOp>V Q^mX1hM[>Ψ?burlK^ 7^Uc<6ZHԭq0NC[ 9ԫUC$w}#3uu"YF%o37]%"""""U*nU/T=Q K(~ }'^CeµRk|~]+'gD|`۲:ci[3l& Tߚͫ6>×sߴ~[S<փ9͗ĀוPe? Ƈ5y`]:$|j߃=ϔe^f/g=6ǍwLw2/tM.Fxoڴ;N"E=x}5o["Gpu.Fw{ƀr__^r)>|}z"""""R/17[T3u{l8D}8}$eX*Nψo ׭0J9\Ĥk}#zu\ Ƿh|gͣX|nX(A ޖZn=w{F"v;A|[_mKًܔtas%rnWPwH ķ/ĕ,csGZ3u#WkP*LDDDDD*%7;:O!4_(sU|sEDDDDDv\i(J|eݺ.."J3_yJ]E ;"Z]:)wz|DDDDDD*TS"JNDDDDDD R]WU\ҋ lMHe,#%CjkR3CrI/\3He,7]4+B󫉈TF~((KA.iW ɉ.|Pݾy!ݺHeTĽ egt/N~}k""""""/G4s%];$t.n^JrzI湒*ϐw񍠞_ݝC;|Ρx/ApvgHNU>Qw__DDDDDD On?Dv] lj"""""".l+QܕuH@~í/}Ijpg TuHNU:dPfEDDDDDxVJkIgm)ːˏ[zqEDDDDD$qrF7wkFPݕ꺴e] WO∈T8XE rjrݶDUdҤq#ZpYޏ,Sd]ZYdsaLhMģZ~1cI:HhB,]EDwt6m.䣘5vmnݝC5?KKE/Z~= mnIDD*UtK"bN%mY!9Ջh %k/|ۊ6EDd̬JF ] R1 cqf{؞u~5[~Ivy5nc \^_(z'ECtn6kޭcq9]zw,"""""/0Ouv> {{l_-F l[6ڻ=s. ls,75m ECuq1@&(=/353&Χ  z&y|ffNoH3_{աh05}֝!> ±ٰA=wWW2${w/Y^/3sgĊP dnm?&3!݇(4{5}틈TV~Rͮ<;k lkqkfN|l\~5[P?2$|&sc[fl^@s C v9wޯk~}qn.pYj&&cs_bf֙ v͜c<60uyNU^!?׃Ǚ"L^X={n>hpQxLj{QX&Z(^Zcwk=IܼAc{nB*5;lT;ĺökjmz׺a1:c{3uc\ARU^!H- k= ^4*V=Fa`M$L'Tog?6k0n1 k76잟옠fg%AWwnصk`Sfl׮=vTוA;S{S7{Ӌn{:ή\b%4`lEk$w]jLXܞHٳ3_F1bz܄RZM خueSs}y.flnL{)R ~O˜Gs7u|j5{L7Y;d/'>(F v@~{wǯW¼`쾛IcMp1"hnW7zklxݣhh6X~ jp祩DN5$'c ]vݳUwL== ?ήybyF)|;P44s1emb4su_ݯ&"""""W9gmvX&U75SM]gc3wk{{T!KG0g>XSw/{3 {f &ByPLovDZvT򫉈H_>q\hv5c{ Zk`7\g S74;3${7sQB>c;^^x7{o^p;vh&c<}k _`knݱ;~5I; ,yP1a܌=;kf5{s;殳}wl;EydÚ}qc hB5cz/^30?l c0c5ȸu3{EDDDD츹$ձ.vϯNMеv{f3kL8ݵfֻ5#Sb=[w6@baՈQ<;lShDoeËfjn]"""""_}37fܾvo]s~=w E雱㚹=L?sFPTWHvymf܌{bhP|&(Xku6iWهa! ej""""":7sp7cݵ]w3P5xyތ!β {nݱW+s;#${ZǺ/˾&~599΄X{Zs캻D %9FDDDD2$:/yތ0\:w{&pusn7\km6Igm(ϐQ4]kXuovrwxM= 0s[wLs'Ybco8syk_ͯįW{7wk°75nȶ׸j~bgdg}cmQ=klþl֘<7Ss{6Hևຟt֊T&nH$h][]׸uS3A6Tpejq-wT7B70kono[N-Y}#1`J7xKZذ{ S$'QޮcujؿRénpA ;,Joްgknϝ5g잩 cgdA rjbos{oRv^53vs=&H+"""""#Is׸s{l~ܾ[ 1:[_ܔVHJvDgL[7!ӰخRO4mAdsXܰ4wPhW''cw zؕI;PAg>UcLp=v:cخ=Ss~ z"""""RzD=(7c=5uخ%5wݽփ;MiDKԃ :.ݞ7D=vpkd})BO6o~؞Ǥڳvߞ$'ꥥT%~ѯzָtzf~ku֚T_UECqǮ=5wB[uH܃!"""""+A:5~5{{3v%y,.!Y*TY5Nw7ziky:vXIݎAX7 7zi=?Ý)5)+09SYJw gݾߚD얩VIDAT{_/hl+z:J"""""^Aؑ8 ϩsSss׹ KeM"$zΒ H]_s~T){% n1A!]ޭݽ;6RY΃eJܩ¦_p{ޖ~ǀݯuH'Qp jBj6wj:w7ʺT֤,CV.麠03XcKw7SZkDDDDDJ&(W%Z׺cy^ Y;uP|mIhw_߯rFP]DDDDDv/AAϭ'~!կf os~IumRa,o]P`[ kƶ5Ac?AȎ+""""";ʒA4hl Z4[W:HomZ:8stBn.hlsΓIw=)tqק;7mؕh]y2OgmZ+P83mBqܹͯT!(uw5#`ln/y2Ou]W0Kqvt}sKwo_͖ljHɔ4%;ίWskҝ^dz}3PXޭ%qפ;O&)Հ:]܏&k)㥻qkk.w;K'"""""C]n͝[9גItחX-t]!zʋZ+"""""_[j 뉤{Lw e>n덠ҩՂ$ZgKuR % z23$% %9:ꉔ 5)z*JrlIa;3$CcI%:>T=%7B ?uQ$`n1GKv~OMn6`"]jzpr?χER+z.⦯݌kg⫵o`c']=zZ)+f5dIwh7+yqzXi'/]q/9J>vAmSPע{nFBۆCW#{'z=jvum%gqfuzO?)Sbw-[sFtV5a,ygǯ›Vn>-5=xשedt9S܈8yc''=KuS\b,٭壧n jkߦ<|o\DDʊA%#mǮ=f07K?Or`4kd뺾e m<յ"Şy)z zKf텊xG{͘[q*Vp4`5ۨ^Zr:݄{W2cPͻuFrZ|ճwzlǐئ聮[׌0Nmt"([X#''k$VիX'0E##>3-'3ťmO|VŽI;]9ONԝx92yIIMt, xFMXֳ*|2̰-^nHCw1{Xkzv/=S,eK~؝b;vl#a:ر}ǖm,5,>'))\(539E 0,q<_Peede5g<XMD|䈕:ԨlA*|D$b-[Yke6TBMv/֢ͨa7LpРB.\cHcd9k`{ɚ]A hy#UkVmg/^rBEٜC,ᗘˆwXšT֠0 reCn67mؼU]R.Г9|?CѠ"ddfi}Rt[^pOF \ړ;)=Gmv#O{G 'oXUͶۃgO@t @t @t @t @t @t @t @t @t @3Z+kWJ Wβ`_Tzy >{RvuQh6ڥP_T!].!].!].}tg#ɜv\jWj13(S"tpW?Z6L+][,|'"⳯-0w Vo)_DbX+vٍhQ~ٕتe}&,?"2.xw}:iվE'$O^Hyr^Z{xq{F]t=ڵhѦU8"<:㰭5%W )_*ħ_X$mY"Ò'~w6>k)n/kj팭o֑veu^X=eSjߏ94Nدsx/|=|f`ӋU1&u=+0Wtť[<ޔ)-Y""r f* ֨F [~pLZ!LXFR[.>1LSt\KJb"R:'h7GU5գS∈.7WקzN\|6O]) &m5K XAÙ;qiYZX򚴔]4SqUOnFzUԼ+S:*X%dy'b- S+d8V+gZYӟv41}qXsKd5Uq) )bK )#00ӑO+˕7s{n˓g9~T ..) .!].!].!]R$RpRv)u7Q>}+ծ$JWƲ_E8E+.Jt @t @t @t @t @t @tI]@DD ؛jFH,`hg$.'"KEvقģǏkhBi>M{ɬ5Ӯ(kdP!D+7UhxR"*+]߃tKHWtKHWtKHWtKwRGkMvy.v׾i٧&7s0*x7׌Q}~[]~5dOoh#V|]˺v[zG]2ho_/$*-_hX93:::H-3&u冚amun' i`} x}1&OnPl_}3]GMa/ ݾ+/oq Wk/tŧut vNBYIF6,1U4n6F4:l强sdќSX.Q_RuN=fZ]<Vcڼv@=35Үp P,dMUDNu:#V3".EK܌J) ΙՀ(xkpX:֥I'Ո!2[2kYb׾w_L];O;  uq߱5*r9t{`pq- .8٧tkxhC?댛~_s<<)Wn}R1BCGn-JƑ ޴xGQ%߯g~ߥ>q{J}\bXʭG4,܈ge(7C>kMR;4?啟rzrcau1 啟^o STxyU˚m{%|A a[ՃVЀFчMTwʞ}S%ϟq\mE9 >K2]( "ߊ~A;G[iZyLoخӁg!8E] 5yY|m?:3/t߇3.~{?gZypƜ5g/fp1{۝OmjWyP٘|JoR?\__v GT;~t`&࿶!gOt Y튜cmJK3ˏ8aX r:?hѳ'׶Yz7I >{hO용o~}Gu~<xrג;<:Tr\qL'[:]72ռ< XbM6\Hکw=s1]//$ٗGxYwj?ӹg8A!M]E| ] nj'&FOl|}!4koHש+'62 "5&`/v25'Fev5`_x7nyJՈ=YR?8}&ɐAn&,#ԭ[KiJCQeGr3sm,\1|_l)CE;ĵ $kÇrᾚ1iگK{& o>|z of+&ְZAq]Xsi,pi\HBM\T \ٛEٳ]S1Uy;&ž=l@7SF5z׼r9^ H`\oo)C]F1a2lZ0k\o{{ܶ'~r>+`rLbLLM ,f35i22VVvƊ235idiS4\HmYiU$"Ҭq\3NX{ӑɡ>"UǟޱgRϥ6'|ۻ*3K36JI 2Q,+ <5Vjn^b,DeeV*jZXj 3 m PƤw~ަ-T.B&qMQeK~N\C SDIO35#YnD'd2ob.09D$%嚹]2  ˾wj:tnY=>Ђѵ%|mF dʀsFvi[e`Sz#DCju׼ewK\:%Cdv+'tY84¾NlU8@ 9tR'1jƌuĺ>F궞dȥ3XuNh\s܅U,znXsW4IjteƢCժTR}^]ֱO,6WdVYGj\ KԔ'kO:OߥM851>鯜KKIyN-5.k qBi h"w^A!]}Fx?OY};w?Jrީڅ~] >AK.`D@t @t @"VNW&+K z]XtUY^]BD-+]B%+]B%+]B%+]aUxrDZbv?NDi+࿭{ņ;XU٠gusqD"p m;hoѻJ2xǶFGw!""">9v*GphxӀm[v7}eve#]qIsp"&sk0#:trcm,qúJ>b^}i?k^dƑe+RzOE Ǘ ۿr}T^vERȶnM xiȪ|{RԷ#""UʽwoY, q?IUTlӶ4QOzk1eb[U=Z#s=wD+٩7qD ʣKPTi\H~ ͺvIȱa$// Ҵ!f*ƞ2Oզ}zzi֔?ū[nG8{iUV4Y/=HTYT٤aUi+ٜa"TTkرpxs1j^ڙt^;JD_Sn8:eQnڶOvxufFĪ5[Nr`moGͳ z#cUjx=&b[xP|C{Z\ڽfЅuOgr^u#&x?Ig8k`XHijNQ5ٱC̥ݛPdR{^h,H6wʧ۶>$KD|rncl7Oz{n+ՋY6|' Hzmmk{yF'X}}6_ >ObVb̳gw{/FfkbB֮3+oktVȥ],"\yf6߽zf׎sr|hx%m6BPԅnSS̫geDD\³3qs_Ws9uކ˻78^B.Q%sjz7^aae=Ȃ1. uëmYRl >kYr~ό,8sVI{לJ8!+vUk5B?]sšڵp|v=kX^N9D\yaE=Y Ideed˘X HЮkcʩIÇ^ / bI=쌌 b?گ1TֹJy#$72gۺal>e=!"XՀ9ղfJ݌YYN.xvF\c'=F`ѯKMA'b/CB9ޫSlg(ޏc ]:ߔGծeSxcdD6^gy ڮ3K0 IDATٙQMb2'113gpXTH‡,KQ~^>憅NЀ!"s3aLTȳDD9KDkh(-dz҂|'N.,GQLO</5`a==1_B ,Wzk/8R> #^cqA+m=OgvoŝwSVBW%$ts b"z)վ]q;2'r""^]޽e!WyiR{kVK+Uw889 Xn޾Vr|[%8 Qs5kh?mEG=F;ݢ {a~sVx?įmMg|ޟ0~l,ͽ*>4BڠS;>,x bkgϊ}LJkj8SD42MtRk 0|Vԍӏb:QeIکSLNMupo?ӥy25^ĭcەIh۔IY>ꗪWkpzRPY37Ƕ.e7kqsW G#Ž,^jcX ]{(]zںkl7qȜo[Z=ӴjUM4㛛Dmt$ܤ@C$M2[֡Q2Q1|;i <XN 6Ms [Gx=]m_mra˗fW'._xc?>c=:깋ٽ~|.]zw|V,2]-K̾q} dKkY_x/+]z) ƸݵKʂ+]B%+]B%+]*w[inW _2;N~!^ڥ1JD"όvad@t @t @t @NzͮNwpi!o;Xk|:teٵƐxMܺ|Ľ{!K\zءNF攫5LWN\刈41k߼@PODŜ9gۅ(>Sr9Wyӕ?rDz,~`rmc)'}?ug͘pѢY3fץhуG[;v<Z)*\m~ܺ‚=}8t2O(70!Ե!w:Am\"Ri"6h6fJ$+,,Ѫ$AƵMW770Eb\C,vv$ޮvl~Aa7P*cxBEDDbSsy53${4,O+* X3f͚1kV9M=,OE<挽ܪ Y6b.كLHBFR{'R.kc~c3 ^w…J%u_O|RQϘ!"KˆNb"9:b/^QG^ztn(DD/2}䳩I[>婢{F+"b9 K373wvaq y/6>.zZk)s϶xwnO ]F5Xqviw8hV;j [+( .!].!].!].!]pkiy}>iD+B%+]B%+]B%+]GwOP*/_vrrjӦPl?G|t7n%0۝;wΟ?ߢE ,|#r<00?;;I&۷_~KX֭['$$T*=tJHHӧivkժ ڶm+J">7C+mM}L IgyWuOqi^k#4Dk7>tED2,//y@|P(  4mT&˹pϗ}g9Km7:ny7?B>pç:q!V]%syDukoy'ڹpUSeO,ا]SO//ϖ}}Jդٿ`DW{0uwxvAu:7ߨui;ngv0gȮ[Mڮu\{5zgyoj?>1}][{=^]%TANO*.䟠W;D;߱S{0M>yeQED dee=y$//O# ߿D'b@Ԭyûw=>(tr*3=7NYrIS%nZ\Dg^CBo]0ķY#SSp޿w*".;Kٌ!!77t1}uśExMz/9qv͓M[{GEykڜUg|Qz~7x)|j౐W(`Losaտ6_PI1޼e-Řnռ!CDmY [|dx;.,,\(,,|qX QnnnBBF622JMXX-I|~RT)K*9ylW-/>>#"ŋSؼgG.{^ ×tozjظ]M;؋)|oL~h>}Y}9I$%_>oGfM<}^w3'"پ#7X6{ 4=y\^tzfm- QiW&M7uWAL~.4Gw  f}l,-5 1&^CYVkT)Ub^1j0j΄5L$0ѷRztl%^=>hT#ql;y#i+.cwocUz4`%.vx"/N-۹G7)Skܸqf:R(U-y7ncQJ"1߮W×'l:}x7o7|uhbyziаU߹'"Я]^MQpqց_ҩk*"s޷YCo6qda~iKGwl֤a T/2C޲9ȋʇm~A-0i5D?y~*HwvN> 7>jmH{ tOWS&MZhV _hєI"""BBC_oCD ¼Mڿoۖ}WnNxx`kFV,)nzo̒KTf9:⠿]A! ժA^=5  2#a_~eH-M^{)A]W?)nsx͙.ݽvz炞.WǗµkGJ۸uǦ9]}ӕr!~-Hv_q*aA_U.đ\~|y>igy=_T2OZ6"E)kSmv. <)0w!3D@#4NTCD+5P_".UrFtkRѸF]u5cV² q<s$G^^tp$HK,aK֝ttX^M5fVEoPrJRS7|YU\MTƲ>ť?VdDGLq[:,FDD]& :5($uDV 7%=:zonO91k67O4dH>n ﺛ3Шoc/<{XqAU`L?ynRfU.^d|Ňn}ѐSF4ުưu9!.n7:ڎ {=NU.ʮiaeieQ؜i8Lbmm-,،DE7F &FE2+y _\gPcŘXY"ujRZm/NI9;75-z#38""ָbŢTA6nޱu T(`͘5-\Xh%k֬!Hxh4jUVm̥K]xi>A#6ڦ_ \4#!YE5DD\ҫd=KKCF`Qz9+/.-%'0&G!/mFo~x3VƳXƚY]%Q~$ff1>[7*cSqH4<7#5%EiOckl]P&#eW7ﴭf9?Ssc{#O/?iu=-Od`niiY-49҂M^5X%4mf^ԘOKIȞ%"^%+Vq2557JM&,W -,mzvjglZ*Ʉ!ɉ2JGƸFtI߭w>Crw\鞻{E 3ZaBB@ "Hw[~(5kfely^F8LDn]X\ܺn8٣Ojt󒐰k_1y<u|Ӊ4 2ZufzQF,iRo5)Kcbf,z$UuyͅGJ=<]3}ӕhJ,.e/GVN8row&Ɗk&y"Mv䙽gyiqqy<3~Ʀr\P~ǟZ,^sٹM"6oMUH|EkX%RjK\2sy?:Vgv5kY?xaZ7iQ-U<L+.qi-Ӻ0hgr4YЭkgim!I+̫8HeN1?c_Ε3W`M6211TYŜ>uCjծ~/<"L` Wi+]ED$4uߺ[s{6Kf&cHDy*Ƚ͙]=O筼/ Ko7FN 7g/c#}>]K)[XΣ_8wQs]XdWgCAsW(kglFŲ%9[${wiYjm#MbY4ojdJ,xw]JSONK+o\v9.&9TǴv}e롛iN7o_48FD%s]UӖ-D:1w=qeiY3WoJm쵗A>|p&F;k_1PIq灿Ӆ5;S6e).y2~ݼ%2ZȾ~//ëDD͚y7:W`E5ˢH`ײf˰6U\M=q>|uDŽzzk'j6,2]-K?=zӳRe "71)=6&p7hںtk A7W~jjo]>J9m}ZfboS/6)gvec`Vu*1B Oiײ1¢{ǎ˖U|mkkױc5kjD=>͋+U#Hgwq4B{Ӫrs<)bcR%&Ɵ|>!++֭[J_A i¿Mt')<#2;yh7Bup%q|#F?tKHWtKHWtKHW{8v?Vw[HWtKHWtKHWtKHWtKHW/KW|jv9|ҸؠIv9K>8,qFj"_P 1ճ2fU1*'qN&{(#59_Y:6v"Yj #0ttv31(jDF%ZV`EBsD+ug X4YY1ii*5#з4qj`e*)^'DUQQPPJI{y/3[аsm#[ \vːtS{,$+3Sc=kKO-/+bK(E-k3y_lS]ɠ֕;H NgE2@,+)_߈H!s D)b&wijζbVs53Iz%_0oħE9^2_DW 6qx~~9fWS3bb:3"EHOo&76$TIc.ſ4wq.~<ؤg;%UlμvQs3b$p$ܨIF,a"CBL OWWt]נ536(]LG CDƫݫTaqDWJ#4ueE?ʑ+xYeOKc="/_>UԸyW7|f*$4T{/G܌,eh虻8:Y* qF.̪Uܹ'tic}͊ w 2"/k2#MV2 2ud #{%bee4u)g:ի $%? IkhG)^\]>}x7)W)3d䚛8i\jY2"Cc+ؔyMrYA*ϊ6qg&$'?bd+n2FGEsԇiDvrqEc"DD]7_15E jJN%3DLW|$Mnn֓}4qNn"Mbk1Om\Z"RLtQz\Rj{*Ɣ(qH;4 Y.*&<5j 'pQQ <_#3"""9$Yie{KD&vEy^hfijXx^ҳtIly*"#i9FcN۸|N&2H Y8I<ږ-ٷn=׫U/j@GttU/E^tu{]ﵯmYlEJÛ{<KlTk *Nq./Rˇ; !hݽfe>0[,UTJAdIEVgTHm%TRLjw llSjJ-@Uƨ RZ+wN])FXgґ(SrUUɊdPRT @j8rksQ-Ӑ5vc b37[&ޜ&kap@t)G hيKHz YkLhMmxbjVk«'$ n{g"Emϡ_xjiE0`78>x\ݽzY,9;ם!BodwtWw=~]';ZZrnRf^}}o {NfYB澇_o;R1)JP|,"܄%S|VF_ 9hB]:# p546ѡ\_D!X\P8sS_E!: "B5+BFtB!HB! B!P#aB!jcD/!B-}n?B!j$LW!B !B0]!B5+BFtB!HB! B!P#aB!j$LWZxXu@MO~R_G!%d_S k_+Y~2'w~QlWR9pׯ`Rnur|~=Uglj?wʳlLxPq㓶D)D&f׳ Z\{6O =+=43ݽ8OqOC並+`}}i TܚyޣW%#n͎<6=#,ʅzU '?|2c=9i%2`Z<CVrYQMO؃畖z/&-<8ݺj#[RX8/~~~^[܋zns_qn; W!лsopFg߲Q(hRXYTUFk tjzqpV g {r3+D!u-~4 ^쪃KO>nqsY5џlLqaS}qG=/B)x? ?5|veos'f^xb%I%}JɱCSZ/~5.\F?hT1_P G2+:Ϙ>s0x9=suSckN S%vHi%6zi3={崙Rɼ*<+@wz{o1NxL K]Zd6ad eɴsv(EYRt9u3:)1O|?=cO?Nnvt743.q?,!G:bt05=3 @Uʚ}Lںt .= 'ݞ8[m0zܦ)locUK"CUX0C?llJ- ӽvV+U &ᱱ*aZLR|yܤ3[@ G3[ZSS\˫gXƣQϦ⽗\~re.rENW m?7@aunj{_>suYgF#j;yѩ'"+\$VÂ<13c֐IVS\*Soי櫭  xlx{!>8G,] ǝj-1䧟՚`NfC@4s&"_mhZ$ {z~lxv6UR>i3멊BJ2rƕU:s[TAw>۝NR wO\u+%>>4U S}m'aUYVI[ǐMvPZK;ov^#jc^`x;s/;LZ^,WTRZ-D{p`;FjE0J {wPSC.Z8ƾ}@-?*x$ J~%w+׵?j~63DU}$U2CR,Zt$Dohm(p̆J /&Ӂc yӓoC!>p9^TX(,fBJ@lCN9VTBx6\uu(qf#@ɵDUĚ"Xl@)%wƯ'p|JR&S)Xt U)c5sљdEV䷛Rk$g-i{.yEeYVԽi9:12-S113U-/:%;V,$!> /Q lfk*V)hX=qI}mTF$}PHb,8@;ɒ chsKx`q9o6^)>:\B:7u:FRrX*d,sNBNK"h,&iZ[S[1QRA 655 oiwsu-]8ߟ}GZÅBñMWjzkAB=QR9#sC@[A  *g'+ Πabvŏ5~WM^Zf'u#UK?m:NY@M'j+m'mJpym{?RY+x'>7j_(ʬ1פc\fǍuk{  ['@A--\n :77F!tEk Y`YsǦh*.G9Yx.`7shM"k3rjlm|!j# ח]J29NC;lXښ9P}6嬿єsKܙ`r10NvDŋrK?m,[O|V45 j5UF L%%97%2CqfmIZCj5?qKKK3k_~9dR4$nAhvג1dhq5>Cyjjyx9,7) nwiޑ?RFC:*% hq›G霢Zgּ,RlmV ~A|(` SCy3?F˦ޓz5[Btu0 ~g⎚^^Qj>-N8YdÏ~?=_*TL 7JJފM-5O67|5.`eaj1%Nn7k yQ[ 7NhFÅZWɨyCfаt_[[L?DlSd1KP7yNUr0Fb8+7*t]gcd9qM"fi@DIph!TqՀ,<0ց^}S(HLtP@@)~=TAqwsVaEY^{nD)2ajgQp&"/)tfh>s>e2UٜlR}hPXVEi84,&"׀V;S2Zfx͡3ԥ#FZ>ۏŗ^ie @X͋QVzBCGNg6$SkU)-f; Ci|*3@3Ov9B8ReYta ZYe hft.]Д㚖}oLeQ94}W9Q{{\Qh^8ӻl}_c-Ԗ5!cMN f`#W ;E3GfvӛU8C!8D5+хbR $K(:;Bjk7*~)kuIPB4m'-(k5@-a3h@0:]d&77 '|V8cn1+[B@Q*\f/*WT&3[t%-]7rfpaϾs)RJIR6++*P9_K:y5BӾ+]Mj 0V0m6 љ'JWfmG,m'>i2:se%<y\I'a'ccc s5}0Ykȸ0?ݹkͽWx '𶀁-/hy }؛N'WF7ʔ5\v9_*! XBWj0˻{_:꫻ zv[Y9|.WJ{emu!_/~›=#)䳾/X!{A'c@}!;BH B!pd!B0]!B5+BFtB!HB! B!P#'2hO} !BmIB! B!P#aB!j$LW!B !B0]!B5+BFtB!HB! A X_G;5=7J}!;rήZgo҃oƔ?4lӏL~M3kqܩn u("ĸõVa_"֫=/ϹU5x {NL@Rnur|~=Uglj?w#)YX*֨l?sҥwBdrlv=+1;:tBl=ӯǸK B@oB9h].V(@m3ttѪ%LkHTT5$Ƈow_M1\-86/*Ѻk'Zᜡ|vilrFw{Ÿ䤙ZN=d3̝S_\ pjz΃/.5/jl%C5=NWdոpVMO|H:A 4rj vab~o%c E'~ x1Xͼ");;O:pf8YrR6tAS }ocsќH3]\dl&R>xK9:1:ID{{{ BudxDž_%,n$c[Fwoۚ߈-|>Tl wi`hq񅀧w+}g֕hu%'^nzlXyvO6x(G̣g[WlaяgL7k11چpյǿ܊ҚG`jC%~uDUoqw4X{H4Bٱźvjfiy%3Eg=F F> vs>84IT^k? SиEfKνbvmfvQ?]N]qNJ0#OϘ 3ӏ+f9114] 3Q,Q80]1OnfE1RcO2mg}81}z@pz2iuKe :|բ!u!/w A?KWkw;d6UKrv!gb%%Yz<(rPBj^׿P"626I@8qo՚`yKZR|4A AF%ʯm0M,- yf !> <u OՖIX/i!سH)e5Zi  ^J` LJ泊X"vq@FN.B{8p_}n?}c'g=/RN}|vlj=@B%(R*C_w)DߴuB q\pMn[9J/Ɨ!kt# +w+,k6λZ}1WtgUYCArpƅv氭*Jac53V7,J@`g\ jV߅ ܼVן MW.##-ŢEMйNֆkl(c{JƧ'q0!ޖ: 2kN &G65NPQFY @kv"ϓb6/7/NFJ%-{6dca%/Zzyuk;1P3KVPkLJ@]ɥ9h&v+{(bTv&jj#*RIOUA?@,.::kzDoЉ j9׶?->h9:>33>v﫢D:{ѬO03Rf8 ȝULKXTٯua8JۛN9ގa̶bfFKtA﹦ "fű<^҄M&v3UhBS69|&~h!3s?gl?BюXz2<\_wAK[O GϽZ !@Uo>9{\&Pkm]ZZY~rꓩ~S(<@h~hrLj̓gլVī&P16Z Dxl\}ˉ @</Eݚ&=m؟Xs ֊u;/љyyM\j=xAϧE p&4^W/47]ЦhG !ޅ#.?__cK/h~~gГmMV21Z@~v^)P%#%!d/: ۺK>ZWmv@XCii=tY<:\>N ?ރ+`Kw ";0dU}}UQf)BVFG-N>'s_ z^.b-}ǽ'B8b7#zgK% rEݝL~&>I肎PE`[4Zk Tcu/ƘRU 7fǣ*k?p'hF}TY Y RURUe#vf+pێW Oh~B&V헭:V!K#\t)n1 RSW짱j9st~\wnTU@cc Q9AU,@eB^Ƶ}^>u[Xڲf?UIV*U jƚ܀htf&Q`4e/*z"UWʻ\7B}fE~,QPV,zR-U @``Ze6s*7R`p蚂\ RJi9EMM΃0jb PKgJURYfkVn=% bIQm@&5*ٹLf'2'J>OO\X(1O:.ﶬ˱4i2>,ZS552d`$}#>L9ov2 Ebcڞ[N! 3rqE"~*zCG-],ǀ+s7v`6B l/]O_=-yvfG#q/4t) SB# mZ+WBw鸎 7! o@:EB!D!j,LW!B !B0]!B5+BFtB!H S_B!z[R+BtB!HB! B!P#aB!j$LW!B !B0]!B5+BFtSc#v*KUJ7Ogķ_=T!;V gZǏNnEVo3A#o[.5>zz$G9lJqcnfam3_)wxuRLͮgE4FwG@P7:v0pUػQ$>j$a^_GBG$g?`9l/־gBG1MWӟ\?MLϔ?Dg͘^V"#7/9j%ucF%'q5J1집1痂奕g[WRX~rd~HH颟nGiИMz8u1Z^ +;x}t穯!z㙮XPK3ZkP#_ Wn ķtCz1).lerpբ:ZόNn›}6hqډX[NmNSɊ{>w׋Kj>5;02֦f2UZ=As ssќDKwoxW]N-6]4zž x1Xͼ")@jr\R.j7WÉpXHTT5$Ƈow_M1\-86/*KK@kyz"3|v8ڭ+9=+!tTtdxDž_oZ{<&5~Ov5=&rH/<9.ܼ֩CO/6 ::p+:em>6Š H\~7mVSӏF+]urvG3njRbbhufy`xQ>Sbw ;s9`P1VSиEfKN@%~uDUoqw46mc/(5\U;9L@K/< ];[m5@kO/inC@/'?yrֻNgjH6xO˥!9JExz=v Otab]vM]Xzpݡu cl>ٶ}8VmnT;ݹ:h}-f y۬߮%'u7gm;\zN}/^gZ4.DNxd׺ƃ\k9tV~h )sl.P24=3UɋN=ɟYgjjϏFϮ} d Gmz% 0K~ep;MSʋ%jBրhRj bn;>J{G_!^8Jp`I1647كI,ju\&mgT4Z#:j@ _u8~G:-5b&!hu:5SvgQZKv(oڝ}d)"l{?RE,$FT)6jnP}&9ɏ峟qsjB+iewFkr~ښ[MXBz}P)DfV}ϊۨXYU$S xP!K7]mc[;d6B( j5x-T;9FV$޴3:auiR#w`Q*,jByDbrj N4<⃁׵?j~E[t foGдMUUsh)-:O^ou76 ]"as8Oo|,dζ=~47H{9@haݝE^\V`m]ow*}OB$8h1MˢRZ XUOޠS[%r4>Jre1%RbrnaSZo2ԉ)bM/&**\\Y.Cރ8 A_ŖVr]Y|=a졠6>)P)<@ թ匨"3ڞG1:ݹDQRUY,f򕗧RMT.9ݪ%JRERF6eZOTfF"WU _alS(>.z[N*5h3 h->yRe]H^T%y{;=B]IŊDY`D:^zӞ.:ש1/t0!u0_(M`^*bhn.pϞ[;űVUZUYCD!t0k_ޭЯ=~ ?5=qtcI/56oDˋo_l~+B_Ry r:Uz1Z!zӑAtqEB} "^B!tL B!P#aB!j$LW!B !B0]!B5+BFz+OdX'S%BS_B!j,LW!B !B0]!B5+BFtB!HB! B!P#tF_aZWKuuBwm+q_-Jc/)Wm֯t JU[;~zḊvD%W֑""bM Ѩ癦G[2@p("&"b:8k~wPL)k:O^'K1kiW3/θkfuC>^SK>7h/yz]Ϧe ,bUl\ "?;fڸMؾWMuV ~er [r7vl2JW+}')ҝQDjq#Nz贈aڱMײfY =[ˑ|j7k\(QkC3Տ7^ipߒtAŬ-lG\E~ 5{_uk͒6o;DkHNV^9D|DDpVE Pfdݲˮ84 i_Y٨CC{N+\2~)X$oA1elۡx.g_ZQ=Yptbç/-؛˺gXiJYW'%TU(hRUD4eXŚw75 =O'-~JV/<楜(8`>tk~Z*UZ.>yR]}\$gOT]Rkۺsi?y 劓ݺ}=#~ɆQZum6y-|ڡs[t.lv]}9騥(-;9(:+ WZC^gr ~ ^GQ=˽nڲ| =B >mP;k-}0bcopʍ ۙHHdnTظծynv(D]艺u' @O+=QWz*3ճӯ=zi=ԙ>}NߘUo`{GO2XwtDD,'օ1z<^JuL-{FjL=f_sNf[٦3^ڷuK[U[u(+1ˏURPĮ3պˡGSx=qzueiP;>kۋ'7iX/,2.!dɟ/͙Y$ڐXqHs_cF{KwSkΜWj]1oc“S,JuYpCWy_+f]َ jѢφ:fLAƼu.yƲR}6ƧlZ[?fĆhӊIs1Xk籫:7ŧ'Ϝj )^hPrvJ¸;x=J]W̺Nۣ[ƽݢYi_pjٝjFA "~L˺mT["^=ki>ҍnJn"bKm*ۉH~KyOW̺_ѳ֜u^y]} XKZ˺ݰ_KEDαJslrpt""{ߵD<^gڽGE-oճׯkJX:;?D6cpՂ#XջQqi?zSb_/q`;u{v%u/ƹuDVT2Ίq.>zõԝKHQ}+9kDΚT~w!O^ِWwnM?{0̳>(틸=Jރ[Q;jᨖk[GyZ ?y%<ׯsnȾĥ3fo^ntti?,8lY_z{8FzL$$27*vzGl\Ě5mr Q@]艺u' @O+=QWzT""rvkWD]艺u' @O+=Jy(槟Ym%]Ehybw'^4;W hغnG_4?~Zۃ@C珱|W?+͇ ]%3c7ۣ/iJ+kr̲u)džLd\L:l_K-'T}UeznC=_6&]δYA]?55vjϟ9ߺr]M1S\}5iYͿ/vǾ9>y?%dJEQ\\TmDDk=2`>祘{cN={*]3Tn<+6lc6}+z&zޤUW{وe53|6f̲hRC8l4oj s>hJR1*6.vTO?UڄO_75ʩUEr1ʩZꊈ![]WREIHJ+""אm.h~=:7s,+kJ\;,k ]tjWx-jnM7%dsu?/h  N>?gE/r4:}YR)F'E3V|Z]vkD,ڰ`[%:YܮY1r5ѥ̯㭹ٹ7Pp{Gׂ<0%\WyyFQ6];7 ۷=GCo~{OEDL{cjK&1^l>A,w쬇NN~zV\o:z萲< +Šihxx|M4v\EؔڵSg{Ok8unB[_Jq ngB7rEU=w연e;yL>n΃A l] TY-z-ݧvN4#ג7D.dTk d^-Wέ$nSiYWd)AoQTnۯbFz훰kQ] *jr#=v&a;#6.wv+wv<[{J; @O+=QWzD]艺uM8~Z=&v "]苺u' @O+=QWzD]CM dwXtOTqӿ՜oQ B ceVImcҠ$JY-EJپMw^?.y}Ts웽4~|kVu{:xtd]꽹: 1kkk4k"GN6&7"VՀȎ'.e(>[ϣkOYF&⤈hn\om[H ]q<[;-1*Rnneo?n%޸G"+1ˏURPĮ3kO~sZg%mߝtzs4\]:9;'OrT"1']5ܴc~Nƙkn4$kkV6:/O((ɺQ (`P5Msf'Go~-;Kp/ڜ:9gMY4dwd\=wٕ9v|봕o.0a+ O]MrmwŜ%7WNMϰ:y<ՂqݽK?|~Ժ{gmNXCIٻb*'Xz5]Zգ1/8T:;gFY:g++/w@2^{k`4L_W?,bܲdYLA1[3i۳GP(ظw;am1N',U-ɛ7%ED4S 6bU杈ٖl] qCgӥ""ZM1 {ۥ_7geE~6^8VF7_XH xe]"-i8|ΆӟP;_X7>.~';ܰSs/MK]Cb#vY""bʮҒ=^ol!lM:+UPz[謌v~+vkqhެaJm-a!ݮEDԀ3T nҶu^:q=>M3"͟4tLrؕ#_1mQtNwStWzJw{Zm\ph7]cԶ_z~ͲYNx?ӡN`4WoAx@Ic>3hDD,"%CZeݜxɡWpf۲ĕ("b|/bV̺\gC@pǬYw~V#Wv]|h+jQ'>iMtco 6rD; Y|H+PZuAY3֭q6Kڼ9#ph#bWq3?|-}:PM ~5480ӨzuwkJdlۡVεرf]+ŠgQ+>~}`]k'lbgJ*[ >ퟬ~V?3b^u{zuSDo/|\sJ<,R׶u'~b+ӶYnT-[c Z X/v *w?®vPz=ŻeǠuj碈Jݴ8xl;zuႰgy^aPZ(73lg"!Q!?RtW;Ck:8Nܾ+Gu' @O+=QWzD]艺S&?aj;֮E]艺u' @O+=QWzD]艺u' @O+=QWzD]艺u' @O+=QWzD]艺u' @O+=QWzD]艺u' @O+=QWzD]艺u' @O+=QWzD]艺u' @O+=QWzD]艺u' @O+=QWzD]艺u' @O+=QWzD]艺u' @O+Ax>v 8hPl""Hϰd˰yDUec2vs_]xdC]艺u' @O+=QWzD]詄*ǘgsw̤%A ݈WհT~##^uycwd u$&i6wE;)c_/wrW-Чtb,5=ﱜ( n[ESQj? K صb;ײLрH\{fI~lgVey>}'L$";VϏ:J1Tv˵󋆿}[KwIK\>m*24c֍}7_+rx3%Bqz?IDATGI\ڿ0^՝~{"bw)a)f'ߖOOY} !,5-v<>y .vz։3*cMY7Uo1sX |ySիe˩fݸyfgM^s(u+ϴ| s5F|9/._zygc_ ݴelYS*SvV~gن×["IsF~ymܲN?`sqkg3#}m脙O~JaiRBA).\2RoXůu""pj&LJ 7RTZ5#5 ߮I{. 1b΄j^|5 2w{׳ݳ %jZ^O͔gmcdfy˽nku#RٝS<<˳ m!""O# 0^w""WWZO-+%{ZS~:Qʺɍ4x"e,`RDDqeg]^OGήUw>ݦN2PΣKaac;8:ns/~Yjgpf(kHU x+P}{7s Vc=[_y 욵pnOTVEu+vDE8BuNZjɻ2Ec.dYD8M&kнK57'J-|jgncf_>z",:w6ABIyNa-)}[f7M۰x9x+KZھoرk'̼7&7/tnߡCo)CWB:k߹ӷ_68xu6Яh6➷U<úu:`TT>niY~{ Gr#=vVXN_Ԧ9R]=`ˇOYEmVIPjnn\6fKYfMuԸ#{}(JAdu' @O+=QWzD]艺u' @O+=QWzdg;!z6995)WE*UjiY3< &'_xv `2@j"HzvQru_uaUvQRѳþ+*Uklx98+zVr#=v +=QWzD]艺u' @O+=QWzD]艺uf(IENDB`kraft-1.1/manual/images/nl/catalog_standard_fixed_cost.png000066400000000000000000001263401450127457600240450ustar00rootroot00000000000000PNG  IHDRkO, pHYs+ IDATx^e\]{f\B;,:DB1APP,A;7A933g*+;B!Z!G!q B !&8B+LpW!$0BH\a#G!q B !&8B+LpW!$0BH\a#G!q B !&8B+ +,,LxP> Mx<^jj*uuthoIHH N@U W7Զ[ Nz#832b׷:2`|m]^:HpB!&8B+LpW!$0BH\{-3V$3qLs1~ U;^%Og- H'zvC;n/COtn>x`9jMb};=+7P]lܵ-ΞCHރӻ{l=cl O^ X9ƩoMyGݱ?$b}INāmAo>u;86}t;C#(]㾋\tH_x}xx}Xoddy+}Jj9jĞgkXZK$#l÷'Ar<=zmz|ǫxŁ]cL7^ pldFmg?pF,Kyk_tB`5/>=3Z{Fp #70JT[Dֳy-@%fm{["u_,q{2Foڵs.rB)?hЕԬ߯¯8$6DU#̝6gÉ;$mվ (نZfPJ-t)`)qki-yHF_r> -Jѡ< bK6iu7}w҈#'/c0ҹ ZVm焺Sݭ ބFf!z4|]1ѢCe $۵<=ck`?w+uYiiJ-Z:\qHlr$:Ml8*Vn)\ADR+w^M3,BR`+y ~]*;R_ll?<ӷN:$|BӼDre!Q/P:^qHl8KQZ]]ǡCy))Kn(G^0OrrܬlFiy%VJd@URQ]PThe"0@7>Ƚ{WWorQgˈ@ʐC>+̵)S~&eqNN  8م ,Ee%)W|$UT`d5)(٨(K'ScKBRMZPGgslȑKgUl0uÄLJ͟VmtgwP"ʰme0uci.M+I%nJJ @;{sߩIwv[D(݊ٲTUU5]W^Z`\ ߷pݠ[w>v4Ǹv*.?ghLib>_YC"_gcro^+ }ݗ.M*y9Ez:r_܍HnTD7~o,jkՕ~tO=z4e -5ZU뗟e|μE2>M)H(5Ҕx|qb| HPI^G4My6L~_3v %T-$H(`HI֧)3Zqk܌?eJ̱{n 3J0Y9-Yy`R9z$\ݡWK WRiʹ$yV̈{BD[gGGr^n˸ :&Ҫ_:Y+$/7_R" Hˎ"|SUSĆ(˧ƧP [[Lݻ! e:` Uؙ*"߭oN×ob>q _?JCO:L6ORb OQ!Za{Kl+9&PNDRRZj#Pfn,'mJ;J}{΋lmf,$ۺ$W6DYZHO[|9 rFZ2_S]60QjMIU֘|Wg n@Ţ.$iLt@IVm*d>ܷdFt:hgɌ@9qI+.梭溮O/7lP[^=;Yam;7+'eRPe9@7mCw rxjI{o4!!/tG~ f*HtfԿ.K+5Y)7'biRGq7 `~!AeeeOyB B7N iyY<,V-k 6ւ KhM4,B%QB rrB?C!$(GQ?]^TSrbGG}&8QU "zEA!0BH\a#G!qUdxܼ|?\V__8`p8ۉ/okܐ]qTTSRBB' N )u BҚG!q B !&8B+LpW!$0BH\a#G!q B !&8B+LpW!$0BH\ Nr1L2#8!BeHw(Y* N=XU#$3復yqqE$vG< ;4C^u bR I #H^%ojgp*8)9$>`/3j-{N;ݹ,@^Cg/?Rhg?=⼷^x'v%}K}ɽiRȡYީ)=4+ݼНcSr j VO2aSlf."]SoD(-?љy` Q<][8R˶M9cS%YjPtϜ o:w.zl, ?k[̟+NߠKs>+Z~g]V] }h>)GiF=<{N;.ŗND2p^W@q~ TV];Y?hI̓7nFN.G^GBuI {c`׮:9zԜ0x/nʳ3 N-%BLRAYƬNCU%@BKR`Vҍ{֓(Fzk< yX_I56TI(:idb[ Rʄ%1M!:IX3^E!Q63Oـ&;:p!Y*;Ckhsc2 #hybJoF4.*i%2UWuMu0'$?!lj*JNaIiluKhgf<46`%L"eBΈ>QRlVc"6PJNAs%MJ]MU.JA0it4JTaqΣ]&ܻ{}s"N$[)x`[NNd`Y E1BPfse6NjaGGg{su H)9~S7 )xoBxeg(6iH~wSWB)(~xBѡ=w)<%B}b$;\eJ{I=\=>6u].yBJnhﲈ5K]4i6!g6vFC)*hsVaznpR犋~ k$%98恎(Y7mBIV>3ξ+3zZ[Xt}ml-z QgU3w=NsA^LZz8Zt4E9a+{nw`mas³ *o۠׀[7fقId?gmѫǗݪH=&I.J‹8νNU5/]̢a{ZZD3u/U3 [wQmzO P\S]2eo% '1p 7{K{ױk|⊠V<8:ͺ{nCÏ]őzZ[lKȁ;Žxn]MVh4iu+'7@rtl' }bǜ|If쉛Av^Mlѭd9w?[{[=9lxqePՐ{cMݺ 9t\י'lY@ksݝ ,@aߵs%Ӌiɸnezwk !~i]d[M:uSo7y὜; 3{r;g_7͐kpN^s3/`>`;GI__{w^4{fs[;{r>iǼJHV_6^;ߴxP烰fgReFr;ǼcgbBt)aLjRoӹc3ךD ҩ[y@2C?qphZuZ244u3䦧J>Yw9DNǨ? dۯM+b]zRw,b˸ō[yVcFcV48󠄥ӸAC ~c@ߘ&tՐI~$,b[ Rʄ%>T e:hPF&'|EQ!Ǹ6(i=.X'*$Z J0knht.!Ƈ#&tѐJ:w}da-БJE{hUA} h2?}$?lv4%8=4hJb?=ee*4E|R&v`kfU?ScDM]&8-qbwG3M/&xq~Sxɑ'O4݃Ze!vݠe3}`;v51iEIw<|Kӊ)u;퇙ƦJ2esehךVdP÷8qxx\ S 忭%6 n ӭ@W'#Z򪪲eʒ R3Y|Mc(5 U0t_Ԫt1e#KEMUN>3?+=[^C|iM- E4RB !CŔ[,iMu:/;32r#D#;2,F ?C'|촼l_%AсU IDAT.wB/&gl_}3H]L+ h}{ɺ_:lC1Y~}~?s^]٣4 J/KEU}&οlfδIU5SyМ~IRWRl0uÄLJ͟VeQ,uyˉWUԕ50̴2+#-&B|3ʧm^&+#yiY2lT$JB0)ɩ*Ţ.?`2y,`ғSlUߜ!@QU\jUTy>@^UQ PcUqbҝmн߶uբg-5|`2^|[4Rs(E2M\!!]z_}ep>8ZACb~=C3HqvR ;r<:LޛmMd7MZ\JIEDB&v.X0_^M[gO(!I8soH*#@o.Ux|NEqt"YtF/NL) %ے?B['9ͭ{m}!@x /2~0U_Z1",]gP͈ ٶ왳-Z> ܦ} J<`ݤ CE,"GxMܣnk!; )fS,jTY}-zf^}[O\s"kVwyzoɌt"-%Ѯϒ$s7 t8 =W\k^;'9-r:m/4Ԫﺄ՞c7vnHu6풵n[NܳcxIl! -uw]/ms E'hȺErXT M̆oYNPU(shn>aȞ1iֽքj7ib-F;$%YT9YUcDܻ؅Ҵ^ TzD/sA ,N mNk);u,E!9G^I7<5@ Q(+lǬEO 瑷[o'X;2_h.X)!P`#G!q B !&8B+LpW>xf1oBDI1BGE3SSx'5ja\N %S lt~똘FFϫQ?^t"*aL%۪P4Y=]MM- RRRbbc[h(8u7o*r|?P] ZZZ"~vu!#ϣyaw!&8BQw# o:LpW80kMM B GQBE-ѷ'~XL>NY:,'|1L‰VVuG鿰όs u~PjfG:Ց?=YI.EA2ΐo[u9|{QZf3j:\e}?YnVN'@a̍Z{Htub׈Jx=j}2_ԭi?=KGeՑ6>2%8>:gܺ[O:{wӸ#֛5'yN(+T9jDBSD,E,P"/ݫE- /3sfB~藠TZYfM5j9LB{o g*zl:J L(J5WEPl޶W 믽+{et)Apx͵z.n\F,8 Uw*[j uLɉײ  1%+x)'mI󺣋m [}ʮ#J _w{f;ɽ}6~O߼+86nJ[.]gL eu7vyr}o޼E٥˂g~oP̢yujlnʛ}Ȗ2]<\zaB%ܳ[tW%om,=[AwxSx1WoIs;j$xm <:Uy}|33o0O<ՔDS7n[mcʂv4p^\egn^ls/B* ^l[ŅV.N7^,x-Ǥ\ZK6/X;bs?C&2%Vu *NzwZE_3EZ{d_#ܴS9hZKg0r4Hj[ωiǢe۾[ I t(+5ܷ_KEhVv goi5dl Աq3#!#B$&;n}&#q|WppHm6zRK^#*D i'Hރ;  z/2a<`FRp~qsK^r OO>O-YTBe)J /eVq|б×"?xoUVNɱ.R3K{ q[t+;N]81}MĂ΂TTe)^eY(˗9JoGNxۤe5bm@*Ge5rrP`5QLJnl@)69yUqQG.\p96i]wAe딨ߓ8imB9|8<)N{KfƋ$.RnFw:(N&>g50AS= _?BsgMI ޱrwH2Pڵ_T( 7opg|tYT=t^͎,0qL眡{;JXFn,kO!5ZV8ve8!ӭV5젢j*/f2?92OtJlk5I@kVqgY6m3pVsu՟R,xδR(b>bT.~]=q9cUK bkZuPi%C\>MHJ˰ m.4`iwirlSNh'չ&Hf= RR2m]Mm'T{oZ;Wj16if7yPX򕴝iA-c %}QUB5nuZ:V \!Pa :No~lpBi8,Y_c2J@Fif2 |i`U evm_RYcai!lҭ֔&a?~Hn cYiQ_ ģNee㨨.&B8,, yo_^l E]p)8Gd߅vrG=7,m O *Rp5/L8I*?287]6zɼ9gXq˹qʼzjc֫x5%'+kPIYYp¯T ΒVn?{Aw9mHW^Xo<s{Ȋ6OoyU0r~6X&> !?تZ/F]:򰍻߸.w0ӯ4k>th2~bGh1xעg3z[a}6@b0#kz%wSUF?kRRRbbc[h!ʯ6sm(U\e/跶" ܼ။JR z,;znՍGK_L{qBш}s=ޫB/sn9)νs!=qIJGQ;W6^s%a&O7ECo>U{Vjwq~G٥p"mBx(O5+D捲*QT=/C|IfKwR10`|m:֫c|ׂVaA].6(9 @ESz+:tYB~K>}6jhTZzHf4-]’&4N~#f*,VC&95y=,EL-[IX/79OhU6JXJꔬ,UB!3IȖZt񗊋ՙ?^}ZyaW Hi?8\Ļlږ$&[# 5>rϪ.Si!2[Ljirs?3-GFfhMm Ϋ|RFj?T|gC1YZ~ed8EEe"EEE +/Wa? +'+.Hyٟ}z!T]xUsU8BwϞ>ipofRjyx~`22ʺLZr ¦Xj/=l&%)UZ]]nUld,98T.]zHubX5Ly_q4Qg`i6k*1.t|doWijꙨ7xJQE[XS#ݰUs0ϯp I~$! j`'49uM>޴С%zȓ,>0yƷw5X!l1i m qyE/bi=[O3C;IRYD ŶеbM>mO_?^UK,Jz8ߥȘ-<4#=lxOYV^**Mdߵ`4"--ٝ$2i`WivUG7eNݶre, iVcP1iVbސfv1V-alؠØO ^y.)\I{ @pp`)0#:::rCNKkB?k?=z%K߽{kN.{?dEڐ~Ɗ:7(>op0XqcɍQoy餈MS>qsQ)y$mH 2w^.5ezc{k6I Oo(!ù $#bC:J7odC~ҵ x^M>]^~. IDATclڄ vo'ETL5Bv~IasRg6&8_X@¨p3)-{4/Hm z#~k‡tcgS4Pt[[lۺyf– V*"[Mrrxi_\/J2NFk"a exӢ$ iG&*]32*(`4Jl&‹9-VIAT9TT(BX4>RU0B5cLY6l #+ۦu눻۶nq"deRl%*[]G5I=Qa9vVP$΃/m]KVeKw|z_xEW*25kъF;G6l.U:qP BOndvvv׮]̛a2}', sA pNHhY1qʿld|)Xqm,MU=ԥ]:S@9|8<)N{YȯSj*,BN@՛I ޱrwH2Pڵ_U**!A_'nŽ)KOqÜ{:N8k|:E@,aFu\IއdC @ۭl|ngc PK.`k׭ń B$ _6IՖ RH*CLbS/ U܊llxLv^ee۷7^޺u+Q#+]"T0B(!ѷ#G!q  PjMM!A8..ûDt!$p!TlJJC)J&8B6[|*66Np!%%f 'JJlvvm'GZZZQQpLp EEE'$!&8B+LpW!$0BH\a#o"*xOkJNV֨_ !Tg tTJJJLll-DUzEAU] ZZZ"~v>8B2BkI}pWJDݍ0BH\88BH #*57&8B+EAUBpDjG)u3SPޓ-}7GGU&6pJx,u -hm-(Sț!$H\FQh)=+wPT<*Tc8t|K)L?OL|68ߍS8r#3ēF 3'Z{\"@2|<,FxDt%/os 0',YPnvvz?ɥL G9rp;nٙyHko>:`POKu\!{5q Whk;PMW 0}/ vvζڅOp3F[q#O5t땛'k<~V @rhиDqqCV-[^]| =ce'-!ӎ;Y5"4pCvL_{.%է{p&&8B藢lۿ0o1qT+y9M+vs2W5}b}EY)ɦd?~#y20cI|4iI-CDXr!UYRj=x@9`⃮m=xL ԶkFC_~IəwkƖ +03LG (i} ?犾]GUa UPls'ӝG? ͹}jw%&7-K\륝HXY,]}=l=F>{4@{V@DǩΉȝ7*r 2ܧ eii *S0}C6yɓ'iR\p=_ o;¡R{ӴDA[SIԕ ia~n?>kU|ʦiI=MT*A4MHEE7&8B#{xmBwo%$"g j dNYaQOS1mdJwB*)+Ғ2ZXήt=:]@TϊTlSՌ }f7 .Tziw ^_P4nrI $he3i[Zj՟],#;;SAyP{I#{n)9%A- ~f5=_T>΂;e۲hAvֺ_unݧKW_xQL5}!斚oި"h۶Lgun@?v*v&.rЉ @4i8| gv>tYUu@juQQ+,kk Z_]!ԴC .,={,QA=~߭N'ISuVuuu%X ssF~p 2Eş/~o$T/PbªfMpLpI>6[gW2B0Bu5oO5^fNF_ :0oM0B!TlNNI9J&8B:<orrIJJJ[H0ButܩTrE&mc#$)**6q^D!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!G!ja&t9aؒa{q7I@58('Y\I{aA{QB}-!T!T!T!T!T!T!T!T!T!T!T_!d%KB5 ?/ON^^B^dY#Q\^E/"/'צMm诐!= j.!T!T!T!T!T!Tlɂ )))eBGNNm=_!SRRu554$ O^^~brrm%4=@Yy97B}9MM$!&8B1&8B1&8B1&8B1&8B1&8K&̦$ߨI^)*oHrq~^Xdy4o+%O+1_՝U[i׀9uĨW2xtlk?qvVLAqpMG ejMC?=, ~+zώÕtה-X2BSO? !Y~vgC$bX$AA,EP"x/{}[̻*QH?3߾Q91[fuݱ<ɓ|ɉ%]݇^~ݖ>]|ivGLɮא;nR9}V=8 ?tDnp蒧'|8;; ]^{§Cnc N~two\...^~AOzWUkN!k>hڦU@e]M ΩLdի};:7%0ޕ P{h߫UӅ3CH 5.n>.\;1MZ{^/5[BBC7cv>+^~e{urUsOwExV4U"'dex 0j˞,_o%%1 PY! w+},|y>=qohL~(O-ԙqjd> JhWtMsvoqneGRېSv#⠯e}|*Gg^.< >r ϓ>{nD}G xp%Fswky 6mB\SMso4ɵ RW*L'zw֗!DŽ~cřJ:L,GUw R|q4۴OP{xGeX*c}l7cDTZD>m4 ۞D]\W>`Z$:ksn7AWemvvl]9 ѱ~Q}[׷O:U 5iJii2 )XeΡLqݏiP=RIEoRCK-*A kS5T:x9gѪpt9 %EŔ"~h@U) q׻8QA}SynqnOꙗ @iV7X,P%^rR\N_95WBHˢfj"$F*KeѠU99j$]+qgokG)|ۯӠ*mȩC4W@G(TnR-W^PTe^rbfNQՠJHt ¹dՇ.M}/7kNسAy"qd"]y#ʲ^$|3AZs)B!-(L7Hk}gWEW24o~BG !lgo:]nri`hHC7?=j> -+oO{yuBj{blon@uڳ Źm!^ҚC,E!] ^|HG[}e˚krgi0*pd%EBRNpum_f;>[Ϳm߰bĶrJZ5~VhmuUrSUkrB^dY#'$X[u,Eŗx؜=BKO7Wxn~jZۆs@4p!Kl깍fwAdi#}N7 n1A񎯠e-P1@{QB`/ B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B=B0*:&ݻ<sqqb>q)>T\L`,G*AߥIp[nz67?wm_^^ݺvo/MŎ$jh З2Ua@2M)5zL35fH$%,\ĉ|u)BSbD -S2R)j~M}r2b{4M1uʫIG\),OkβV\@MJa=}B4M?Q+|o}oW>{S(]pyԓVfӤ . G!9#FsRrм 3}f~T!_CsBo|6YI[0h47#Ե8{2!9 j@DH[*4_ .i˧'Τ `ܦTC2ͻ0öewV6nC~]v4;EX3^Ċl4clmlm}FӴ}tLoW>*7r /Bީgz c`ݫfnU J.ڂJ [>2j;: ?vط0v(?v7W+}ltg{%YZ-M<>/9/N-4ثsߕ@e]M 6MԫSS6UG-qt}zt*'wvw6snIl1zP7!whݕU3/oX`\iǪ{U@8dLoG'_7ʷdVy 7GׄH ܞ<38|ak{M< !;^*oNvgo>s%Q ,~#w-߈XLdZl&YJ(SGscۯl{.X}meOMq) @3ק_b7W7ta={,l"|g[/? {_֜l;isH`iڶϯ%:J!,3F0# IQja)mf,^uT6E6m. mdaJ &7GTyDT$HkۍUg\;2IpZ d0RM{xGeX*c}l7cDd1:vQؐb3H%- 5'峭Cmll-zz̹5q`cSX5k}K%YF]A\[,5q4 Y{*DM6HoF>*#S"T]%+#Qξ#+ a5+ޏI&|LrGrutCjz=2OϚ=$UFcWNiV3hWXLhhk<HU5 IPTR^I@heΡitDDzUJ/*+(mQ%YN҄t9 %Eh`/i4jNcs✩^mx?=c9:W#Z oHb4T-;8qhL ^l[4uZwr IDAT7l!w?*n_VN]}UTo 4kP]l9UuujDʉun㵻iIӅf~ E"]ϥ@)!>{S];LH~nP:-PU"eU4KMMMk ߯BT Ey9%JFO@(OwofwjҍJěR%;>_% ޔӭdE Uj=.iX&ga$TTe 9cFm*ul`eZNT5T']w5&@(*tEI V'_;w>_"::k.lvc6=]ZXDm) t+%*Բqh|v^'"5"I)7T A~GܱRyjRo#Ş}|J9 TgN^{ hS > سAy"qdZoP$T fVO^X?VdQ݊-Q; ѭTH Tyi >W-EiQg#3LMd^VOl*3iBZ]S`E]WIi$U")j.ѱulR Bà X~8_ 9rZN9!++].ɠin0[HQj# Zjpl}&zK!r=OZ|G^1aH܏+^qnYv.JAw@ n\?=TVli5ny@kqQVܿ&whx}^2q>-#Y?6 3X+J[5bS!Ͽ/]V$duT!`6,@>:f;[ѠktwK$Hm?7Tl8 h}CPwY,aG:g:*`MUɞKn~h71kxi -G gX~$D!HK6,6..)1iĈN3gښ5,wNЎWC4p!Kl>ۭ8:u}t%^\jNpjYV&qAdi#5%ࠥ Y9yy1?\|%)ReM;+#4o$I2NDS4Tdfpa2/n'J*N-' V JNt\ ((DXU3󫪪͖f t2"tZ&^dddddd$KjVX-S|io,B &8B1&8B1&8B1&8B1&8B1&8B1&8B1U6S"Il" 5]ge*+k~ eeٹzz:B_O5o* |#`B#M6Sc*B? vYb ;ד{l~@F'1H=]WMe se]lv?8V2t7Sl"lKн,ީGڇLQIBo܌ūT%ƙ;q+l8 _?x<'YT[AzdU)0"~NNN^ P@<=m{g,l枫l*'fˌу8;G 9.qsz܆qPn.mx[TQ_yatţ{;::zZpe@yYrQǠVvח樴l۱{d2@B޶uUNv! @$t~"l9jnH{%94}FJm}י;>9"?x{8/Lu\!ʹly1£reѢo(*+d^ߝaQQQ.c2i4k\~^T5Yy8+܋m NU ;7>7Ezr+~G/]C]zwӜy.FE[ѪAu]7F\ͻyG|@蘙[p]c0bʧ{~={غ; ]U^u*AGF !w*||~O%B!)%]"B^SNTwo5{ةcN;LLdx mjccWlZ,l[)75Wg0m>zrr2R,Cס:Һ.ctFǕҕB#X}{#Iܬzu[;" RVVlgիGw0ω0/8|z^iq@xP6VƷe0G n6G1[LM\=2 ($Xd}q|mfmg84E[%4k.h.sсZl*#.b@g>ٱ}A'ӿp+or+ixu˜2! *~u֝l|A#M5k+k6/ t] Bݔ /aTe;SRRި[; y_teVeiOqUvUgLʶ>ʰmWi#vbYXM1t}<)Y}0$UUdd$,}&wZ?9ݤ[GUr=OZ|G^^E Ǜ.>ݼW/E(Vؖ]NIvPTr=f0cPABw!m*?}']nq܁7E~1܋IWG^SA[vu_ajg)*0?DH\^28 KoX*_@9j5ʈҏ:@R!ߵϯ~u}˷E$)>!ڪdGR޴l'YJY7ӼΝ%Nuꨐ{]­ U+c9(yuA}7foM;c1NLiu[(ZK6RʷbQ"R40mkZ몌:t۫4tWHEaxlB2rk 5l;OL8hxӯ_Ks'8bjЊb|^J0 x*!!aXnӞ (UUԷ%$-ifѪve l#fʑߍNpRJ dTZ|_DsX Yha]OE=|G;X)@ti鴔z 5),G0XTU)vA!&ih}+St x|zKpmΑMZ7!P+)9٨+K]ԫr^Uk5X[[5&k*O.9aɨe}]]_^0}Vfv* ۾koXF j'IROOGVзٿ=)P# 7 o`3t<_Ku.yzr2JDleW-2:kIM`C}=s6 T_Fp;wpUO?eZ:ra?#i^eWj&n3KUP`vߏKungTHkuhM ﭟ>0pp~zضußTI=qo^d*SB6=R$dvY߼/awoý-g-lF[8A_ 'Wɷv|/#i*q'͵+%ӂ}Тw5Ya'Z>#}0ztaf $@1Nz5ʼn\`:x[Nۊ^[ 9p& 7|9:sV[+kG;F cOKP6lȢr..^mpW}"ƙqٴX0}ve^J&њass_kw% xv=k> TzԮCzR^3tЖʿl;n_̙tQ#6Cl*?lӲsw[?qj>z]h5/] 3J/O-1gzB*zV{/ké⦦U=F-gPD]uJ^ز 7\a@DtۉFRy+Y5~}Et524@vy=}݁>]X&-Q56y*5'QF[Vr&-^sio=Z Dj.&IXB1᳭Cmlڑa{ܛ-O/Cv)?Jr)G8mZk5\v/nïYy9@w!ekۦ*?&4 DO.zUDI4F]A\[,5qUЂWlA> V4ntgfC'zBou+8Q_JU=ٺ*-"e6lmOߌ|" & xɑ ԉ~Gb;5`@WD38K;烃/y pd9TyyR2YTW@ey%éY GSYQ/4[5-v'iQ+9E.]UAkk BEV;th r#k 5~[_K;Ap5 {=$UFcGӤVN?2{_.cgڹ(nx`QB>}Y9 ^ *Å*/V5ѬٻIM2Zӌ=!G4hڜ.uMT[[?fmEuj:bUyߛ[?X{3qIi ]YGpd9 _{>ʊJ#8rae@ϑH+~2Υ4'L\ F,6uskԓe]_[>.^g#TֹC:`%M^xTٖt8.xL!v hZ)?-ylsyTT.TnV<@u8{nlxA_=*8颿kuG];sT7.{ǖ h}.iL{ʰVFZ=I+3EP42Tai2 y!,(5c&J&Z BA7"Aǟy8ϒf RVJL) ƾ1[ntia۶4寯D<PܔgEU4m DUU4*ěĔr&5^rU @U%'fK2HM cVu14;zywҀQ1;JXQduwS9z&=zWلt[n% GGAGDTYCWɵH{8W^9|M%]w;l;Q0t4g'q; aHҕF;9߽4 ) !ݥ]Nvl` 6Xx|QW wvslcݜo.s89><&d ,t[b&%aҺ]=/ZwfU"7Nprrv;)XZj=ٙ{ﮧ5=]q#S ^yUҭ 6svۖYMp`f9^v׆t%gH!=s}B'ϰYF'&p޵/lSD!ޠ`m]!~jl:1mC=?ZK6RS)BDib IDAT_RLj͔#;% G!G!G!G!G!G!G!G!G!G!G!G񨴠I^)U /Ͷx2\E/|Ѽ 3=+$-fYc&SXo s-O/~ R~gѼAyU.fb3jr.+>>o_pw%UJkG߅(0_cߕ<&/@ Ccm2 5|y%A4|\;azr6%+x|zKLTnm{u.MZ&*5"D]=o\{.=z5ƍU[J!->Ky']Z^ֿ >A|ߛ(! #wJ}MP Gsrrv]x( ?.Ύn}W>;cg{&0ܻZ§C=}̲4eA}\\LˣwWVWaqUT޽=s}zx+?:~*㨯z @]^=md>nN}/8oO x׀>;T>8opg-Yi95nTj84j,Վ]s$8U^W11ӕ`mGB@+,VҔbX,$0VpQ}(~aC- YTΥeKu$+~CQY! w+}NIY˶/M]aMsHօG{ojhpWzK{Ps_ϥs,~K"ufχ>pí*aƇXkϓB/N]uqūۯ=`[tjCPyK. )ރ&y+h~S#wR9=ƌ^`͐GO"()<>Yz޷d}Og[lQ^N!O_ o9L/}@QNEfh(wN>ii-9Hw4" `hs@ۮ;򤴑-Mm5/S`T'EЗ|ht{yoYDhh uP"j'I(=:rr4~e|͇?Lf?2};j'iɡ5Ks.*'lF/o)^qL}{E,;qOs<*}^E594=fe>9k0OqƉCcj_6q vMB^[[Wz.:ܡCm9}XOyWUT$IEe% IEХ/C,'XDEvLuCT[[?fmliPX󤸏=zI$m0+3weJR #M${!~"ݓK.8Mf=ӼUi!Lqɴ9];:(Ls9нtQ&y/&8BH5M5K tiNv @j[X`5l밿,h ㄭE}1v*,KUCUqEW@ ̽y~?c~O!^gt?Rcy|}:)H%m`}cn5=)U"bTn^}nPCH22loAOP#+xoDf% ۻ?7p6$JS% ( Z "RBf-S4no@(?6N/PRU*OMMӤk_;odVPTY֋n'][w{=;-nέ?=j> -+oO{yDŽ!1Op?{ŹEvTn칤HHvvKwf_'kEy9%&彼w7/jߙ#" ( ܲ|wݔ_Z}tbEB-eg̾$yNOofK2ϴ ?+`ɩ1d_#SW$YH V%KBG z@ƦS~ݎb-%K!DIF5u^j͔#;% G!G!G!G!G!G!G!G!_ PTZV&9%//׾]&{O&8B[ILLjaBGKKr+;;I6@ T ::ڥ &8B1&8B1&8B1&8B5£G=z,YL0BK=zxB?$nB"= v"9R68B}8ũݵk % ' n9@LjǷ; qLp"T)'Ϥj>3t}ڬ>L%U 5ʺ0á〭5۠]`Ӹ}=BKq1kJ>_}tvCe~ߦlzI"R=nƴDFbPhuP3#[Zu  lzy؛[H(96AhnA{'U"ekwDoQÎPR3%$4tx3yZߥ绖_JDHh Hޜ ΍kS|ɱn'jcc!ʇ7{h7}sX6.>u70bX;%HnNU2(if ×RkFOrξW$'Y*gŒy=ĄժۧK%dk%86y٩ǎO"l +x&8IwZvIj>m|\Z[K%V3^ 6D Rf ̹vtkbZ8ΙjT\-vZ%E뒥JeْP!K"KDBJi_f;c*>59y3g~9x׊xti6ϻɉV *s'sNv;;xo_0UTai?l0Q&ۣw䈋td::hBӃtR˰[O98OڪǞSP;t#> 9M #f2hGYpƠ@WNTZcڒ4` pzDLU3%P B6ȊXژ @YQH8{S޼^* @Zð OiN <{?Bϝ?~:4dPUQۏ{OiHFlsZgiFێz9|~v|CUU}ݟPV,*I3Ӛ-Z*3zwjON^ni׿!3Be/Ox2x^S_W}VPS(`ʪ+ˊ8]z7wv3>4 ̲oʨɲ ||,E%eNrr^/VR6IkKN[If={~f;C! Tkb⻙5B!Z:a?q߀ B׽{7 !Y~ypT!$0BHRa#\nnhO-77W^LPS162JOy6LpPS!IsgR, BI*LpT!$0BHRa#G!I B G-VhBH [B gQBHRa#G!I B !$&8BI*LpT!$0BHRIrSy ||BТ5_Hu~N<ъ/G& >QJu‰cϪD[ ЗjoWE\x&Hzc ^ O =|04,Ѻ/C_ܽqkV Zl+3B{d.rQ'Ziyx&~}M&PoIUCa2ƍUЏOP(!*^7=uN#퍣o֍f82*Nr=U@V˸ J"8z*) #} kꩲ뗮S*-tTf|Ti3/^@ {9Wʋ0Tf9 Pؿչ5:t<$|=}6PvMuYH9⎆LXb$+RBF! W .I>yXї3˵:vKtEŠݴ>ૹ. eVurRAT@e_?[ӹ{ke>C &9&(I 㽪WpTV!+酄C%!99E|m7dO^-ڨ<̬bv҆k2m:17P,O=@do]9ʿn+'7R'w+1~ڥW*'_;\T,1dkgǧ=|{!gvjjշw{{{|EN7jEJAw_]AFVCS\LkBJrwyzQ/}xБW9 WN#f#,)tk5߻}N6 #jg_YRL>o!Ee{7yPzg x(iҬ q*?)ɲ]%4vu~ϡjIAg>}/ 3x}S19xhB WO\>fՕ⚳s2u._D=z5RUGsӓhb]2T:bԴ4ڭ5]GOiωpj~VIV'Gޝ#wo˦=Yڅu/?;؉7lъs|=RQUH@0nTioX1yq&j5`j]߭L:K[=\sܾ 7n\[OMaa AaV^qq->3]Gt?pzb}[]S2`x{hҔ{Ynzk)˫A{N]+égug׼HY96TUVSUU*u0k?@%=c3̾߯cwhY;ٵK%4CzxG. ,}>~~ۼ6N) Pvv>XQk?^ᐬxҲĔ&r]]UMHtѬ/l<8!g-M+@YsYtvZ[Hn@a>H'iu@k/4~.fǔIFaoEw\fT\ݦ Kp(xYێc?ۺTMdN.4]ŀُ 8/.'jVZo2: rO;y+3eHr@Wmk3LYJ(&լ ^3.Eq R-kW{ɕ4]~'=aRF5)* xO.z^ӕ2pHLIfܸ_ଣERU4]v1 AiBVAVXH4TWsVZNV8fUBJU>Y\𑲪GOyRvmC0tuv:s4!/%EH_HL]x gz O-MΧ"=x$}yʚ}7+zY}>9T۽nMDzS %qEg{}$ dR;YCFUK@Z|s^Ju+Á>kңM,}p[Knb~7nʭ1{?Nm%P&x-RZXy7$ca7zMR9 tu7=B٫J~Jӌ= }ܫ!Gj x?B7)_LJ:+ J %`hYl6zx^ i;U3i\Ju!HRJ^Ru';eIG!عߖzymr<>hRZ@+ E%E*yZZm $WGtv)ہ#[1)n 4$_>7Y7Ä@]w6n(x}Sǜ WT̻RbT<}TʸmACv f}T^ж{@Hu1A_깸 E6";D5i^V, HZ{ Ϗ=w2/a@$qۤp&*jCդ6 g{o@m,[t!%.KmC4I(X&7GQzH^{!Rؐx,0V5v\xI?E݈bһ VIDATf 9W*4t]nƾ-[rf[L|\|ޘqwRs̞c0edkxL[QMY }/p{/R wmφf뇷!Vlb56jzE/|rf}+v#"TfV:'{4>2Rik:l?GczXBĵjkm<|t쫡vwSK(̸S5:u:  'usڮDDQqhg.?eiG:^CQ/>jgo57yw_lV߀vncB +^lW"WKdֳhgj\!ȌݵSݨr!ӗojuW_MsjE FM9 teV\F+˙s>서ق D Cwox,n0p!EA !$&8BI*LpT!$0BHRa#G!I B !$7HpY9ق!>[9owQ(̬vB?5Y9N$co!}@!`#G!I B !$&8BI*LpT!$0BHRa#G!I B !$&8BI*LpT!$0BHRa#b O}\'ŖavPTTK|Gi%Z{İh]%, BͤEVeeէF-7>ޫcp M4-Zss-7>W#!$0j&=9d1UH1] B j>8[18BͥCSE!$pfBy1GAtxxxxddVV89!'%wja#x]ME+$MAAʕU봩&F&PAGxyz.ҳ"{L^0;OOq%K>zL nY[ZQ*8bAiG^ E7NtsQUCtM+<~ߺ>utdFǁ:8}O4^r(B̑?W*qdj ۸X) NVg=V1 , ,M~]˷ |\,(Mm[K ^Çh$ߩ.HwD͖&R &ND2흝{^Xm'߱BX'7Pט=ǧ^u5gUHrBNI(yW,zL+E%9}Rߥou)A:٥O~zZ𡙙ٺ^Xny4} -˽q.+xEVVDޛMM޾`EQi;ƒ44M ߾f,pF-MѦ5[B~w7<_R\JJ'7f(_QMkSn5yR\Ϲޛl;RiffSP;0a_gdVɆyb|UV6wFFFIvf*xYetdJ'D] vWfQ!\早Yq{5U{a+6V{Bhtkm4duqIvWǗSA|?^U>OXDQqhB [[[:uԪU+ъFMg<} [η^#~DA88Vz0j&eҟm;M6ŅBa#GI1, 5p3ao|=#LZ`\9d1UH1] B gQj&l6;//WSSK' ZZ{u;5ʊ ъ>%P\{&8Bͧ\%///&ZZo|.' B ?D!I B !$&8BI*LpT!$0BHRa#G!I/s%ld$IENDB`kraft-1.1/manual/images/nl/catalog_standard_material.png000066400000000000000000001301351450127457600235110ustar00rootroot00000000000000PNG  IHDRkO, pHYs+ IDATx^uXMwȃ[ QA.PTT B Q h8v?NNA9=χξ;7K0 B$0 8c +1 Äa gp 0a38a0LX a&p0 V8c +1 Äa gp 0a38a0LX a&p0 V8c +1 Äa gp 0a%h_YC]?/- ̤(.CZ"&&Ox5B7}GFf"_'++۷ P1Q!}RYi kr1 ð?gp 0a38a0LX a&p0 V<ۛ&H T$=n}0n<;:;DQb!xo22蟃r."EU'T:j $֌4iG]1uCFNR z+4&TŅ 0wacgT_Jhk8z5<͑i8dTqĴc4Ƿ5*ĺ0ٲY5Ͱ25{ߒWW!Qns57Myng$#=HMߥ(µjDM>~%7}Zοs'MEkI|iem)vBaURDb^wҭ7zdܦXMNŕ_{Ju=^wo;4cgs 1089Lb4Snopƥnyp|ɹEeHMzg@y WmOf%ZZ3RVG9 +ooXJ" ;'G(L ]*bk5+e(CZ|Qyt`e.zRp3w2}>˵t>.ɗS%ϰPi }*.';x'ozm5QO1RV÷sKE:=I[trQN~#{w#"ac סggEEҚ]lRi[Y)_yv#Pn|k+4Tž J9ڶ~AY]n֝kNRNV&<)7 KJ(껏hvưY~j,]yƢ^:TƽSOz_$5|FC7g<6Hp#BEmտ?!q~!RK9nV.P/XRm,բ:1`9UtEYDl˷J?? %nJsOn~R'OpS'fZ&K̞^;+Ņ&mo$E0$ ƌKI\_0t؎|'`9X_Eyв 't( ㏝<}dqx(+%˶JaӚ)>dNKŒoۣvBu(?vߖhr]Dֽr,klH ++͐WEeދMҶN!l8qJKYaёp !z?:|Sns(VBRyӬia]']/ݺTVWҙ>Ä#sԣ@Ż3%Y05=-bMgj E<3p ܸKṴ̈̀f'ixjMɲsgP,4\WG iu^ WG)fsa=m9]숕NIVaU7y)po:t(8YPɺ$Bi[f(om\FŃÚw_52i9~Ԯ؝&\wo&E :jJӀh@ '!cb.FMNY5,@QKl^yn !m+Ehg֞oT<5f`s.N[OJ󹭧bjV}\OGJыR-դwF*$ NUM#nۯk ( 膎.RRz]$s|c"JdʽQR_!me!Ftes[ػ/qZtQ&TjIGVQ r(6OlgLqALE].QT7 ܤ[Y=<0HBLрA2Ti!Ni֐3T]{> ʠJ_VCBuŤz5-ʹ2(V]5ΚbMKoW ^9~RZ-Zw2"@H4Q5DG xzJ,teT_2H<;2GiJ!]Ti,YTXD|Z\;#"//S^@ 2rUqI"NsljD8 y9뉔WGBDjy]$~䲳lzg-p*忉<zm$R˝TTSue?鲲E<%xa-+Z q Zmb䕻Ŧ0'<^'E$9?|JnlZ~;̩h#-{I'褋\2f NPמ.+/IxkRJ¦ 2LB#((}wax8⓷ې{LR#_W%G?{C>"i9﹆5VrrzoNAq Uu*kNT:l%(MϠ&SxgwlNUъ'fx,^8$}sh֪wmPa~@TǢu:RLYѼ\ iܜ9YRPzŦBɔ&"`@fLcjѵߔ>y//lݴڦ*!lTňOVsY_@6U"̠1de/t=\QB!M˯l(T\k d:۴?Ͼ۾WgysǵeШ.[O ZHE  [BTI'e[9 /a@ =jeKwyA+÷-8鮽6H~a{mpm4c߫Uqq;(9NݭN6ڱ4ygA>5MPWp+ ?߿v?[]Gj R) =5Iw|*LrS)n޳ZkNZӍ-81y ieKoj}ˤKr=X@9fpDd5%)͐*KMΨZCBl =%1*2ž,Zď"B.PEO&[șڵORLO3xJۡl9#n~!ml1|cNR‚"QU]- P;R?:|n 99YQJ^}N9@k piTdBֶVqg/ȭ@R~'Mzpέؕlյ (V^VVLP#n dS&!R} ),+M3L_]'[1Ж&}ʝL<"|r ~rrBBi=ZP\U,nk@sJJɷw6zWY"e2R:6'kY7w񃛧`qD؎[OīƞMTs:,آq[JARc+9e!QQ16ӀPvyt|儍#;^r}z=9?;NRB\^:&yuCOzS.i>xj 6f=q~r:vCiWC0mFNshɘRQ*L֤#ӑFivf;ϟ}NJLS2@_9q;oVI/͊?jr!JP25UBǩsǞT6ke}f:w%MJZ[jT'.[45-/j2pHts{@0X1-Tr֡=o,ݼerWjc65C]IW/ːW6qſ"y|X{QsPntܸ{׃~nARSSGՄ(B'3#$%a Д(/[9TRHaǟ4m|aXY 0 a&p0 V8c Fx'é(,,$%$lO- }/='7aBb #)%ٶu1t#|aBBs3(a&@vVvzF>A0 k(E%h a&p0 V8c +1 Äa gp 0a38a0LX a&p0 V8c +1 Äa gp 0a38a38*f5D:_a&)k X-!Ii[z6T^#(7!8aOA"FS??&N)6ƒ*?F ?a֤v ^!"ewzZ!dyrD+/r*Du5k@qγk󏾔2{ΚawGNW.ْuS twD灢IY)׺yQ7W_;j`^?K/մxqWN0m8qc;Ӳz&!#i1hF2uN61 ~MӏPe ivJ$?9s姢n];Mp^L/i^4 0,:{oo(.+F]v`Dآ!gI9m+®^Zpt۹d^9;._4i[4Pw[GSuEHxEU'1ս.q015}<²HQ{y~j4 }GWCf} $i[[s`*/"*V/i,\IAC ĵFPzt>/V4ԕBRnF6i;_;HKQa }GY( Su1 ~EϢI"6'? /@NOjgH%UŊ׹ňRJNN2L$CVw3"IP7a**+dQ44=r@O26/B#)6*+d?з*)Ru1 Mg*~ﰸ'y[*gr5 EWT"HQ+@L"d25Vg?>ms߮k[K'|n2MNQNn5Β5u1 CϢT}~&:Uh{wAG@9LDyJJBC:IHVn1C@[n+w2Bɔ|x[U aAӏ9Ϸ mqE G/jKF)4%`jW)ox>!%Ӿ{*uNCz뫗eH+w˪7H }nzL۲]]8}Q>T35b Xz܌?ڌn!gwPyð^}Sh3) a_aozLͱ=a1 Äa gp 0a38a0LX a&p0 V8c +1 Äa(DgsKs<ƟH~E?z~tCU|wǿ}{sBtOγk6R1rXiEA SܖA$4-Ld*{#ttEJ^EĊ:$f=mxfvXsBq0(%rj73Rf4CݪbBGM=~:[¿H#4cgs e?]͗6Y!sVC3 6Lw%h`]VO {!T{~'BDZYKZ!Ԩ-]\I*R ԉCz8p#7B%?ǐyAr*ùbgsKɕNu"n㽝\'T9[Iy}7qofUwV4xѐήg|}uiAtyGέeO^7cIYԃsx8;=BM^ϹkEuo,Ϙ{ wus @e:ywwG[>vm4nʦ*pۑ?SչU#\l x3@qe=>fª=|9::z YpYo7v6Kn>k u# ;瘀hk$#w,w_4֮WS!_\4Gw{CV֫,A9!}w'U37l}:kO [5c~w=, y},me\7ԬG^%s3Y!=\z YLrdR܅";f>N=jAdݝNwڱ^.VCW;Dg j֌}@e$Fۙ+~w睖m弥>[Q]Z>]22M?rz[jE߈8>[iteu3"J4+ W_Hڙ']V]u- ݽ( M{-wjt?cOLik[<}9r'i&xU}ҁ~5NַurӶ]q(ˁGKH^F\Q:yvS+?}o^n޼<ÕdPs#ㅧ]YZ?`QcWc6Fy,%O8aI6<{6f_ͫ.h@`Xt-.mVYG#o\;5[Gn:QSvtZq)AgFy ܼцVw?l}_v\rz#o}=Mkol'y[C קUP_B6ay~zE~r.I#ע.jG%)¨w _~qE w6nشB38ͭݦG*[C:Ȓi͛)Ү[5:b-l[ {8i@W7EhT2Up㾬0!4ȳUuAw==Nt!μq*Wz>#U@J{AroU)FvUzo\KpFRuIuo jck @w//J]L;/3? bg*%!N*:-M-ueDjmiaJ' JfPVR$( nvJކb_k>F6e$jN>6vSNNjReNw̙ƴ^6w_ b-iʋ>KD]z$XƝZmG*Z@SlS]@Y2֞օQ++zjjAp߾d 4ɶgY5RF[[2W\q6.Dl)AM|pvolw:RQ\T IDAT[{#9% vq/=J ?MYo?d9Y9Kms߮k[K'||3YYٰ5Z I Ѭ˲"##O^Q$uyԵs49E9)8Kֈr6UwmM9ptRrǮE؆|\ LJ֐u%٥sBtuJ.L " }ޚW9jP LrQnaA_H*>bkxVBT~N^UeP2wK+ $,LJ׷&-xLtrk=YQ#7=d NAʋ7BBި2^9hv9\N)GN=IRACr8埣O^K%-l&;U4Jp"ha>xwU&/ծTx;E0ħ7I%5tCua3t If߿r'SpH{8w&iL.=\8M*PPkv":Ξz켕ZJP_^HNWuOSwFH/mnRkN(<@gD ]wOlʴ*Ch:66?fQ@9s*rRIzkATyb6RJC_W`k]>u>N#g_jdC;b۷xm{ zܘ DZ-4(@1ݴakJW|ҵݢI% 6nඦ0fm@m)CL.1|+jY8mziv3W_,ض(DRc[fy.qv=fm7QoOFBȧ3a7thĊYn△^׆~R:%Oz_{,kwtf9">v2"-mnN9Qe#υc .p|4AkWWq_!%Ռ/o"ޠSU]i- kCAco _"hzڐHkǎ)bXWFyOh눾gd$ݜ]ZD}nww>{HD G7=wž%b{wLT.[lk}[RCf%R*W܅dmNCsQ|I pRԈV^ce[TʑaO}#KaϽ&&(w9*q8"D_`͒ Q0 /5s=W y [U<\Y1:㗢B_E0 c, a? gp 0a38a0LX a&p0 V8c FOngTly s4Ⰽp8<-**/KRBBmYYߩ3qm5vf 7[GRV>T=~TSC]YY׉ڶe0j<7kLZƅ8}cP0,. "JIqIvi18aB5Qk&o7<0 V8cVKS#"Mt8c +<a?<.,ðpiMt8c +?em6 y3:TT%j%y#{U#,fzusv|b /Je7w{7n^?/hv޸3G/>FnQɗL@3/:?kĚKl;=wgfxyzísݟBJ$IݘuUh=\F2^vLoWn}&o\Ts#KP;9: Mݙ i =:U||NQ)GG޺cU/˫ݾP9ͣϸue!{wpùyOT>~t PFzvy~{O'/:ХR'l-l*J+cONƯB"*y+Q疛۹+Qq |"bڥMC4Kwl+'J]Kg̪X^>$ }JR EIDQ̍ʄLp] Ͱe ]{Z'tksMIHَb9Y2ح$ 6vF95&hFL*mۄޭ.|A5# Kt5eԢar_ @!nNV.mh㼕l~q1UHn%Bw,( S=ֲ /e;φ: ڕ_fo,XgeLаa+KPInnQsd5dI])e;*ZYӟhlEw/\}Wu36}}8cW*| kh:U6NJ+ȉqd^HTE0sЊXr6_06C }fŬ9[-`ɘ.#lrpDC|3r{^XaQO2$tՁ-^YeKXzsֵn&R#B\PDdD=,k iI-#:G- }z`XfL@pR!u6w%DX3`Š%ؕ󴥿. i9eеˑ4S;kTwآb6NY#N0Գ*G&B@x)x hmɶn)q6SWRok _Wer2z^ʫP4鬴2ȚYߜL@T$Rvʥ_^#K{caBBs3!ѿH}cݱj=G3=C-N<Ыׯ禵ԭ/%DE]]bbb r/  BPIHKK /O?̢`M =;v0p9X=4} h0gQ0 ÄՆP~Z7E0x aX-8yo:1 ÄEE6!fKIQ$%%22ҕU ̔aG?uZaĞG74|ebb]222Z鉉Urjðdv`TTT_Ѥp1 `08a?a&p0 V8c +1 Ä t_xaX#k߾QCc kJ߇.f]]f<¶CO +[Ăv]:[_O-ou>CEoίդحktҏQsZYXyMt#>noci༠G=B-NcN61 E: 9>\͛>_'b_Bvr[t[)y2B.\yf=Kґ3[[nǨxc>{<1y#zG49?kyM峦R C^@X1dͩ- o^h"twi䰥RO/[l_Ȯ 6ۘVGv{ A҄)~SyoFFVw!hap $ɲ[~Yd6nԞzu9OO?H+ik\۷;O=L-6uro:o,vD}J!/*d /ݽ!tꃱ JEԻ\jp{IǖNST.iʚ޺t1llj{jG _ \}/NNۘއ];RE $2ucp D~&{v$Q O><7_gq4\ϕbKl6!gADs?۸I>"ZjK3}VmQn;TZ\JדH0ԓe#*7%$FV.魓rQȭ{wlC_ꏦ|FH,{cgwϞkbꚛv쵑cI=碯nDPqQa.VnC=fꯨRR\į]$g-@q+(6ץ'ҕBeCh c{pl+g ֥ @ۮN`3U[ϹH0 j7v`;iZi]ibAAF 4RJTV\,Du*-)ʉXiI UZR aB\B*).CP`z{GwOnݲ, vďNmrO?$}QӮmN,SeeTOUP.0y?eF\LC;}]<mFɷvޣt=2lpS9U,GM|L\.WTB쟝o?雮dp~vjrֲzP/QW'r]AD@So(`E9QWЦ婑KPQ. 3T*yv9%KʞYسR djJFe=yQA<~Жlwibد8i* "m}IDoY}RuFLkio~q6,6ʵCui$r8&v^WҒ>?U)n㤬$kwuO+Bt-c;Z35x\Xy|X=LHb{+#lw}c=kl5#C< ./ZBr.u7lllX=ܾ}[_A]7516PEixd/*y$ϹN_Ϣ`o'}Cxw &j,Jһw6mZz5/4ɿ3ۯ6O`X#JLJ?a&Lb+vN7PALgj/dp Ĥ;?WWnnƂ38aP=yvɺk%&%_9BW7ͪyp}G}SΘ6iŪU.]YY٩S/Z }\;d5uhK%J¶m&uqvgL9V#퓚qf2X7 ^Ԧ'*u5esE*bWz_0Zmd/,.7ʩ[oQCJ=6vg>OȢSMTO5?q061qԩ3MwK-JOO6[/],6yvҲ5jG6T*:{O;tM_vBwێdZ";ޞrR6 ّkZ|/`ܒ*PG{HwlCD ('vָo7ۯ7-̇Uѧ Ǯ k?F~>a?+1)iIÇo}ǏO@kF@WuSyta1*{p9mh/=I6vot+6CG)ɷw1E3qSs2/&.4R_~48f._\L!1D&y}|[HF$ rB4]p0&M<}֭hoh{'v-}󠼜<jTnV.!˔1ۃF̖΄%:uV( ȳLy&ϑ-ފUY+D/ˎ6 ef'2;3dXsg_Nɼuv=7pSNE.CN>v%ض!nn_+Y_}*@@v6U|y|R{;3i U,-KlXRɝ ),;ҺwUP3t:lbuoN*;nSe/NYsei`W akђI}Ju+oH5!,6@yni˩cUokԪ (Ȗf8tuK TΦr"\K^Bs'5 @d啛n栺7j2TH]//H+jR¿V}_fmm]ynں~GLLAS0aՂ##X5}yp 0a38aðOk1 'M38a³("))_}WFf ? aX- _x_}LVzbbbd2;t0***/~DLLha8c0Mٻ?j[*YPPR9s%⋯u߯#&*&R۶vg~lQG ̹3yg?3;Lb*Lpb*Lpb*Lpb*Lpb*Lpb*!TP(|1Trfm()+K0B<|rss_$'k۶9o^P=eeevEyE3w68B>G;ݰ BL ?t!TLmpP}Yo:Lpb*EACc/[ !O ΠJ?9y">DD'-}ghhj@8X5GIbJ/ Eiin8 @cʌd؋ gxBr?3M, *S4ӽwӷF*đۯ9uPO;bNpu0tVQ^Q˽m}&,g \_z})ׁnn#f}PBֶ˩{0nɧ4ХpyC{9ySZM+~ٳǠi[~ _x}LpPX~@pmrL@ɻNŝ-s仭9yҎVy2e]t-u^$<HmaT~V& LJxĶiê$>?dÿGFˉ%[Me:SEF\f8pyGÊZIuZy"<2k_䷄ HmWίDeP먫ݼãYF0#I^mR̦im,GZIK!]zڿmwN.Ee>xXź@zzN_K5̇ *=R16lq@߈{*I92ݭ,GY@8ٛg-ivC!TG޾-YTG8zYo;:brtQݕ\7")Kk9E3'k6\AzI&v;('npޚ̡2kzӴTA[S&RjEӴ {|ʶiI=MY+BM]i&X$" ~ !=7zn);͵PSmиVucN yvD|Lcce7D߸)lb3_NH%eW\>UVZNKU]Uqܙ.uGKYU8ߙO"hFZy:oDXmI6ryL?uRPr -K^:88H~ߨ̠c^ݸqܼ䀆ܽoia!YDb4*+QT[JOՉ)[[хW b2)'"fJ,J&B1&8Boh;!$w'φmpP=Yo:Lpb*EA#''-9}Tn^dW g&'H@Ժ䀯 !TJN$OQTlf8&8BHb3'oJ&B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1Us' ̨,E5K|,E Ė,;ʍ^\rBpX'9R@͝JB}݋BKG!G!G!G!G!G!G!G!G!G!G! .''_ YBrMG%˚X,rrmڴ! !7B}+!T!T!T!T!T!Tlɂ )))B5DNNm/z@hhkjhH@!ԐڶD+*0Bijj|'|G!M`#Sa#Sa#Sa#Sa#Sa.8~JrFM;?r߮g"Q_TQ9hܳ9z(G?/|շVxN=WT?oc+ogٌ RqLVS8F͸f@`#[tB~sუ Y@W)9k1iJ,@?Q!HdX, Yl"I(N.|U J =3 eȁ]{ ;'%.~|b_7aSPO\sޑUt9xڎy|V1Х Bt 8_^w'pv̡^NνGT*Ξ~\]]=)X\u954>T$)Vqt;:16vWprwؚ7λ@qcc~W\J !1LpY{z?w6 +fWj=9= l 3֌E-?vj6c[C(P+f#wFDGhwV,cgb#xyx (f˞l] k-%1 P١쌈w(k},|q.=~oX\~ O,\3}~o.ۛfX!&NW, JR]֜r-꠿̥}|fZw62ᱲ >qϑ~{#E{G'5Χ< lu1c.=0B,Z)7kdkuNpk!Clyh&D/hFs\_L%d{L,GU R~q4۴OPgXeX*lDTZT slH_~,P .Ezi-G 1KE + LK噙5mvv#촤{8?q*c=7%#nh;u!1jvլ{ReQtً2+QKus/8*[g/ALH%嚿I - :%aPV=thr6çmU/Yees44JK(Qe^!!6Uͧ* D OTf]&^oOY @i4X,P%rR\N8W"H˲vj"$F*KӠչEj$]'ܔ9j׎@SRhšNLv h<|(n~! zT^N>R/R־N}y!Y ]QXXI@W*), Uy ޏ@WCËc68~ wP@ 8TPVfskv]ZZZg,5c]~lJ9BÇnhxn T S^yrE $ #oIq=__fVH^e\̨ʴ -])H]Cԧ Hy}V@ Ώ?'w5z8Hc>&켖YIPϓr?zemqY^,>Gɲ0hxA͓>'mpBniP(ձϢͥg˂ݷٰcԘU|8Z>^6wυk}ͳٮ6-gAKUDkZY tUj؊#*Y22Ǝz#uD'y]!k6{N`<"pUm I9ݎmx2J7}r*(i.W-4T>q 3V뾆V1v=]F"xŒeMhcMB\j{v~!\kSS6'-ضXދ,m=h>-F4 2 J"Y{QP9!FnJ$-!EA&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B1&8B17{OP(M-M]=WWgcGI%TZ r"1LM]6 igkBO_3\յK "THO})S6$ߔQM7cJNз ޽{I)ͣi]r;330stĉ*>Ʀ}uaRCGה+/(cTg r;lX}}}_z䰯zÂhdAd,Quc]DTZЄËض#"T-i)ZX)iz=.Q)9#|; Z?,pۛBIwt᥹ޓOfPXfMpP9Wr@}a\44G!~qŒİ22c@;| 2gNq7"H]3[) D$jN.L/x|ǧPӄBn )束fժE7k+['.=Q"T,Ebf5cblml}EӴcl\䀯|T^m"_s{D;; c`ӳfU J.҂J [~젗#bwq~%c7+$GᰴYVoY7yvVdiC4|䀏??x .._Lqt;:16W:fl4sD-qtO{:8yZSpt:3aIm6r`ownTVi";tjᓍ>+T]Q/8rn/̨S:*4E;73ss$UԖOu77g| m`29IGHe βo(i#KVJl M,4ͦϢb}+ m?vPq ^?2IpZ hY4RCgXeX*lDdQ:Q3I%- 5GӭClm,HՓ6lp2BlŖVls #)ڂOUKQYZ̙L-SeŤFo'*䗙4!bɂ +W\Ȥ4vcrkU<)j.;sLR9 BsX~8_ >|:O򔕕ԡRdArFIVͽe(uV,[vF}$K9ScV-SThYx = {q^{r6쵋R:m4q֍([ZYZv* uD'y]!k6{N݋>*e9-ڥ)&ae,۩ވė.[+[:`FZiZ nbhХע :K4%N_+7m?v}giO[8vޒ#Ƙ\UqDBRN㰅kh7>c؀) -l|5 x?W,YD 6$K~$__o '"fm >C)3};j l:|nbƿGe & O+O/kZ|,WΜZօYܽoia!YDʊ tCKCSGWrs cc㼼<KSʚ+܄#5m$I2NES4Tffr^eR= ݙScUOf[YYu!6..>!-/ҚDYYY N6zy|RmcZ/NX?l9rkދ>b=APR?\vjIRVrCYGA'&M}^|~uu@ `l6NFVK ڋRd)BVKB{ BL BL BL BL BL BL BL|(*;'W MuuH}E͗9y Z첟BYyyNNЗ|M$@ /P ޿!54_#K.δ24J w~x},pۛysA?EACO붐 ngєv05JUNozH]3[)([6(P28I׭J9xWUnNq&R|QUDݗoZ鲗2*1' mZ8RfzQPsFtUiԔqƹwoEZ=670A##<)i$>H1YC/+v+osp_֪]΃zZ1 K].ֿݹ/w'|qwݻ=eJevzܥ-ޕǖlR/ɜQ7"9?g^#$K`+ ץ:U@%]ХON,>YXzգӖxg|?{W6eȁ]{ ;GBYj8R)6b/}(ơ,*ҹG튌|`Jo(*;t^111.e\d/| ]{ԫN%{9}tQP{a{tU"@(R5/("589YS|-x<ދ/;vбC/_2<ąOw4cGܭw#ZS_imI#?Jr)WE?8mZk}"]+%6v܂ -Fh!''#2tCG@Zu΃etս(V>HRà>f)q6oHH.5!ʑޏsvυ ]Zr>:eV2b&z}hB{Am?ǂyk7S'h@vPO8.„Ç`y B#omUTTmۺ2ôFӖq vMB^[[WȥXyСEC :cVݣEa ɥ\hq@M*^"T5T蒢QI~AeֵYaԳ(]0Eej&gBYC]!nl*ޛNJ:wǤ.Y,hCypCVɑ#e{u>˽C dL.37*[ץ5bG=YJB2'܊z5*ڝ%u* S߈u%ߖ;ʼ1Wn?N+%,}Q#bn$$7H$JJN0!,5SWF97*AǟyeO f RV~RJ]![hPQA| t%ۨ#Y8wS dmqY^\JupN;TN \bͳ*X~YeqVQQv;ZXYU@e܏}D@P7O%ivh_saeB7Gk.J۷**_ݽ"\HJ^]9y5uǶ2;_P$dhCv}6/ t:] Bv] /ATe{SRJިk; y_teVirU;uQHxTʮ>*IB eѮ4UUZR_GMb,-,XꦊJcXd)%5$]ȴJ㬹ޚĎs^aԘU|8Z>^6w/3"~uc؀) -l|5 ޾EV?}'ݖlڲqØo)ΣVn7LڸrJ%ܲǢ;IP#dosz!]xi<~WQke'`#J?IՄ~޿nսm/_Q+,kDnHM{Ӳd)]vfOn&ۺtlFXt3ֹBF=,Y72Tm{%F]>7YF-%Kb7jl:1mܽoia!YD߾ .V}E@JQj2*^mH|Е<^"Ee8Ja~o)V03kҏB?1Qڣ$cMl|): SH))e<{Tw }o>ϯ2j$YYqRUI}YaH򹩩9!ؚfnZ&8BXm&)Y @JIJ )} -e|r{gXTa" I6/^)$ OeU[z-tjJ#&~8_Ͱ,Z-)5cYm7w-,[ȼ"˕Jq0V iEi몒%e| $3RRV h!jnr£|eέTXH$:w[Q|^  4R*RHPQ\Ǜ N$%$&6 LMc|6(5YqHn[KS 6g+i X% îdw34^%ŋ{]3RKW]~Zץ4U54y|s QwR+iQ'+l7jcjw5oY7-3Ri S SBaii6 CwC6v1,~{+Ũi>懿D5o܋T \Tzb|# }6xS% 7 'O@0V;ұC$! &80BLpb*LpMpOaT?KpiirR*I6w~]Wnݬ[r0uK ƷyĕQ7]z 6VY(!m~Ee=uC[wˀM z;3ny+.N<4wY{J.+j+:Z99yE#HKhI~g>4J*JX87PZ/сQ<:5N֑M{nS?;W-MSrQKuիU4X[5&*.ܙ?p%?Sᓽ^|d(QiAKۺ H7uVǦw*qi}W8m*4B/$I==R [Afx.ʡ@(J4Uxwoss*ii5c ),7sG)_uA73*:Z0EwM Hq0~zĶ#VK5~oޭdRB7>R,dv[9Gg~Avmýo͖39B#QK.srW [Mk4JozuXnd'~]-BFdVO^}W(|y5eP31u2E[mPe'S:t|pVoCqL]-^š/Qg- KS+MȻaC791T]Is&l}{G9\IG\Ou9^ztR w}C8_v *ref~0&/9 "V3]κVmk҇;gze cK;)U8xڬMAm_Xー V+gԶڞ@_8T#䟎 tiKk$U[VT0`UWKkR8{~tfӽ7Bٲ'u ޤ5<&:oRк$H{XNؤeqkP; ߰{KSVғE, @;&|uˠ;n<ͽrĞ2Hk;LŨtP24Kz.9WlZ"{zw}y @\eNnnQCKήMuAA)MhG񪘖53V<"iۺ'!Xj6<4IWAܴs8sy@4J󘑝TX@* E^ fȇ|)Vmd~m5 ǑXLx6#AJsGmF> %LܭXM=|.$|HHD|7l#ˡ**<Ȕy7r*NV 8ʪ/|i1ݶGy;L;qhT:)r Mڮ B^[[WȥXyСEC :cVcc$Ԝl%u8"i*s{"%WHT=MZ}VP:k]GO>SJQ|.偱G 4y7ޞr2V DD&5u4_pil =rpTǁSfw5l¼BuCzmOU$ƻ,AQu/xo;) |:,KTUUr߅3]UYrG#H9rSWOOTT;9y@攫Y%U)@U'̬8e *mGMek i`wR~#җ_ͭd4M[kK BRIE0eh0vcrkU<)ޣyw- {=ދNes[oJE^}IV[w帣_STGok}˭ul0C*O9w28ui O×T͡yDGCǒu).cv5$԰#=qxޚH[M2`Ԡ !ݹmNovl` 2Hx|ܐWٳrtqwlr@(:w}k\Bs;;;.2&d ,KurLJ|%u3'VwY7Ltvvq3!DyC[j3х{'Un]q-c ^ՒےS 7qۖkٟLp`jYN60 KMzM-N~ 0Jd~ AyW6.{a"x 6$KBG FM'&ms^di5י!H(h@_%^DƱL:Smpb*Lpb*Lpb*Lpb*Lpb*Lpb*Lpb*Lpb*Lpb*Lpb*Lpb*LpJ w~xQh]rq9~*~ᓭO束m!Ale6&ݭ77BsԪw''iy9}'gRby6m=,BJvļek6}tv߾'YդJk's((ȚM!Y"HvhЭwvz~{Cg[ݾϯ$gVġcs#Mi o yRҔI>ʋ޿-6iq1ٹ^ ds~\u*VsYIhaQג] Yauv޶Eg;/]z+\*%mk{ L VзޯKu *JYZrh-!7+-ۑ Z7;SQKoyTSZj*OJ՗AQM(K۽h;O2$LpcwvШ EB.]{A֖r)V=thr6çm7o򪪜$$!I(Ea ɥ\h^b j>eW) 5[Ի&<)3{^y'I({[.5= A凯\z!o?$n" A]DY/n\6ziۙŮr0w aJSfvfHrh:yԥCwE]lI 4NN$e9jj$m;zϚ4$37eڵ#T>ZPnXmT5T&\p{7 ']r5ì?v2ŽwHN3 5=)MXz] ٷ,>Y^ۓR0*NHhǘ^gn 1ԩ{ #+$@5~ݳCFeV Ƚ33OC,irR^߬:!PR*2/SJiڬ HGJJIi4vcrkU<)[FIWx|zoF&TJN&J}W=d쎃G\dbN yjM?qUAp=wfYЕܷoU4 3o]}QJUo7XH̺mG .-@mF]dXP9 c`7ftk+Ҹz׮mJEEbɲ&JHL&YB?7jl:1ؾ{/BLBL$J{d4o\l:EAƱL:Smpb*Lpb*Lpb*Lpb*Lpb*Lpb*Lpb*Lpb*EBk /_&Kq˵o< yfD -u.~%k\ڵX܅ȕV*G!WRHk1YF_}g&LpP[vg05hbz@CUU*@[[R`#G!I B !>BbbRbbp B|+W~%!w"P$&&mܼyƍq˗n$^8Gķ {\|_|$ Hd)c7i| JGy!TɟZ].Cn2l?=/8sb<5e l:@_;B̘oq"fٽ)os{ve+Ej?4w~w+bSL7{rV1 2x9xpnwwgDlGM]~" IYcF :l5ON.^sjӜt^iJ@T''3_Y Q%_ONSjjx7`qڵ%4'!| Ν*_9a/)ۚﯰ+{:%U&='cq_Kcm/3*>ڽ:p*SM$)$MFҾSGOY~qp cn,XҸײӰ3Jvw~Q}GWMI R~5^ņF&ԱT /6~^Vս-<* 0/QeYb‹.!˞wl2.юaLlyMB|Fx6IRN?z\{ϺT5j ߡ`2HOenl1vH^?cǢԧ?l0Q&ۧˉvÛ!q4==L U{mɳ\y<!/9# {?7I0KMt&4ЭB&v"i$LDDE!T,fE^.gk m*Ğ#o_ug'/50qxB">4 )^}A(R 74d(U﷟֕!Ԑv=fxY/;umUy^}'&&y qwB_C?+jάCKFA [ܗWq2dH١M4 a2n7{1cw2e[)/kCH+7Rf0eUԕe.; u992Fulʨɲ|<-%ee~BB~V¥vn\Av¥Ik~KQĻq} ~$!j5z-fPDNW7~Lpj=sނ_0B|%-!$0BHRa#GyyoZ~~{~ 'bbl)\풗711.m3Bd¥YT!$0BHRa#G!I B !$>n\pBHO >L$LfMB˻g/$kXvՍ#!)*l*"~'SG/Ɉ_Tm;^iD}D\qah#&PwJ+j nUI4fފ_#al=bQ}=U}ʍBJHnʌKq%8]y)($h -.-[Bj9xXu\MrSZ+ySzڋ @$ `l3ʑݔp%Q?u?IU6nn3 1?j+Ϥv+ R76@wNЗ8o AZdt>GY׋))u;kzVFeԁ %ͬeIx=fݺ72i_=4} ]Fn^XRL}|!%r{ RpI)pwQ@ӂ1r{Ta|Si:݆^ CJ{O(cq${3=td꠩&N_yd:▻s?2u.oD=kW)L_I<0rUbP`kwԀ7/3N }a3/܍ރm*N}.{0_.?diw [l%^ ^vQ@٪C]ŐDRQUO0 =`tdcFO}Um5i&:fCL9\~~zf ;ZIB ={&4Y2_8&}9$jύ?폺}vW}ytuv܄O]c凯 ~_y/ ڌK+ڸa7\?à֮Uteuo݊=>ό̿v_p~G_Al߫J.ݾ}^Egt9nd_ӱ7nݽzjVrj]( ]ŗmC gWw͗ō8C]qg<5g׿HY96TR5U5u(pߟ u,o&؍q]5kpr8+e)).OT䢣ER5U4]z`FTZy4! +($ hjk뀔VZNV0fjDU#BJU>Y9:#eUwF uCZ)8`}tmphB^J.&vP'-2tS(J=y<<{{?lufOvW#q!U 4 ooI䱛h.?e6pӆz2Z2Z\'=A)ձ;Wsc׊eǼZmuhv[Slc`UПakVi } rnd6$o@JZ(zPv'dL;pݴgTۿH-=iUUUv%/9}yE^֜4ө# lqF&SIDAToZ4O9[ y^ ^fe@9R=:h MK,&, [ו sZ,׹RA+)ԛF)E~CYȞS/NOeq]Cˣ\.MJK74HPO+T :ʷ ${cL~pNr( }Ouu|iiLOeWИtU_};zz:tl%%59 9^UmL }O&)Hr!T0A\دTMo,Vm18hNlȦ5Vr%M>DoK}=9q?άrt3g'g/wks1otOVvLX2X0vii49ҟةϯ&G; ZĹJ+K )Y mXrIce;G#';t5"ʼf=EΨ ,ɿx1.۟=dk3M"^O&wL3<>1E&Bvtpr?7B,}Qh)*j1DWlߝv]ŲW-%FUΝKR&CjS:hnBwnf҉A9nh[NSl^qƍяVv5inV, HZIk &O>XƓ0dL@U *tkb3] l9^ gn\<͝A^T;1Rʦ{e:kˆ;+N/s(oq#5LwҪ&NK,H4=zXQǢ2n=U|VR+)8Y0NjNsgbclW `+)161?[+/ otRmX]ޭ` POU(t}䓳wҎ=gnW]^BCH(T:Y6;3 uLlZg:z4C"'bռQR(ә5Gw}o26mTgq 2᲏t?!'\^gU\p[ z~,! {3w®K,3?;2k!B6x{{,BeKV$_dw-.H)~vbjjj\@׬?t.`=g";!gEş7/T BH4 w 8B_΢ P B !$&8BI*LpT!$0BHRa#G!I B3$l"RBQg(EeffVUCo\w##1gHpB_ħ R0BHRa#G!I B !$&8BI*LpT!$0BHRa#G!I B !$&8BI*LpT!$0BHR1 Bm8Ƨ18BK!B"LpT8o@~7h CCCWggWWW ~DNLp\.7-=ͬp)**ZzuM]̟LM)҃RWW^@s#L^|5;7Oq8˖;.\шz&)Z[u˦Io(A]ḥ/;[?QdB!iU>϶6jjv{jjwN?n{<&8BC%K2 u{> ~?Yn74]v5!WP-L޷t#;S4]>[78vS϶mxz7ܹ|:vI+^;sR 5Kیp!1ip8u,޴a(31kLY-Vd5k~ۺ)edDza݆~6-z?\p+*ڸ"F\<@ >ط#|ыI=GW_ {+S;m-GHٻ7yNú/VPPܰޛ`4i(,/T񄒲'8&u/9wC ߛZ g \mHkg#~/KKnpOx`+.=wGuְRCؑ 1 SDʅbiS{)L7?ǍϬՓ"hk̛Y_wU5uk֐$)r儜QOM*}S JrAXuuA.7 Rlmm-,,6^aeT.--I ?UX2@sT"gW&TTn_d0(4 AЂRhůp2v 9 *WMmoލ1 BHlƎC-[||wjjhYZg_kiu{5Np3.l&/HBEOOIKg٪9+1e7..N.NAG mK \+ 0ťPy'h}9}@ -$ 4 4@OrʪRli.dCCEUEy >&m 7߼z!y}x@:su=[KC +#x|n9ϩKY_bbP5]*de"Q {PۉlK ^~atqL\̴4ګ V,bK-#Utt>xXAUQ<jV'vE=ڢ'y5laՀh^ŋԧ?w#$> IOYM4%w-T:gl4LmN]94mf<{n5ks_0mccc$zZv ,"2"2m4hDdSc_Tp)o6l佚  ֈoG~']\2]UGa5 Y=fm^E%Tгһ6޾()-.C[[[oZlll;t \ъޠi:<"<٧OKVkcp׈ WWWW &8Bb"\.8v5fS\!&8BI*LpĥN8dUH]6p øq"@k!$΢ $&l6 _SSKUPX \ڠ{;IYYYZzzuUp7JQAЀŒRh)[o|,ѽ!񩨨.vˋKt `#O2BHRa#G!I B !$&8BI*LpT!$0BHRmC[IENDB`kraft-1.1/manual/images/nl/catalog_standard_template.png000066400000000000000000001140441450127457600235270ustar00rootroot00000000000000PNG  IHDR}F5 pHYs+ IDATx^w\] $lAnq{"ujmZ?uZgZۺmݴJ['* 3l2~ ! |/^}sw{rsO`U@ B*$8P!  THpB@B*$8P!  THpB@B*$8P!J_xyZ6:&&?/WݒE [ёe+G:W2X,d `\o cb::7s߈rttodZmrJJu$xy{DdggiVkr*$8P!  THp*S}8NNVD^^b6M ~+_yKyա>+>;aM;Z~x9PeѱB`oIm[x1x Xz 0ި;pL8(pPР~ٿqB]qĥ[W}s1x3<1/b'.O3_:yձ})Z'OWhmH6o9Ƙϭ?D7cljHDUwt2_aK}[7Aoaӕ|%O=s۹3](\Z6w^tň]y)Y*Du_/A}WS`1fNU£1|];gg|}OC""oոD MbBo u=}ice%/*,&Q[7yoQ--"bGO;o^۸&7gصdtԱy?*)>>6qnjBZ_~|mDЮF*=r߷Jc-=z bΐ[Vo?y[eLjv>'uS5_5=H'O]y6ɧ]]~xz͞٭&!#DXxLjıEwaFgE_KzĊ!ͅ_lZ"^uuu^O-&Ѷ}艈v">쉨*mTYWn=~+)#W+~!-m~<m./s}Ξͽsx}2u}~8nX;".SJmw3IOubzZ\vv/sj㡾Φ|v/.5 _tz끣ZM ;z9Q )1U6uυ.PZ\s9&~MxȼѭS]̦I[vLc{v gF-d񌮶Tj-mXS"q^jV w1TPLp杼s/\X]ؕUA>lY[z? XQM"r5MRq̤\~ 'UiVO4qݺ %eԉH}f[h78d%{ z D\~! ftq!K~PyM,u'V_6k/:]<͜NːK4.fAưe4{bop*f\T)D|;t\3nr73-˹{ѼV[0n~l׿x\YO+mgdۼeGA3~PIo͜v^űNmV{l_-?dl QUYbd ;yM%n>yϧ0ۥKn_-ؙoʲ&7v.^hUmpg0Ѫ>Rۙ՚1 r_WǶrWuLX<뇿.߁+|?Iz+uEx9W*sh'gHs$W+La?3FE_RYcILϏftMuTCf=ڼgW3W1-qz̓z<;|KvIM 11uR Fu=jJxvGņgK}՜%%-NDe ,}[Zſ갳_G y߻ܱٻ5V+Ww)jer /wֱJL!/1Q*eY:UZo> )(sv^.Qb|NFκual3VWNpb[yza3'toiQ:tAϲZ΅Xg>Wn xOka^0ghXZ=}3)|߮5SqӡT.=Mui؋krZN|E/<)_huh}hJ*sX6;v>vq.L~r2F ^:y}4Ͽ]ض9x!Tua JIKKJ -FT4k[:}oRƦ$gKMNe,+"Ƽzv}?:+gYp/;&bO߹Sy3DNOϱJI E.z#-D4G""ⳳ_41ލ7;sV}.q Hwo_.{Li={{ڴ;>2vֶSN]|׽KsK$-9XHRDo~o]|yV/oيJߘ"l*o#kbfwctU,t[F8 oSs}Mݿ\]n˽O ^vəjZu'l]͞kSְ`I|.'|?vfsMo(۬UO;b9Ҧ^\m@2:y֌gוT-':ĻSF'JRVKZKP^~fZYΔ!N^{ڤOyht\toQ]l'9">?Ăe! ӏ;Ir@x+b,{7M;w3š,Cmg["興w&"bVVʆuF.O&n'v˓NwE˶mk4osD&V՝m:K:Je'܊{۟7m;~MmEd.SyD<ϼHcxLU!]Ss9hѩ5?͊~ǘۻ>{:,e 6wF`޳_Vg [?`)yg*Xx/I}~NJzL[8 Q/ 0u,dNͻ9C:յN%S뺾c߮u3F-xD[}k@˿/Lj¯KCm ~ngIQTab,xO%gQDV iy\SR2bJJɫV͌!ҦeYHqdyt"HJDFM°X_9z*kE/Wiut3>[Z1+@qc[emFΞRLFdR䊩N2y^AnnG_SDD$u>_hU-!$p?/Hke2"ʿϢٿegHK2GCL\ҙׅZjɋGcUZc+\b9bU9u&Ғ!>9W:t>ve |ƾ/#b|1j]?H,eR4LH!wvfSNUMHS,,xuz\Ll\j2+':խL_>rh MkU0:x"mƝR,54j]rvmҿ*C}V&Mb!n/ypu/]k_[/W^ȧ_SKgvqb.]aaaVMdcZIZwE[w0C|W\ k^|b)t.RCD**$yE5.fԅMg !̮:uq=:|џGy.s4 ?Q{oWb>܏fGw\Wѐ-nXq 'b,zz#nbd4]eGFfmeҒӥUlIj">+5V|^kmqexÜ ibWiܺ}OC$݋o"bEڵ]bbc2T *&6vmMDm+^{rC(YƬv߾1SL_'̿cѼLXEûHՙu/uH 3g[c0:>3=QZ)K|UFA*z{%֩ãuܝ#?ZDbfCښ3DDC!QFıc?o+Z3v'v^J̗X׮[IM 11uR9F PΒI7+.ldt)cIR0.+l8%ֲoKx'q^-l$Ҷ]}sǁ>&*5?|[YLy8pĖ ċ~s+KFti)6f&6Ii./=MVxMJbԩK'%%' C$%f*j*YVbȉM'qY9DVV>I>˺q}F?:ӗӦ[>ĪEsC~]] V{yQj"bVɩD:a^|r}t뿚ye3Y QbJZP+y 5u= ̬mSRŔ!Ԅy*xL,^4vtiYy1*F;FPFEEQ*7[VxfEƦ/2J[[+fqYw$9b͝׶ajH4y׶̞-2W!iS(KOsbݔ ɪ rto϶ov{mfpeIUxV.k9 #oD'jI\ԮkV]0c\@-հKs b i[tt)g/l4..=MeRD\ƵGo==$Ul nH,̳6 D$&dDKlK'}aQVʔDXX"-ܷP(ׯW~=ɓc+184xڪ ҉=?fz|v > nT^{¤v QQn+f];}m7*rvzنkf-xIk7ɯW87:x~R|ԥG51!#NH;|m.=cHTj,mJޟţ#?+ZŘ;1y`m2^nذ3f:DD$k5nyGwplާM DܳX$~c [~VW [ wW Gɝ-hed6{ J+ "1R6375$ZVmذ0]QM[RȕD{3&-{ <[WK{uIٓNohNHq=|eG󭫇8Uyz"f~ަdQΞpwׯ}B%`hԢ]'2NMܟΣ|f+tDM=f^FeR?F1rE(Mtf7sxh46ſ,[69&)c$V©5s IDAT'`lEx7EEE`ŸRJ9fQuam|wWz-3v#YƎ0:̢g>ĊEyff v盚>Vo`ooB!755_.AJ%˲YHp#255շ ΒF02 THpB@B*c0//ڵHW}aYyfbQCըFD׮E֩[^@/^ҲbY!Ptշ o @=oo~ѭ͟/cpB@%ȝ5gP9Itmmq<֞mM`kbL%ܡDl FS!ׯwڗϯiZ|*1t[!z*r?scfme CIl*k93y""uV9V;2k"eT?GkՕYpc7~i=Yv$HIܕًojKd_5-e]=FEL}sbVVQbn}-+dOY>pfn6"Nq+2-/"[=4/,<+4}n":+Y6Lj'o:NR?Թ7.Reh09s~'rYzfEg.eƣiMU.hk5uQƒtiL2rs>7y|t)c]WV!Aeh=y$Egdb̩ؼH5=ț2e։njt3I:]zNKaE&zI\zW=iI#`qj.S8Ɩ`(i;SY,q3R:QXUy|ou<2kZ1~Va1#&zu^\H"|Fz_DyGfKP+sWxMLZJ_ʳ~ =?wʝ۪k{*7 q C>/?v  Tb22<׳ za^fQ  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*$8P!  THpB@B*c'8+b"[&/e͛6xJTt~,ۼYS[f-==o @B*$8P!  Tva,J*,  9+󱿒-UD~lPJu71Xs>f ^הN-?'y8^;#R3I&> o0ϢT~ 1܋7ut/BÛB]Eg n;r[oX[>R*Ŷbz{ƏL}|f+tD\ơ__r(3RA}V/Qbĸ Χݣuѳ#P2 O;˫U6m}5s}D[yD ._|֣eϥWW_z!w %87r97-L!0f|VMp""q;ϝ;{NoVsM^1 O!kjeK+2 ;eV-MKO*\|辛U]^YhN.LjƳO7rș6,'Iz0u}ZcEEX!"άԹC݇NRL&tiwkc؜>?>]:y:;Na='f}:C =3#Lǧ7GI|̃BD$2Mwnx^zq7#v$ev9G+gq1 W\o+WO-Q 0 ^Wc} 4~r+[)v=?{~ӫ{ρK"4)d)T٪?׾]砯(G"">e8ߠߊ&ԐG(ށcvk׹E.1X^]2`ԺͫM˫wm^]{O#>9#z{uby# >d.1qvоӀK版3G.Ov=A?.,v7p^]ү3z1Hp=ܽSq#_->QpgvᔭaGW?#'r؍fl(Rgc,YիW^]tgcHfP^xgΧг>-8S`rH`is%r.lǮgf0kBb`2$\R}f[ÎiɞGO.ڷg)u?;cw KdDeԉt1:vCV-&/Jp,_8pª.w:W_V;dbj >26GD9gǭ7i?0 kh{-c0~k,^0ޢǂ ZFA#[ۉIر7H0{MK*}qI:ufƐخmQ=l!Q\e,kѸNjd ;:%~^eRK"o/V6b2.ԿҽB,ר`D52.쏈f:7&VrY(7<9lt9P"G{nkS=NLuvDdʾ|x%%(Xb-/vq1v=e:pMC=>z^ܵЃnb)"V^؃{擶:jx8KLʼhrv9KbK 'c^.51#"Ƣn+j,fm<./țdOLsݐjO^:4G,z2""4Wna[Z="q\a,qe$%>:6! gg$+\xUZ}2J[9 +|Tr5n88xKҥ˂7nX0H\~==o8po轧F6qI7Xomav6 ,S%YK[XN]x-A;F75ׁ"3\Vbl5QI"bSʭ-\cgWB:""s335/ܕQX*=#bfOa)km\M-8xs믧5a,Y(4*ң'#"ʴ+;XO|F^%Vq\%WI&_Fv^Y)k 8'ژ3lu"C61DT5Vnc#IJHɞ4iֶ6_!#~^`ȯ+cj//7UMg>:ˊ)Pyuy{+8]㉭թK_=券щ&mճCFixuڝTVا l캠)Z ?-W;WÑ.\qՇY:"u:UeZ(/ry^/Oܺ5vώ>vx{kw^mOŲ{[sA_(9wZƀ_qn|qm qn6m#.kuҬ3H7c3yyެUO;b9Ҧ^\m@⒇MO͖jXÂ%]S9"m\U5c(.GFndߌ)F%c+lӣ8Q)uͨnm;X 41v}>3ۻ]gQY[kvn=k>gXO*3U|3kq:v|m7rt)'ٿk^:yˍ<_T <߸QƍW0.IrjnZV@񮉽}xQ|"×2t?w<ͷWI~ڜ@~< m̟Q/IQn7:v=+x8ÓtQLYn؆g}0vk%eXΟ|d!յ~0raêصC) NtmLZJ_ʳ~U:ܮ];jpĉF:::7@3G:-+$ګKNʞwz7gyW_RUk*EUx2>T+1-*|B%=0ۍfFjx~US\se?k Po4(Ĝ>AFC<_/Cȧ)^*7>ͩ]J+& [٬Dr][q:z nT[6<Ƭ7 D$oT豽߇Ô_Wϛ֥~dܪ31V|鵾S<@FK*eYH$bV$D";94D?&~ƽ??գǨߣt\bߡ}c;ϫl>_ۙ#}>c_pvGG߶[q1WPeցׯM9ND4`E̫[ǿ!oZ{uɀa?X[Nbhy.#)9ѱ !UݳyֶV#HDkmԹtÝS1(z ;k̄C NXFē=iӬmmX"X#~^`ȯ+cj//7pҠcime|l.5)DD$FiY DIɞ>`y;)0|NJJ.OIJTT"S[+s${ !'2|߶|R|.𑖮9E]Z(§,fQlfzk͑6u'l4 KyJd&=5[^a tBO=֛fmw29"./):uqn IDAT ܻֆx;C;bNk0j{\Nב.5ٶ#bkucr9".;Ftb陡X^ڪg+L;빞9RN8m_v*!,Wq˿ޭǴAQ~S V 6wF`޳_VgJnŹKM]r>59JgIԯ^Čov=K/|ޝ BLM嵼'Ldʧ}TK9RNĄj}\͒壺MWiYS֭RbE>y 9SkW~ucu9 [Dt~%pgK* 3M躷^P}|fe?oS%^]2pR[ @9wwKzы-zwI(Bb-w fQ@@/5#FE(EԐB*$8P!  THpB@B*$8P!  THpB@BUn'SՆ ())v+=Uj9:;&Q-_G o!P*I.8ګ{U''"q}߽{͚]ͽW:IX(&]s?{8"g ٳ1_MATߧ֭[Z*[r'\nEԋ(|uFE5ʟo_ů'x {Kmow{Q_A}~,Cމ9}~qw|i!~Ǻyͺz2YW9qMeh.}9~æ믎OgR8xƨ jPR```7{ЍܽuC?ߗQ>B} 3OIEF}dXGZ(Elj"‚zḀ|D27ϻZ".[zIwjޢ{K}|o0*+(cЄ,Nrc;պwq}Hg_Clص7ǿ{cѵW Îxv蜢u?Wۑi(qr//_.?5"9/ٻ(ߙ]]r QAPk`ww\ب؁"JX" K1WEr&vwgΞ9;QMhKQ խD\ ])}<}VԐ}mvPyn.N]q֊'B1*OӮ ^VV&yTTJyS6w혨i r3Ćmx/z!tvܿNjqS_cT:V/hP=򗫫k_?Ai|qvT8P˛IP'5`\ kHI[}Ϊ4%+ dhK*82hJ\ּWFQA)@ӱӓ&i`gTY"lj:23Däft /3, (?i(SY(LV>! #MPdi"5͚q-N2̈́|T}#mm,{/t.]W?ñ .zpڰ41p7u$E.U]Ȇ9ai]*QAL#0c:6gtb{uc"x/T~?:PIY(@HtJTTu`=#ԛ{=CI~ӳAc+8NT:4urMLP dU`ʪ J K\N`8c2M8K ;v<,!`…$I'*j65& uSGSPPhFDCEW/qeYumK`h-ddEy%j85-B9g/,؝?A)kէ _^dj+MGP啇l ]nxM@6 ?CLmoyU˖i_YЭ]wva }#:Qʹ_?:QCU-`4~A&Wnu ybLy9#.r-]2i';+`9E9Sh1'pIUU$UWΦ>.q{X3TzT34V><訂ʶN'x@s#G"Ϫ5іAPXرLCvF>>o#ֵ#%w $5)!_SyKF9Kɯ{98%A):9EʯK[72zTډףve~T[\W6З]+:yZ?7< 8e $FSPbj YGM u q f]L{1g/gԓ||5UBxzz3FtZ !.yx3;T>G6k˽G^aHs-:KKMkK7m弖h8ixٔ*(^ԭC5fW?.;K:QL8l~ŝ߅dmTK~꾑ZfWC ],rU<޽gF+ZEcCS|]kOw=4`^ikZQwQi&a?$?YR6 ҹN*VhwJHL-m[Gr`8a!.jÎ"NhkO ^V۶~;3q쫱w@N9OuVͯ Ѓ^V˖PkϞ[~p{;9)+*@qQIYEYl}.wI R~efl76 Oث$NfѥI2dՐx= Wu?g[ZZ޿SZV(+++Ϙ>`HII.q YYH`brM17dɕϞM;w}s8EI׎cv-Qpgn}\G=lhȼu}܆Y";lu{1n4@w~SD ]gmҐљL[>a2l(-I0]g^Iq 8 qB-Z6 \JZMŏ1j&o$WW# )Q# 8XDYs m Qrsݲ "bb _2A}50NLL͠55=e0vF[M؍Ew9/4WxHw:$*Ux:nyz\ڍ7J ^XzL䕍ݓ6,Y~x>~ U-Tޮ=qy:rdp^^uU]PubFWg>}<Ρ1WtV>њPI*)Ӌ /GJKOfj4-=8?uH[[fv]o$Y0"i}511\֖xu5mԥ/"t,dIؙ+U7e0i>~b~#Ti4>`2vo7'[}3E\Bµ$*N(x "Аda?; ''hh*+*1% $+'O)a3fl[!ŽKo(p!]R'-G7.#| Sd5U5rvჅna D#n^O`& <ڵT:w}a&us/%Nm;bFyȺ3]7WjeG"E쫂.@4]P25iiN~NÑdWTrH`g={VR'5Y.Dwf(м)7GOi淳Ooj=T>1/njSqY^&ʖu0t*%yUIƊxcEˤ\Y;=Wr=Rzj1 9) nvfLхAP,)V&lkRG+Qs,wa=ohm,OD"..p`9vZ5~\tK4'fc^6O>f$u#vd@浃q^K>s M-?-%a?$?YR6 ҹ@r SULW Oa)Қ]4@PXL^A5RBSB u+A~r0*)ISYHἚF &?H~##W\&۵Bh1ڊhd~S*%&XUVy ܆F4 Vbфa68*;u5[8UBN@ \.+7uRBQi.YBJ 3sXl}jp.=s⟿%1*o]iOx$n)ߋBt10;~rcFVF"4EsEB~m-GVUadXUZRD>__i"n~r/ jX ?]7D? =pcB'xJj*t35E ?KJpd2 #: AF# A QGpÙTKpV__/Zi_w~ IDATWC͵iienemu'g1j6s][Eq[gaL>zozM\[ [8"/Ji،lvHV1XUv=9*8y{z>hxͥMB^U7wrq Q,oդb6Iw7IB#[/:w_WcӔ{x-\9նܓUOwsxcG)]2SywcIcn~j陷0oT>=mb>Cvc`dE^-><QΓoDm~EfRB:~w|m]JbԈ{wgR6߻:JEB#J3>_ 9ai]*QAL#0+r#s7 i7P7OBwZo1rΩBCCD $:x@gЉ72% 1:6p8T:y+`tǗFm{i_TӹONlʊJLITQdUTRV|;%l̙r[7c{{^_w#zudb/~z6|lz%lj|Uĕn>.sCk޼?QYV٘~|FI} - +{Okp!kn\IUVYOu{$[ зg&(h|cd=@ ;vS)~:@`~οΣ]NsX|G].gfuAabcH| t!Ao$F9>.A= +Rp Jq\zrk9pbh`:@+Y8 tܱk+nyEW/qeYumpᬌNNvaaђ]7:CV)/'sŃ#ۼVY{zdYkv?\dK |#QZTFST0yӡ vY`kO _ (rr^Q D|_ג3 '&z; }\>U"#):zZerH9Yy:Lč<R*ޝ)eEsH>EN,Kj)`\. &/JWKI~֞}=qsؓ@UUjJ4 އGRy$Z2L)}H@{ój S r6V~  OIf Mt춠oޔ q%*b|.aJWK/Ib8 MEo3JO zvt_q,:3x]fc?쪼Y>bb*{̥z~u>. ٕp5wä3I,QɻT h.S?pH^ٓ!oLj((K ]]'VmMݜ{s8Nw"O% hcuK>'8؏ }1(f 矛RHq[Ugu/<{[+7G;qD7>(-TzvB](@V^3|^{~UԿv?d `Xf5fz(hcm%Z ;><$@qm]<{oan.ZL  r3t^R+ mtq:P JpA %8 HGAB QGP#tT(A:* JpA %8 HGA:<"'xU=$6Q|)<ٹϊÍ' J8mwh|a}ڊĀ99{ؠKno$[vEwNUyvirC|"(>?6{#eӷG{=#d[(bk֖hzg tM5'?W_ގ:Tm+HsI;OyNn%?lk~#gDaJ# @==dl>}x ,7- Mvl;Džk3>K[]'s{1v0j7 )!f_;Tx/C^jxweMB^1E(rf ť%87Rc|@WVP( 1VE4Ve?:y%QBB\*m¡ǧ2W @E7va s3hk z;g0L~}pϏ&+iG;>rmuEG.< a=rc7 ߭\Pw_KSm[7CZWV{ntѱ;Ւ]/{wn_Loߋ"Ѡ([tӔ{a5#W(gP/aG^94HLe9~DkND>T98:n18xxs~vk#ȯoJ(]o$YiJL&:ʤAg*iq+&Þ( ߼zam?cGq}^LnA /|u3`_緺*4ogir։wZ:8J%@Z o|+0k粡G<<-.%@ ^\UG/? ) e¶}q` H^5,ENQN~$>N.VID/:EY|蘇ƮpPt?>X]kkѿD'"sp3 =)L;1/?)< A!D@EsH>EN,Kj)`\. &/JWKZ>^ZD[ Ay|Ra_&#'Ӑ$q~_|&%mNb5*tNǠ *"- G zΨF׏۱BbqP6Ň&>zU7W/L)@+ *9$PԵTG$CT[]]&.x^R^u#ڬ;N'w;Ƃ68•ٹk_ аm6Ngm'"Mu\S ;a.SVפ91[֏+-EWyZkOqnoa^ikZQwQiUZ]''=$Wd1AY'Ln92wkܺw=u8SaͯL:j>NT6k@%,fx9&]&l^Pcz@\nyt4fSɥH(t}/XZ;%$&X["O6 P}~۱yhwj3 HG$I:]K~?ԋ 6JE  QGP#tT(A:* JpA %8 HGABAGu~_&(Zʢ~_%oһN1D oPUU-aP#tT(A:* JpA,ZGVII+VZj/h4! 7IJJ?U+V}68 ȿƷ0zZQ#WS+ZIZƷ qȟbgo?ҐvV_is*u5اžQw+iUHksLkMȚ'5x*[8cqaג^_C|g@@[6ȟưEB!@>ʐ}T /T4)R&L%(7-P`Qr;(h]h$5|f9J^H0mf@ CtB{xPy6;(lyZ)_&.8*!Ȕ p3 A)On۔Nh&`,^xŸ8bU}Dk+RAxϞ;;9vL"?W>x-yhwj Hg_v_At_j ̬B|JpAdGP#tT(A:*(RR%b)6+(FFoߦedN}III0(QpD^A %8 HGAB QGP#tT(A:*4wϞNj!U?ȿk B( JpA %8 HGAB QGP#tT(A:* UGNp/'USG;#*I!_(Bl[tAU{9Х5ue_'4>TAUlv^NZ#+>ݧzP~]_β"8IZ1ddɠi:Q8RBc&~Jpq̉<H gZ;xP\t Vgg)ȵ~zPob~5aDXU}T3%Otn)*z/vMd`2ik^˒>s pE$Y0(4grcIsTH)<7$Oӗ[ 11s Qu+uS0B@8P|Jm@k^^ mG>b꬛gm9=e2K*YU4du⥳eF}Qk@SZIbLlF'}z|yW3 E<~JO}FT 2lV<.\Էsc"/WnAFn#Мݕ.]t.#Fs>A_ÏkK>pnPf |4)%|Ѩ| AG ̩0Opmg6ȱ_6&@HRFn]) q4>ԥRO rtc3aο,`MZD>f6/uةSUc0aR8 o޾ͻ_2#LD<Cej-}O#>VĆߩTWCUC *K /^ -R=:bC{YI;Rr}Ϩ #c/-ZcҝI^ ZaDue<>*k`HYڳiyUqXj&].OPQizWuxs>zރ[,h^f[[AfԪ>1t? $G}?bgJ]A܃ s))~7"9g-zwȎۅjCn?|yGqGd]C'c?~tafwǵۇNO9~ɓKm{l]}BG{ս"!*љzfLͥV_?pu s-URPun^;ikQoI ˗.P. bDNdwmZ2nC/FV!YFx&ːJcdC]9$XU "Ne 1I}=UqYb=0e_\:M p.z ^%b;ɢI';>[—pX" ꆥ8 d$ߦ zm "U|j1 @{>U;v.t8a߃;o^W4{Ț Qo3qB ^*8?(.,ચjbND5 Op2,g+mbBԼ ܌y< ;3W3 Uu^MXz3e9E]KB*(e7 ge;F=4<)c7Z)x1ni`(y%//_tԞPϓu1vǟr|%Zi6f_]"8WmitwFusR 5+zT5A1Ck7ӈ+o5id]B$<8|2 rb$M]ܦM)N"Mb/ p&Ir`u`7d'ӛڤt0 IpV\RBf&_yWa4q%@r¿/vG3N_}fmqWr~>KbR4@s;@"|&dE䪱J{B$P6M)=eeTMfٟ-Sib<.WEw{q>$ΤSeM_&ty:O'.M~؞À> \ v㼻|8˚={c-;v~[irTjujԮ W42f,-T6iqm\EK]+YCӦP Yqq!FGkwҠ`Wִ}x*jJ/'=zЀ(/TVߕ0+ @UjJ_E{97>mr IN&%+Uխ)A$Nh.?P/v[qԍ=jy^/>Ox< X,rzRtH>nt=t[Z' [Yf*6 pyEQ .N*cmϸ]QQG'ߜ]<K)M׸k4v|{a(cI?X&8/3 .I /97;#{^qfRk $Uڝ>?dFTty\ɒO.PqXԩ'2=6kk}<$)s\'T#^Zi*{=b@1ڻY-d"Ph' -gh߸uVҜԬ7VzԺG#iZg=)HOO+'>fjuyI+=:ȪG=vUaBxv'\wq3p2f F] -ZřD W2춉PY&KN5UkG;cMAfu;e7]YJ}ӈ{54cg;UA깵SԼ;oބZFIgv%F3)ԥ4Hx;&bQJ $/+h`sfeRQtOW9PAg bRn{<,C6EVa&3O8'irN\w̽'bsUơ>3} c 2zO[}WÕ x.(%.[ r4bZ={>F@Wַ[x*Ŕjqh=mbcbKG qeO?@`*H4IP( $8I'ڬa/2sŭܿ5Do&ϣRMmh*Hkk|DOb==\3{x <,r{f@6dsD+^CPMK,SYXdS{4ͽ4'ԀqzV*.)*JK ;83pcq8|?g|3Y\ zT(='`J/~;1=l BU0 \wsrrfOSwܹZ|գH$bϙ^5ZzImmIs]]]U=80 0c&XjA}+$8<~Cp,c TZR"$8_`v>\7O{7-߽ j鈦GHlYz1 eԾWh=c)W?[㸸|8EQ͚HәYZ7W{"+5)ѧ]/]FҢ'Pȣc,,-n؜0)11lx/{+ N=<,մ'(>.h+gz n8s,c*[&C.MM]w)͔@ fLu65&"o"Td,8>xZ'KiBQynoہD&[zP؉#>W\OTi M./^7 !g_Bk#kYp`RnW~b%'>{\{x6v1} /ԭ:qײsw~䪍GTk7΍.]h7^vh9?&,Wu/-kνp/[^ں𓋃wݻ7,Zj?*J$MKM Z5UUSxʮhJpom<]Q'W>nB{8%ЛZ  D~!#wjzJ}lb0j }91wӭ% x&tD慰(++ ¼eodH~'nzّ֯ճ wOJLlDTFъg~Qk>iSzA:p<$pww+T?BOZj⸸_K/uw+I~auboҁaC;o_ )iF8$F0 Xvᄁ諙T gm-X0rJu{~KUJ+huzoYS&4t@@EFFXbuN &Vx=Z(i([iĮv]c/D,JJ!btclߵEz㛖q\|jJrtD B!5dzؾv])B혗}^244ewM բj,J^ؔ[RMB?(Ztۘ 0p3 ao^*)kx:``< v{'lYes?Q4 bdoku[}^X@秶xIK,y?rδ@PXXm6o/%s9~c]( c[Zkk:Ud=hxڪw^2l(5׭۰erbw>]-՗i:_3l[: `$/ֲ')[ܼHWZ5ZzHp㩮a_;v SFkqWO WI&_! WHpB|+$8_XRzIENDB`kraft-1.1/manual/images/nl/catalog_standard_work.png000066400000000000000000001522671450127457600227070ustar00rootroot00000000000000PNG  IHDRkO, pHYs+ IDATx^uX[]K("tH(!؅-vw7kww(v!*ҹƜ]]/(}.3;9{fv(,* 0La a&pc*a '8a a&pc*a '8a a&pc*a '8a a&pc*a '8a a&pc*a '8a/h|6?/fsrr(#/'?VRZ E/׌::#1115UUXjsrڛyNKKay8[#4Dq:[_;LaX a&pc*a '8a a&=Qq̦+ndQw~30ЀYUƮ Mps.qPYڡ# m>yp ʢ]+V4i;{2 hȉs^x[M" rps׾㖝~ha Ƥ7I{MѢ*ȔQ[˾m2*8bʱo$r{UPIATԉ8`$j-|o:0rr> =f=Gl_3sMTC:/SI8-~(ޕ=fnG¢~pWű_R?b_$T"*~Zša} ?&;ueA,6BJG}?ݷ0FyRz?W~wpa"Vc`+XI@n`J@eGvظs.!)1<QxxGELkySw8#foX+rVI7ԃZ|W!asLp7C3ebKڜסv YASl`mo4mYkr7M$#^JcSj6JjݑOy%4Ma ƕiz-3sJ˜2q}3'o8V!1`vj$0cxoQ;5ޘF<ܻrٔa~ :wVM@bitOC/>1Q1p1u!.z,zg&d8:#+vh겒x~tW3&7jtptqayG/vywpwV%ALpvvUҫsem},K߱_S8iO?w[zۮ-[3*K<|Y-$oo p^eE?C1!zy#ܥ ^YH|Ryb\MvNr>0㪣kةWNR/ńkb Vj@1>)X-X2h|C~tI†ӶGxT@[w{MYwa8*+Md^>~.ÓS;0n.qZzZeF_y|FͼQs.e@f^3v[۳ֲYr|W/5"x:b>bZgVaʨ'%?DŁäyT]&}sLGiV9JԫF,J^L`^y <~q&Ք(!3O_{^JS.qmr4 ;0# ڒM}L,֔UbK9rӓ&خy὘@Yv2%ogm*h=з5wV?Pwl V޶SKE15;j1 ) U5J_G{UAjAO_i4Eo.@eҙ2M#B ʹOoǽg)%gISdF$$uL?NN:RZZANVcj.G WQ J:$X@uaz 3QS)DFS@\{Y!/صlS^5Q{.{S$QG ^LN5"YZRJJTE r;sBIV@((+VHy j onQ¼"Y:]w<tT_=}F+QS5YT{z]EPLoiZ!!TO*r% vAnAýpUb&exQEu *]G#Tlڞk7v>*Te<|RDt:>\xjɹ}zNs2ӓE1S..{oiXYP8Ier?b6͊ra߼TklَOSRlJک J 5AFy .f'.fDs T#Sj U!(` #M\FG _dzu.e9hSeCSVǢb@(, Y%E¼ Th|")f¦BS+.GHC:׸U^7ksSL;Κih[O`F-趣fA"T^PP@R]EyS;9rX E(X9P`J^޼cӨUVߡd7ntNk C@() anoR}<+CîZ/.|]tư0ie=/U\onR@e 6LGWÇJ$\+tUWR9Bk+x8Ld4a!g3 XVׄ; y-$ WҒ!Sow ěwT z;Eʼv;ww/=Uِ&-:7>"ƞv>NEz)@\e[mY6@((+NJgB,*Rm^[wn>-U N(xqC'#q5gO',FH[v?VwJүȄS{͝:J⚆z4@e?Nr4 e+SY([v1M?VF/)Vq+++NFW|[tVOU eq!D3r,)VĿF&Şsg2-\;m +/T Dԧrj{)u9 dS4Y-Sq!zKjTbΎj7:j. d-z8>ZЕUS >}}),zuϕ_ϸ_5.Ö-Մ(C;'ddvl ðAS|d/-eDah,_aO`a'8a a&pcFfJJJK^LfIL&C0irK۸dde!_mC77z$&XbaBeegh_=`a FW++//m8a '8a a&pc*a '8a a&pc*a '8a a&pc*a '8a a&G+S::E0  @E'w_MIV52RE# kuo']Q[q *MAbf!'jf$_ݼU2lP%}Gy.?Z aݫ< v-h-U@L1;3?+]u$ Bʠ?Өn֐haio  ;;B9_;H%sk̴L9S)k4ʎ.ZN( v0 Mߋ"f:$b};n|}y V!jweR$IyEɈ$i@QE%HTSWC %jwW$Yٔ+.{?/ЂX#+*K*N 76K(*)Ԛxc~!`zХ"hjʲ]F_ZU`&`Z ð(58)g嶺R7V9xyg]XKEVPEʕW-]j+L skA((+NJgBlշ;WPTYۤl6aAӷٯ &sڏ^p4%cɡ! ! )ѵ}6~,Dt˾+OCqȕmmskMR>Fx\rnnkVBÂI-ַhS#a $&XA Ĺa؟K g" _D0$8a_9Ώ0L68a a&pc*a '8a a&pc*a '8a a&p N\ 2l@UjP/T~s 3fI>;}{a͎oܻ޴Bg;F }awwQPݗ>`@R1 =ؽeIh-ƇډPqm[Gj9ްn4[%V:倩jd9FO, c\zXȑq'rFN.&Jp>]qa.QI=[?=#Um=6?0z%u]mt$AE0)}4RBAϼ-]m~{^n]<\Qkl*.cd~Fw TN]\=EgzƣC{:t]U3ʏWWo0Hnl_t_$13{ӁJ^7kC_MJ;2i Nԫs>w% b7c̺[iߝ]]fkgߡ+ԝ#vdX'prrūK! vF汽]|=3W+f~QU3ͧݛw2)*vNڐ}eѬ w322bhsO1bOSm['fy|7HC[wgzp,읻ME#)׺ѴtWիӪP7.y#22ʞmt(l9h١y1n;vrֳܸs|'+T'oWL枸uj~mw$'P_/ܭ{ joS肀J;p=IF8>z9[ 7p1|Hcwo Bl-&Goo+mr  nbؿN!ԤhJRյGM8RbʝurAb bheH*`ʱ3/h+U%9Eq5(Yr :f .~[*jl ڿćwCN&{XLyw?[=]] MMeegٰU+yyyaMS'i%p|cXrI˒R M@_ zikUT4gncCkj a&"'0pcN"0?K_+}ɓ981 ý? M]o81 9,Qr ־>c.wwٯv !1t7LbAO7ߐ/}X/.ݳךr zbly7 -uy7˴C BW{~ПBumpTtyjϋGSJ>`ā'qYzj+@(ZNQkeuJ6uݪN%2ӈnB~Cۥ^fah-+Vao,^f.B_@E.g!&?x`+z7Rqd2 k ^b?7#R ՒT AkVͩWH!!տݸqcփמ1 IEzݩ W6atz6 ֝y+5ʭ,ABKlɽuҌijk]~zmwq>__HO{Wp5oMC {QɁ9#kܦg{{v;bOTýy{zx[xo>$Ih4 $ 1Mss*vF }<]ܻLEpϬA>^n>}ƆFQP`77w'2hqYq˼n}ks^o*%jk\7שK]9~l%\2d&qmϊ Gfe_ {L ޝ^4{W+0J;:*(^̎\;v^y5=Lz+ *_Dr z/ > BLNǦ_'Vʧ,8Tӣ Fwuw?l'vt aGAUj)]}=wfc=4 D 5ɧ`)o!T|y@=?6w{ߩ;q fמ^rS_n,Ib7b>,LT3߽?8 9- ٻ΅G(ymˉX*Sѻ.DD\X5lޞL˩"5'~P'm+iQig,9pĝkG|yzaߺ{̶:~f ޺uep^·5qckfYF\/xXk)Q/\9.@qϤSWnEyJ2.!^}hv!*:}W n^bl墓%̆]ѿ3W-o,L;|ᩢ @K\qG)ݘ7lkʧ;g}v1oAc㾫՞NH 4;/wsi伵—N;E u+)7. .BFMJ~G=òظ/ GĬے߭ïZW?@jwo,NAaN*i3< I>p;ޛ[/G | {0`xM e  B@楸O $ն ϱ1C-Uh@S0 c'sYe0cOϤ2NBCҔe<6}w*JsV5d6xΚ+Du!E((KvwzgH'@6AiƵwRLQv6[s+:F"~"Qk2?7#a18B^VJ4J^GDz|"P'N?RuҚFcUC6n vNm/~T%ԝ @||RB@*W0Y֢#ɣϊ(JΞϻ@U+ Y/qC(9t>zaZ ,x;lW|W/S1RIG[%r󝐷dfRr bٶ]Pwk}S@oSsB>¾;xݶ~#XQ E:|PUR@*(}LokͪzdY<}oBӱ%"r hy/;֥bެ@(gz.ts2~u [ ʺi;WǗ.9PW>/;q}@aCK7ϳ+[N^9r9kˎq=HYmӾm7BYOxX_iEбrRtƽ ֬B4zΊ;ZM ZuiT>K7n: |gm#Ӣ/LٳJV6vK;i@`@[} dfחMk x+ MN5ГD[kR!#.Ib姞צ^;h~jhc#S[yݓ?޽.?DҿW{FF%XZX6ПB`err2b D!HϗkCq4֬0ycN}l7pSuVY F;M]s8N4#bqigL/UgᚾpcVՆ0~MDO aFð5ua?'8au47z)MO3$x^^._j`}['m<A5il HΖZI3$x-0 kb/Km>= $%{S3$8a2EEEccRlf8Np 7qa?G40 a&pc*a '8V yh* zK1L4W|cp_[3l|-1t4;>92*ĴFX1C cIۺoɷ#e ic{+ˁ!&G֜Hp7]~^Xʒ3fKAjoHn)yvt#1_*$4\8΁NuI;qQT`8[&>E!mo{UH5 xa͞~1+&8zdb&xbw;#Z225v\~Y&tPrqIsLJ7u#}~ے|y_Jkٙ6d]+7|Ŗu2o S<냤ڷ }P4T_JDh7hȘԉelр*x|hՆ)% 8}p5b\Ϛ7+vT|טvwN4c|ǁ5LMNF|1_zg_%-ni4`<eݼu`jM;}3uo,~~ b[gƙXYt8<&.0K=G~&EdPԛ{vӁ CNCEE~} YvSoѷ \y6ױbyqNߟABzqxlA?üʤw߿:)tzHߥ+xqi8'ٷ><&4dhvj<(ץȸ ,fTŹSJ 㕯M~2 ooܞ}jGVh;˷M4G8>\r)6jc>2M_s嶇uv%p}Vlc*--444ʛKs&8*/uM:w*nuul<`wo`'KR±d~vczڪX7- ^aC>@AZJ4 Gq$:۶,ɥH-Nrv=AAX>=$ }?oۏG֪݀b@wu4, ΌbɢKMS&u,7Bg~"B˻ӋY@sz0 ):BePP{Д-3prIy1b E~y׬Mg'=uG6/"9uF?SW MC^]'d\'FYZZ{'Qƕ9heLY[ǔ.##՘Ϣas@7`Aeak d}B+Q!'5~Jk:"SH2ֽ+T~⩝n<ˮ$I$\bPy]w.RBV鵨|sq(6Bŭ]7>f^Yej%zWnwA@l&ʹ )*kb$i=%eeÕ[ _|lo> i!mn,z$~k}gs6-8\2]!F#)&%`[Py9yW貑OVX<`QۧZHɥtO6!/ۀԐ-G@ j/*߲U*Q%<{\ 0Зm잊:h}N=`E ׇ#bÙ ͙आ^hxa%R4|>G ٮ[x <%ETO6 PVRV+7ݾ\wXaL|ۿBelUnKd(eUI{k/@WYФ5L}z/J23t{3aiӪPR3>/bOO!wB?~ܴiӪ+cPkoIpsCK1 >8 IDAT$'0h ;oqmS;of]?Oݥz0 nwſz]Mջ Np c!&L!9y!DH=YMU4fEq_ᅦיäiSztu_b@QQ1ddQkk\ZD)u7ڞN@EmF~,);{l]gO>Y#vv[:{ җ7m> Bޱ#lH`-ulw{qQr9YFl]-ƿ87q*ؘ_TRD),,7)[}q5C$0䐐iSzyz >~=,E~*E'/,mZ5GH4e^Ĩ'_@f0Q {fK^W qL @̸@G- $t6*KhOi68a4]'L&HRO_;έ۷7nڲyQ¦@P}by噱3|~ϋI2/dcn(&CcэqOJRUti,I-`&{;gf\VF!I]WGߚf)I (4BEU@ FPB?ѾZ Np kISCBoXviql7*/D@J 4y%iàGNKJpgblLݭTK{iQ%%GpwRP[!3Zt~A~,aȢ";;3g_VQI^LL=8OZq\sg+YBۥʮoY ie̅d.r@j۩%?,S;#>PTe^r L()]/߳2' mَ, UμS(.81 Ws{sL_RS¶nv?A>Ggx,]@ g~fAGA!DJ"Sӵ,!DнK^ի[)!^I-B. V_): ^P=!Uɣ )DUd~uFUP_0?n߾_ v?ön5_۾ ef[ 9Z~CUet]_8͚sc&fڛ9 { OCQ1~Թ U|0v~4 ̈7wU'n\H3>ۚ(D9MOO~-)1١'#썊:;U+tsOU%nɢQz|T '6 [%APk"G3WwoC.]ua%s 4qĐnjPJG"/K[ cw@G%d ,Sjcc۾ݻ< tҗ%f=Gh%E M[Phc];/3Bugܬz͵2O&gVJlDx/ M"d[3ˎx*hf'}ےCIaM< NЕL9g3YJGTckE\Zx3~:CNE^vVUeEn4cсN}V^gZ(¿j?){KvMoW#}V<]4>"&$ SVʹmRMS]ϰ5n5"L83φ浥@NPq2)g :[nϢ) LqffI]Z "m6E49IPP1ӟ]g>.@jKwvb ?aKqůHEs//=.N9+m& ,1_vХ S2h\3gsy@WWԢc3%9Y40;6#2gfHUgO0Le|Y6FRBh },蚸p4>ɶyqhE|ӔlQQ} ^{-@ +D^^.++S}VfVPߪ{zuR64p۸RܴdۊeZ{)[Z+R]&Z"a^Ku$o;bRپ}- ǎ[6'LIQg@7i>omzBQsZQ2Ę-v^of)ZXH{}/tƅM3qwuÚ[{QRzyhOn^yP[KҽE {\1R! l׭Zq̂*BI 6I= suPF6{L9XDzEḸ70z}@31@h[0eNGZl =TV{4dS;~K#r}Zڰ(ءãGSS O@ܪUK0~o3EAcY͑ķSD5D.ߪgoQ&B#%%/O"ԈB7l>ۓ}KBH`!$&8BI*LpT!$~;Oxw\6U M'OzڮM|{QBu`|ee |mpP] nG!I tSg___Eqek[8ֈIOW׶޼SΝ{3b.$|!C$H}-F Xݻs6k:t^6fT66<{Lq&:i}ۋӘQiܷa [xn|T|:p㎃U: )13wYgF~? oŪ,>|z΅;U¦}7?4†p\\4庚e4̝ݍ\dڼf0j|UmcAOG"Bc0uuƈ?J(ZHL m܈~:*:KS,, V!R~uJ7F"|5j_]]M TedUuL-duv1praSMx\۝A%jap?eϭ>0EAc&;hר1Yk{r3zO{}y_HMg acne>bmXZkbann5v{BٟJw"_+k A?=v$ze-\=ÃjwqT3_.#;ίcgioʑGAc״}ϱ]ȂBg:zUpc>VVWĀe~ miX074KjdLɛq(`<8&V j0%I_ 飕_ֲW\294RID W(?V Iz{!X;L5X@(u6|CϏHO0tx'J& Pp&\ӧW 1#Ij:(S@8Zei(K-Hge@IݎTUckcem~d\!?VRNܧ!0v{k599d2gM8;s L^dPW`'ߪTd|lyyُ;o%[j]^ {b.2?{ w˻g]򯻍D PVUܜ\T(YO`M>cY$II~y-t^N.֮>TQi_ZښLBai٫ײ|FJ^o_P]!]8ҕi)@*hjռZ_?p/w p 5zs6ƯsqF>yH5FM`Q$ͥE|Et· x_L1dZHHSdМ" f;"ӹ /ښt'Ae /mT*tNvN]y\ci)aS1[lRׇ/f~3K#4%B&[Rz؄vU~~ 3If.]J:4:U#)t^jC^MnLM/Hu&xECSRu9:7;&tVBEU \{o=wVuUϿ;I f3bѰ}4s!r ?̾]cIJ־W.iEXa FfNjHRMS]ϰ5nuz\R0t>V̲ז=[;C1ɔZ'A=#m6E49IPP1ӟ]g>. +e(}"D 5FA8nbjߤ3DuP_Fcfd'H*4CN1 Ly~~FMLr1"I6"4}3NK+gy} )~ڥCޖ3Lˠs͜ },\x8{Nƶv61P{|7σ'V?F)|anޭnVNK3=ױ+E,Rt E3fԧ0BFfdAą ΦI}/΋C/>/5N [AAVwC#Ǟ~l8:ACգ]z7aKĻ*ӏ-&vǸ>N6Garp>Lɶփ*xW|q'3iӏ wueQ<N}I;+г3_Jҡ\WWY?>}j;9zͧ7hBnط6i٩sWSAJ,:iPZcG/72 IDATzv\,Pqֺ{.l GMl \mf{p^KB^G)oL7xȬ0C7k΄"rLM;=x$ {Qw%:-Wwm".۰9=ٔqoUݭs?@{\En;8qMz=Գ0,#M (#{bҔ#D5tUZe ujBK3ckK/+g(6+)r}~Іf'<7.=>)1LNY黲:z|A{+M37&l Γ+„WJoHxncoy)iɰ ;&Vjߞ0Jǵ3m \moˊM^)~N[vRx2: e_vrpWJ#{i(LQXsV!5 ÅPWRicm-\ZCtL׸/\]݁|б/\n}gV:^)}O[L@Y"6N:,z-`RYEE^e:tIq)Kj&įU#? NȯPٞ|pv ~D3R}eC1{i5/ y6p ^u3P26mz}}K6I(Y~|CݵDT3++'+.I={憠l<]i,py[!;~:pHqqkC1 À"gQ:1Kprt,(fjBEhwg}fiE0 rZ$.su aҰEyvupr;mgK`pZ7ulkD;׬9GG}?xKNۡC{B_HϓUROb@#%?Ms.䫘 _ڕ+o dRƓ]$\;!$0Bu5nODkM(!aܝBu`xg 0BHRaIN;R=woZ#Z岲2m>+3+KEkp[5^?8S<{/L@ulrK H#ܑGץ{[F̴\3ĭղ}k7j͸`>ByUlmQsx//{v1m'8Ӌҝ~p'#brhĚݱCG>>IYYU22?^0/ %Sv B܈~BDEg KގOѳ"~k~gJrns @T0T:{ڭ'ܘ37Ts똸ԚU9.Mo-?1BF E^cPUUܹSII9222JJ omi!!`HSu(}ݠ2"cr"*ߓ7`D1v/\az~Ib[f:ĮZNIFΌ+\ ^PrinӒMAmNߌ>џt`.#~Fk˧y,!:kOv"'Vu$ b~ ^>9T즭_9Y#/pUCOFtx|>Lj~jtyGCa7oBǮ7cWuM^0 A:v^۳p)% =}Q7o^?2}U)2LCLpp̤n?HLԱ1вo}?2~+) D&ե12o![8ȠX=12N UmpS]E9Y)Ln;-vԕRMan_DʶmѕUtm=1/ M"d[3ˎx*'V>d5to[CF@futʕ7oFt->8~vPWB&|s>/ʈ~鿯vE+Z+R~=Pb0S m 3ߦ[AmarCo5?U_iqcVؓ5̭38jȽ/E~AwDK& Z 6* J4x \3QwE{Q@q; J)o#2>𲭭 P*lϮq/ hy$ ss* ? Ku,-eT64Ԩwr 6zV'Arܼ]x/ޙEJnW뒼Y1] ^ejkސH4.r5(v|Nܫu ]V,pq”v*,<Y]!]87*)=RTԐ$>[[ԜZ{PVe @_ҦL n3 @j6?@>`VԈ^~· fxѠQ&8(p:f +fYkKޡdJSt-ONk2c5rO/$jRPP1ӟ]0} DD0y94)-Dۻ[~a]4khkYyqiG?ϗiX )56 {ѧ Ex"V HkV7kmz 4䌆;``<j քhhJSYnR=HM;9r9+M.s$P Ƈ/ًEgꊎqPffi]iJZ'|$کn*ү^CO#²m V^=¶uU+z 5^'Dg }Ucʬs]^ZaKJZ4B7%)輛gҪj2OR`FR|fy<2W_>W[ {S;f^vA{/gC'7BFfdAą ΦC?^+xɷTK7VvmJ+fb'oԳ0,#MV?DI(v,>xӻ }|8#D @(;o^D{+ש!N[R&43[C\b|g^bSN)f9T+O/|G AG->^oobja{<ցɽgYv~˓ZM1Zܓ}w'}o:ޞff]ݓ m8ŞǑ^ʶvLԋ150W|l GMl>82o3?wfE;D"pjܝC8ƦV=l(kG̞Ft3_'FYC 㻌mFϸSA0e.swA!$\Ew͝8]1!\U} !$oTgKBH(!KG!I B !$&8BI*LpT!$0BHRa#G!I B !$&8BI*LpT!$0BHRa#G!I B !$&8BI*LpT!$0BHRa#G!I B !$&8BI*LpT!$0BHRa#G!I B !$&8BI*LpT!$0BHRa#G!I B !$&8BI*LpT!$0BHRa#G!I B !$&8BI*LpT!$0BHRa#G!I B !$&8BI*p"PC j.B5\$!$&8BI*LpT!$0BHRa#j Eʻb.-< !$Mv`˰HBxBϒW+csK@\ZPݛ OCYzQdJgIpB_gI?KBEY* L$ᔥ.,AFYEMeݛ #gEA!0BHRa#G!I B\"+.E5R-~1e!op>,E.E\Y:aA{QB}/!$0BHRa#G!I B !$&8BI*LpT!$0BHRa# .//#\BHlyүG }% O@!$|֭I[!B5o= j,!$0BHRa#G!I B !$Kxϟ O@!$\m=!?BH윧ڴ ee!lK$!B5 LpT!$0BHRa#G!I ~(xՈ㙴~}Ye>? L\.\.k3L.#T~c=HUX>\~ݼv^UN>RzkwSv6H]:P!d:4FYy? n0Hq^I0PrqJ]?Đ_ˋÔ-2̒w=]83W ]'+XNEBT3aW&bo" [9S+8/"1QH[@4u5*MOnyhIH7v'G%n&G2Ml%j;X:]cwcJiiBLɓBnQE;0Ϋ|o!߼JV2k/TVUd Pt ?UCg[vɛ7qV#TT/V,.,r+utU%)$ȷ犚.)ϸ>-Dt%g\ʀ<V0( hlR]c9)( DotI~_ˤflu Guԫ JRٙ h@UVV pnҶI}"ɻwNuA5BU]M߉~Çe@MV#h}~~>-sIc/5mϬ qe³r(nfMd+^iM>#%\*[+;;Rx§UG=vhʓz8z%h2"7dm=z]tvui8~dn!Ʊߌ#%y=\mL,`KKo!lA/O~x6/4ļv=g3 rppv?ug|N;S`p+a]\=}P7f!'ssv u"Epa;c#O*j__ZEFϤ5Ml'!;+;:zN~&4ډ)t.xיʄؓN_x]wG @ >tb_iȨ_n~9R*`?!W]Vtx7>oے ON^Y8o :3TACh.>%c]\k訠f/yGpO=޸}[؉UWJ|%=,A7z8 2>4Gt[Uu;VEM S_Dhhk5H5uU IPRV~/$3LɓBnQE;0؞t:?X%zSʚ-[3N0_E+x?4!"]YMbqa @*K6ym]c?=[+Y^sy&JSGT)JEL EW-;?v`>p ^Fo瘲]{jb/XWt0C*YK` ömJ5[&+*iN9TԨ9YIsiZ5O+/A\WW/;'-|>ssZ5u.Fu5K~f WJKWp-"Uܜ<tIj_BןnҶI}"ɻwο(ԿOK)*RWW^rvUr,;Xsf %#?WȹoΌ LԠ;[r)oKhoSnoS ޖ1-e5BZł,كL74kS^6L'q[ہ`.bav.(`ʋr>q6n| ]X_뙒BFM;40e//?~R¶MqU ;!D Ty{CE9a7+@()z΅:Hup{^]$U8B>p`xEi[GH0:>z6z <`Pi@DGUrP P$`uP% 8Sj/yy:"]˨ԗbR͗^tEv2`xϟi ;lor.},K|5hgIF>^ޝ璱r>]3<===:`i8sAv{U˫6l1Gv?gMkmq0yˉ+X5}'OQܿW WB }f¥%&%={߿AJղ6x "VpWjiUlm4:>+;7;**oWrF(RO&iv&$L8NbhreaJ9"RE2󪉭.eV xq6y;vx@[[KKKkrrr/pw6Lͮ )VWwU~.Ot_EG_έҋyWe$BZsde XU#VYYYUUrY,4ɈPj&######\Pj$ŗ"`#G!I B !$&8BI*LpT!$=4Mr& Һ:Z$M~K~ %t' k"q\߅B%ߑB?B%8B.(xՈ~}Y+7r]_ki^~:LA7yAdTt[bkKwH( H5 {m QD AT@P@6f?W{]}s&v왙۾ge-^Fr^랆-}fӗ+]Еi]Fr}u3;0lѱ%SՉWL("qakۜHr̒BFf%Y(w7wo˓ѳ6oN 6}glDZ];ġkE_trI<T-=]BǦ{Uelwݸs]Z+~j;yCe–o^J=x+ NΪ!_^*i?w;x/818^JJJJJJKEѲՑKP{vrrv^tq!ty%^ݜ^YoY{};ٳ[GҭKĖuvp¹eûuv}ʹ7˵{wݭ}h6T Y?Knluq56],hȞ]vuDJ@\_7~STqҒg)hlZX&& ё&qܚ[L$ɨE=n7ҳ ytRg@8Zki*WU#$zcBxN3E8&8$%''%'.!Ng>/onˠ./_pA|+-^|-Eٺ3Ztt}Xob#i2aHإ4MGBoDp-;=8SKs7?Ld,pd:=qtb!yRt, ,l[[/sO%024`}}T}/пo7k:<#rvN:>8h5¾1[B<}@!z|}T3SS3SӔTq^Afzn9vtѝ&tג @\ag#2ANWWU䅨E|jjMD׳/BڰjQ^Am#k"%%!18xn<4|\AW? `ӿIʘ4zuN>Y]0YTGXFI}`8c#/o'.< rru:N,w=F:sLh{̹ʵ]QNN٢r i4p (&d}j ڶUPPm)O]//*,"TNh%E~^:xͰi3UH =p04.`<ʙ m-uݤbI/BQE.+.}(`=5TPAՐ4| fBɠBȫ(7S^sVrJHn vM(uޜNq^=zG& +;W겦j*" buڏyÂAA|Ymr՚9*  !.TRU@WV*+ЅփTxǺs5{]2$/qc%g@Ӡ @r Y%cʪ!(S /_Ÿ0XwUi ?!ŕZwDpdB# Gni >lRRmq ֑2绷$l*o>!V8*?)ZxxqS"ޭȈ_@ 3bc"#nDy<\0Dc##n<㘨1q/ 8f|>?/Zi/_4J^vEdWɻ3#7g]"#eRZH_p(1yik;+)me+C 6^ /^]MCMN+NV2Mnw}V93K`LڑϥU+zt!*֬>]o?5@ޖsyg> TOs8UuThI핆츠SoFy4('vØJ /Kq*2Y[ 7S/` F}g?ΫwPb)OBӴs'9qSI y{COR[^\-XE)L{)Y_";*%$u"~5QA./ѷ`0 FMƪDlc٦S֕QZ=T 2B͐m8{*`9|~ЫL^bpYuw>_ER7fr~zrMݹiURkk~Kn1h [/~|i˦IpBDz[6>0oAݵ4;3b_jf˷tbT^ؑk}vtt!]xw@3tS/l[^!,%}ku#LRZ{M1ѥe/?Q\R*\mKmKmMR"Aި 钴q5m.I_T&+^vsM1λ,E[VRP~Qc'/fmVz-K1~}l=9<|kan.\~~ǫI⃘a[]zge%ٯsB# @KJrP ~ )bTWy2%TRWc^bnCo1' mbb $Y$1;s-/>pyI+ګ/{ YhRT.Wѕ%k22r9A0U,+~hak]p7bt4P' RZ,kut.y0oAe&$ʶГ%T0&%%n&-&$Ɨd?>(s+}K!nlٺ%??)$_ O0%uӓ)NxA᧋a_rOL$SJ"mK mOoteU'5%y<.zB}(@qʲ (9yհp^%~oA_A|>wUSyL+9iM=WO xTVńߎ7xfIII\|r5!B"9iJ| R-Z0)L{Pť`Tt;hJ@Wd=(Դ҅w/ߔ[kCwԢM4Tha`a!$4ڙRSdTqi^{K+˛w>}pONpBBJHT\\PW^^-"BEWzz…22.F;0K!l~(ʷJ*5Vc ~]'ll,\~A'%')7B?%8((( #\j.ٍO'B!> B !ƹeȞx3՟\\\R*$Ŀ%_ ]rqzNVV.}.;[8˯ˈ{ZzqƫƞQ^]~nv6.[(n?APznkn&n~ p^[?ޫCϱCkti]m]PxE?Pl_X_ qq 5_lãwqg-Y~~WtI<õ}4;cq俾H^V5 [6m7wĪc;(s^+R1?laN;Tr[Ϋ yI=ip`٨7Ayn,xbw,>KNf-ӗ<ѳ|_͗$Ijjj"K 2Z6ü:ܛKQ⟭giA3{[*tyҩN>*3u|,ֹ>sŬBqF> <<'m;bafr]vyN{L+J1y=q*ѧZ g#%*vS nYwu I},ܾyp aH3oӺQ÷+2 q Zv%iٓȻ=tY1pf ߥ_US{|]wi J w"lx1̐{K<_Ŭ*b4yFh]I^oO IDATE0\*3zFǁ=5I1 'vbח^SYO\wQ!ާI(+)ZWиgKUpmͼ3|gF>_<Ƌ.O6` Iw۶3U>{r"[M).oen!iJ0K|ڮ9q‡k}m9Q.8uَ >Dv{^2:Zr)R}{uhF5k@>FC[x]Tm[leu'~֛UVR Z^{]SF׮W}}̗|hou %odkk<`殗lc'M k9`Bw- &0yv9"tu^E^zQgixp=:^]YR]g3u Νp iBUWŘRZQ+%=.rE=%WոB/=h᲻+7m'Mo;^ wFȣ`i驾 OȫSo)bzn*ZtH߉z* &u\GyI Ɍ@y7O`8c#/Flv5$~X,RjK*6TWU3YV Xjvw>5Ҙ_j^L'Ү"BUnVW.),d;lMZc?H(umpF_c9#;*}p|ɛE^NP^fW 2HULUbíBwK,UzU~w+pr?cSx) [*4Mi`l6@Ut%/}+^Ny2\8Y_1h"J*}z}n E99E4-&K(S.N=L@͹:շ4Cgph+Q0lP7g'с.KkF:u{Vx n9|Y~nӂ2?O=81Y܍07eA#Wų ttvq͒]_wu8PXi(¼>NNo S{N ;<[})o7~ò~C]8Ō-6Opsrrv,5n`}'8{wjE&;;v;sM%xE_| W ˶OӍfOlPDq@;.>J!~~}l=9mc=?Z ~:R (IL[pJᗃg2Bq6 2B !D&8B*LpU!$0BHTa#G!Q B !D&8B*LpD&h|Ea r7Wѯ  蒋3VoƶY5$F2o[j/OtQgj/>Kn?u*1% Wxwm8(ޕsI]`\W)8[cU&,CG 7G .xf9|_ȼx~KL>w }KOx& 8[fT~ԁ77:6;4caD?9gnkOG݋gk]z +Tv_v۷dn=yc9bXȓ[j!-x.ig<}0tN37`#SFfWGnFz.@[{DžI'x{usv{Ehfu+.f%r3z-l 7k{.ΞLy^ݺػZ@ >_/n]z 'ޅ3.?|G[s޳[nK Ν-ޭT1o .zso0^.]z YxyէW yw^Sf*'gNdwd@{5Iq)Vl84z8CԱrAng NUU(`(mIh~Iq`0$ٌڌBEg>/onˠ./_pA|+-^|-Eٺ3Ztt}Xob#i2aHإ4?ߛxχ1&u0wV <-Tk?|a;\ˎoM7\W\|fyroףO,SNp7?Ldl~L .6z#;Elhna-[PB}- +Ϩ}ickN \:/gٍ-Pĝ- TF.$ֳ[{ޏl}~MlwSJUc'Iaq-%A;Laq:"s`]]#̆w7VmZxA_7DuwjPw0}WB4)gU/PYRo"BS `hѽc¨K ~a~a㍃zn[CufHՖ:chxTQ¹}n<ͫ!IȩLǑ{A}[~]y?Ç!z0QB|-g\\t5vS ;ev!$) &rA&c< !!<ͧ@"/R\ խ.<f/\ŋHė [Y[Go(C7_XW EE/!8\&]?c:,sӷ.ۊ M J_$#\9fl}sQI&DR8ڳ% Z{A|>$$%xw~#BU9 vky%ELteHĆrrUiill |"-[FIW(n"&'2<-<? zΘfGݸT|n[UEFK_ Q\R*\mKBwg֓~߁퇏b-ͅKQs)BH$,% Pm& .e`!D&8B*LpU!$0BHTa#G!Q B A(</55R%--ebllG(i:jjܼ)L+~f:P @T|zEEp B !D&8B*Lp ¥? &8B}EK,Z q!JBB:u`E:v 8B;A| RcK-Z{5cXu9OR?%Hc?չNw Ll5D6UvG2VSf54נ߽vQӻ^ԢmݳălUN6]sb7m嘉 7mR̟,l>{G%bd2 rIl6CDl}eב~N ~sCʻ/hyy-@y(m"%)gw`C;vس;PJRR7BU+WJhQLѰQ_ݺWH'S)K ^Җnkp8wVN0cs~Q P*dݸ=:w9bnP ՙy<;s¡^%|oa}yqvCej/!D33-_|hG?1&Ol~2Gl;Otl9uxyvyp*\q蛡k-^mr7wnJkGLtҕl=ݕtcĔ024`/! Pj"$M4$ oOomBcآ/ka?ؓG/Onǩ;9&ݺ_yW`jIwE(t:XRT'Ո)@H3)?V-|;ANҳ҄Vj) }xArɃ[~9 vdǦ&ލ#I5{Gۏrikk)'k&T`2HO f6};G4gWT^4,f'kYH W Ӽk{bqdД6tj/'Bןa?T'v! L[6 RAsRmԾ=L Lt& ͻ+|OeRt貈^ ޱӜҏ7^0K?v1OM.$i$LJkj&Q AzxD1u,s偌aku1@)J-MPfg?sGurܸy¥ .[SIw#[3&rC6ONѲn~Fe|[*6{ ^8qRVUcړ]d+6m''6Opsrrv,5n`}'8{w]{?!$dU>`0U. $T&|֧Lto&%)9w/o3wx9 Q\R*\mKBb8 &2K󣛷|M$>|kan.\pB"mMw3/!%Kݺ߀ B_c_0B"-!$0BHTa#G(22ҹy¥\F~3ŋ4ߗp QHlD}?8B !D&8B*LpU!$0BHTa#ѿ{(V!ԤyL ]|B GQBHTa#G!Q B !D&8B*LpU!$0BHTrSy1Gw8PJ voq%+\ ]K).̩oS ~r>@2X2*V֭ʏ >зGyB{(ñmĄ?T~nM  Bm8Pлr_xUʕ7j8{1nj9_xJt4^wCT<;1zd6Ⱦyb2zkũ1RsLE]u>Fԇ'O?*cva,{sRƝ۷M%inOebX[Og܋'6O K:5OOqTAЕNL3/ XIͣ%MCe/˞䩎~[tYٳ%R&MQ/D;r&Z|Q 11q;\uxm/ʋZ?k ŧvwݿK rB_G1kO9-GjBucnb˫>y)iK&P11)bb/K]#9!ooUh8 4ϋ|-Ҫ{7]|Н\I>#uoEJzϕom׽{uxt7`٥0Y.zT|N8"|UbOobG'~QH(98ʓ@?Ro8z.t^>{glƖlQ]JF}a)ili W|SNzOx{!08Kƿ$.mYI 廟Tҵ#bQ9^gzDv5,yuyلβZ^S}pĞs;>>[[f$ U?޽lSɮ1J{\+.*4cItg3k:ﵑAa{ѫI%F>>cG:K^Y6vUы)>vD ںkd꡹wne`ͺ@?c%۩ѹ\ 7s'. 'ۚC]Tʞ=Qs='-Ļh^?DZkO)vĊĽ{rfomF^J+<1q&k}[Ⱦt0̹rBr{y}l" S?"ŀHM *!N9[XZF1n^k|,T"|B˴EÉGwg< =rxxVZr5$j@s>Y>OӌXTwd\{NSGs_Ɗ?U+jS"*_XPꪒZP.-\ӡ}k9RmO7<"=m.3> ] V-jK Lz;(QE|(b+.$t'j'QPkk¤ QsSҊ m>vjLڍ|b0ثޜ?J~ ۳km,>Bm׷)k;fwnR}mDZ$]%=h٨[u/sLn߽}jzG^ ߍc f{]t+G{7^}עwD/x j9p{1&'so\Wϻ37ߏ>;FVnэO(v}7߿uqiWS }y՗c&sܹ0M>ֽ8. ]Η`N7Qww?α8I]0`Չ1+'vRҒؕl;!IDAT+x$s?~3O:Dӄ,MǾ]{ ѺFj7w/F({Ν=tR܇/x Fطc׮k#`? {4OC^Rm,AWUTjv5 b~fxѼבG2{0k=|H9g@e=ˢ _;zqYNyg'XB?=6d̈Ԑ/.Y4v2# henBL$ӭӶWաE7^h~kϟSf@j:F tYvU^6zTb[<ol2*].n!{sȡPq7 \ fglg:[7#ȼ#+4JihV9t57rX#s&z'n2t͖E7 fЭe|"#kz)da;CUI*y.sȶ`ã[G>(`ij[qwQPf M,Y$ml|o>Äu)b~5kũgie]UMqӐ,k/SVUl "f6Kti"鲔^$ŮWI%Xͣ)Y)A!I@P]]`R>3nU}DK.%é[wLSW:sn_NphBF\wZu3fPg&{m_G0b+ygNSP"eܥIT0l! {wd*"r޳d%Jp_kOn}b8&uÑXJ, u!^&>A+q~nWy'p“XmrbWgNpmaW%vSզz!ߩ~"5*&V Oi$Iǧ;7Ie}?)AY]SSbm\zngv l H }9OH T~v`j6P3Jܔ"Z] /Kf1xŠiVNZ6uZBiBF^K𳓒 ) WW{b{mTC6:s\.&%$#Z2 !$mevSim$TjfgJ*tM _BSN@lFaa |~|̀'2kviՍj}S3GD*89V`͛ܗ1(v^RdX(v6ig8fNwg|ZdlӈƏ .<5cέ8"U,QzJ@$g+yK2ҋ|*9Iv_'L#^'0˸y) b0jU,ϖ|n!6*8Y2O u#UXYjV'\CH Ԧve 55b& /oI@G/vRi&36m^dFmtߝ5x3'%!Fj :3ߣG=fFd5ބ@G,z:k]+qN6Y|fV4k.Ϩ|~Lة?IJjn'k_15 \M{c7?Cޑ)$0 y>2B/iӁ Ť[YY1mJw1]Νg*T :y(Pٌ] ;v͐6̀zVOKв/^؍K#9bJ-zPQq۰r89}XGBH_HUcCSi%ct#_Nb. |uW|!S\9wp }3oP;6xσ'`J)(KJ1r LN8f$;9s>YMB壨LG[eRZB/}vl߶ RAr眔5ub}N>PYŘ%մl# ̃£rzp_>I.*Ӣϧ DHYOhхKAFrTz!"KJ˾Q\|$\^ҖcOM;/݆:_kk?w5O <=ߢ.orZnmO"V>mqbmV8ֿ?{(\}]vyg`)W H[:L/}mg$v77B$1AUAdz-&L ig.O:wFA5MbQ_ O(!GG!Q B !D&8B*LpU!$0BHTa#G!Q\JZCp)BF| -~r;. EQiiiUB&%-А$k;$8BB,!$0BHTa#G!Q B !D&8B*LpU!$0BHTa#G!Q B !D&8B*LpU!$%?{VQQ!\dI?5Uӭ&8B$)9YG[KMM]7*akCYYY?5Uӭ L*++RWWb7Z[5zaB4M ޚ?5WBHTa#LCibB_D!$p#akwG&7Q0BHT( B̈́ m /]tt000ӻw>}7TGr_ho^B,[]S3v ԋ)ǎ~}***34ʼޗO ^2/^],X()኏'O}(A]2iltM#Heכ&7^EӴeON4AIYIEYa]˖/oI:' fG?LMM LƚU)#zTDp\GSƖSSԾB"i߂ukêo'Kk85[7o^ I')⥋&\K7en]|P!\ 5Kj&8B S3o k̆FW^]bBKA^Ω'[K6o/&B._;f:?%?XE#B._7y}t͐rvtyN^8uK_a&ʩN.nNHtYp {w]v9Q;f puq0t644Da#$jjjΛ/%%ίvR|b. T_= ^vتfli,-- qccׯ3>M].rJ'nmytJ )uˢN?4^p'k?ڼ+L͍7*n9+ǦX%_.};.:q_w~aYP\| I0A={fgMM͜ydea0&BU 񄼂<&8]q%U5ܟ޵1/C M-~zXhc{YR֮}nW*^R$9v5w+hItq̕}u'\ToU f;e"))A$ڏn&OV^^wn+mXGlwՃMPUQaTYI4Z ?_Jq(^UFWQm#Pׯ/ISNݰaCj+-o]Kܨ8֋fR^Fe:hsٛgcA':umK ˵~k.[ࡃ}>*DyIPg<`EHHh$IiXxPPRض~*+b(*)^~zn'z ӧO' Oƥ5Ofqs~.',Y)G[~}MD wCQ--,֬=g.%@Ӆ7Chj&aUnȭ&0RQSS4]TV.Wi9/V4u)uX 4ӯ&n1P )c9jɚVѶhQ\R*\n޼ \[i۶m-+5hr94 oӫןsW}B" xGՃ P3|].5`k|i6ąBG!Q Ps &W4#|p>l5?0&4&8B*EAHJJ媩 WdeKinLIii鋔JߔlCIƷj>GWTTddd?5Uӭ' B d"G!Q B !D&8B*LpU!$0BHTa#˚*YIENDB`kraft-1.1/manual/images/nl/company_adress1.png000066400000000000000000002576751450127457600214540ustar00rootroot00000000000000PNG  IHDR.( pHYs+ IDATx^w|즑B EE@:JAD+kX^PW (UQ+HMPz  ec$gOf$~>y3gvgpdvB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!BT %[!B! C&'P!B!D(R(t'H!B!DEF2)c B!j; ۤp{B!B!MM1PWVB!BUAU|NvM9PB!BQbo z !B!*.T~*:] !B!N*P6A[Q !B!QQ7 {kƉB!BT ~SƩPÄ9V1VDNU{>B!BQ^Um]'V8*Ofʻ}$ʳl+B!g_m#U}w QU'y^6hǍ6MB!B,Vhlj6?Ro4))B!B!*G z~>Hc%m/ʞ(Ghy3f9f2s68=^VO!B!up7cfۉS3 'm/ʜFX䛱pm'fNp"͏4O!B!Dd"|GѶ9 ˤ&Ѷuf_m'N9N1]~7eN!B!ePΩ)f2sm̾hTt~*k~"Sh: էs3cf[q !B!80&flsL̼P}:/v8GWf=Yfhrt~٧ss[יhDeF!B!%eLGm[q+TBkM~4QIn4GVdpu[ۺ~?l+B!UQy&uw+nu[ۺ-))$<.7*9tHtnbVTm[=1VB!B!*܌k+zsέ_;mNۺC47ҼT9ұ˚TL0u*봍xu}i+nfv!B!M˒V0__&Զ&\sݩ&yQȉo$cG܊f.:s[ 8ǝb}B!B!JT9ŝb\ p<}i9n1)\wj$/U71˚T0s tgS)8NHe!B!8eRmnV0RmDg:/"1dHrt́}vѴU,eU<C!B!*C,&nc'*Tl#Iis3̶H"ɉXEL\#,9 /xf9sZ[kQmB!`VID~sCtz))n.uf̩$V97͉d]o;- ׯ5wKK:>8B!BQ [['NݖN1lm.պ7]u7ʉH8Ht/bfbf9R4.X#B!UEq spy9Y,0&,>SVim!B!82v|=֣Ym*GͥۺR1gƜڦG,PS&N1/#YWbD}%TL-D3D/B!h'fن1uϦt"TZF/yB /*/T. f,f3Uq34c43m /B!pf?\'ҌN}zYpƩ/ԺTnNBJ&ƉߜGүz\„9S<Ըz 9[MP}B!Bq( 5aΓv̢ZyzL_w%1zm]oKŌ)oX'Tdi2n>=n^Ia>>s|_pZµB!BfNfJ[q)? .G9N}RqBA*[E:vΜԛEb|5[YЋ* ԺYͶHr t)\!B!8ʍdBnmE}KyC]sESzYZmngԶjir_!^\q+nqnnoi1u3E -x>s|.m(]LnfT~!B!8؄,Gۯf\պNmU@3sWۘ1s]̘ĭ-,BMg͢`ᔧrb*n[ͥޯB!BÝ9D]1'Jz)Pq jm5U 8gzjYe8p) 5178'b'jj9_00ԧo3uZW{I4B!Bq E3v5 &~3 % m>_mr|@6PXW9*f\uf3~XTLPXF+Vzzxv?{k<ղP:V9PW\(pjM׋f0P vzFS+f$B!B˨Q'P،>%#h1E͏z>+´+UE.cr3BSz"\ x:;B!B!Diyc!P2ՋGAuxabNm/_&)\/,􂃾ԩZWK j]ާNv1ϨY/(VVY[7sa!B!"sW6P ⅊g~}-5>mr.CN~VEyzéQR0 2ēb磰`?{x,)`3gB!B,-9KGZ5oJ5aU̘=K# ^P7Ó͝q5gW.\drO_W'պb^cuuMS_Ss$XHD{%B!Ӡ^]nJZ5ojvѠ~=ԯG't*}7/ q"j15UWT8:9SxuBpwApA帵4M,Zcf˶MA~ٰoCBa˼l&Ǵ+B!Bqiռ)dV͛cx7Xb٭N կT+|lɢt)J!źp~pcfb8= *`8]cϟC7S|6x&vhaܵAA鱢uI3n#B!F||u'r z,{Vjfgq˧i_]Gvh]…mRB̥zXEsԲ"נ^].}6=475[qbTVL gN>xtL< wsGq۲,F l]za\7QcHKN4!8tpy{1d\{ۻ2dTǶiűmZስkӊV- x_Xp1O0|튔V-}3ik>/u3GpuŅۋ3f[t0b*n^}A evq+7ogmGm}I!jSu#rrk4ݐiXT!m>ϭjҥ *Z2BJ`gHRb"{'3faߛ_/m۳p1g3i37Q;A=.<~7+$۶,2G=OZ}u(EEEzf׫ˬ9b6vr74:s晩BqHٸy3cM+}umۿ2,hhYlޔ֬J6x⁁<,X ڭ[4灁w;h..Wcإ# ,[D\WB#;-pWY}f[qTe.`EBs[֯OEIJ_u?mؒz5KMG˲)''k{&{׆x8ooZ4s,Z|x>; !2lm^ V{/y1斻GrمSf |ȸIҽkgbj׬ۯ/MMԬ O<'/.jd֩Ͱ_U7PT㎛ͦ[hռ-C^^ƌȏprHMMeL/Z vm~Esxz\yED^3f჏F/V?lCmwilL;U_t#bͥOF yW)뎛͢Ki׶5N`߹kiݲ9qCOVv:U]_M}}̘#F ޿B"VYgz})4oژ0⹐.!>ンW3̵ЮM+f2Ciצ~O< qsiռj m@BunEeUaBLP1T^`"[* 8 s Uم ~Tqi]\O/E }HھV2>͖$u4SYj8Eb#t$;\<|6vBQ؀a7_gݷ[5kٿ?Ĥ { l ym,ΜMAa!A6&`}ـbjڷmͣ9'/o}u7J$lƻƫ-( ТYSa y\zQF~yJ[ I'va#yo(2yǘh 3SXQ>;S/w+/'1샑QXTo3fRXX= WOLufBÑ sm7'/'_LfJDX+y{︅WV"*ZXbeP_4q>B7Z53PRxױmxE a`Qrb-3\'v|@.s:f;zq"P}jSegu .ӋYP8ZOvV>5\O#,B\bXo/m/WCJh)/ /?x/ZRBq0sXX,\ IȂˊTfzrvNZlݞtŸۆsd[={_.Vb˶si|$mbzrwݏ|}nY|ӯla٠+75m1Mo>|>;h? Kdw??\P>w"ztbvkיm!8ԥ#gcשʹз[xyhI]V{Gp,qoy6Xja+uGT:msϪJUq9Mfn5H܇7Q?P$ zɿoIaє?B_|%E !8X0{<>3?I3O Jg㦠 =駜Lrr i{&yš{vNPnAa!^ccpQsyXl}8%?f o x<+ !v9ϯ[]t~oX(/2d=wroFF^؇&Ʋ7\ :F`n-N˼? - *"%EKȵl48~}eH{mdepDf?QR?_Jս.>>j;=l-[ZM[/_B!46n"{^ ȲYfm||ev5뮼CO=/Kݎ;yw <n;d=nƾ?/O Ef{V6{ Yђ}y˿ٞO=O~Ag:`N5 !ġ.z '-楡o/9_P 1+C/(5-^TB*T8ݰSYl۾U1*6 bcd:}EZh /ltz}@ԷXeL6ذ/"< v?8u6-xT)ỹS<溞gTC]qAyl,;dל\jEE-_K-/\wIB!:Ufyz?L6a BQ&`Q/\’e+h_H/UPۆGHv_K_OgU6U_SO߫Jy1Pmj]RB/:mr]aa<2Ϲh1 IDATvm+{mXGlEBuZͼUll gWB~G+n !B!ġ-iۺ~Q5#g'%% i=S,9O[.􇭭Oӗz#z-+.E Ooȡ?t9N Vv kwۑ߻}-!~<^سfǺ"cވ;:/B![ҿ__>|u矍<`40{x矍fNϪMfK5)U1v" ]WIP1Ez@3B>G}VR=űLsv$X6u8ԒSj|!B!8|2f,9|ʢyixr{J jސS/\E *ϋUC΍[[*pa6j;s]|#¯c%NuXif7g8W,fs_dc !B!8&= ۆ@V-U&YY,Zg1oHȭ^0}mJA 5UB߱Sim W ' ̸yu=Uf!c뜬m,;+( &O];VAJ9B!B!۶sB\* mZ\0o1| [RTtBp8fyիRzL!B!mT[wG̼PmhƜQ^OB!BQyo4NsaeXm7s9gy;f J(urUZzBB!B!DQ#35B֋R IݾE2* 7s;R PNWNPg^>#B!BTeV:1slb8RTd"܋pzVl;*vE!B!<"ӺNo9nKsI2ʓvm}t !B!UsF:U̶.zEPK}NqVB!B!sk~t|B!Bink[Oi^LU+.7n'ʌq>C:z{B!B9skoP1}n" r#muoߎ3B!B!"6*洮p/`DsInGEbB!B!DUb[&?\)T_o)P(TDrs]LZ:+TΛ݅؀Iftͤ*Ϧ`.H/A(!BT 9lތ,'BjmF|qmdŴ6zQ3qu!&NHsPǰ`z=V_5B5:o䏒L:n}*njƅ"< }]_Zy$6Ǎ`&O'%u?}#&~5&KSg_#^ݓtϾ9_73օUeѸILkȭBB)9ۜWqC*D*n}N1!!=w'!0zIjI׾< V`L?dJoy7Bˡ+!Akfbc^!ˣBd᢬3mTܭ_Qr؜/})5n~ń97LLˤV|vmbwe%ePF('E۵]gdZٛ}J߀"dBFjbs*ܽmظ&o?;vϪFzzu\_X>;dDz5^F>v؃/)s\mߍv&5ꑑdh|ٱsVJqex)Ɏ=E$f~غ3^@=;ٵ?Ts=>O Vi ;p%-켿),\KmcyhtAeƒ\4xx9|gLwb11rG2  yC'>DbHOaا߳p[zGk? >-6Y$BQ[Cd9n,PB D'¼tC͑s gX7m՟cttca'; iChi ~[&y 6;ŝdq,/){*eݹd?Wl6, y_.&*> m˙2Ef2x>GEB۷/Wl0hk6_2<߂Q<79&哳fc_ПΉ.Exic;u~e{KGҬ"|.! ɷ_>VAbr=3jD&n#B"FW9w`F}yB( ]''ٻ`.KUôikЧm3\jipX%o*^L|F,#9o{,Z߬z]%0ygNЄxh_gbob+yL(Z)<~V9{^͢.(hC>\,"64AE o7K?z u_>uRKcUF/~!5Mkէ~LJrt21ehAqeUVԯ}4*$)BT-g#sSc*.b%MJHmPA_|+)J` FfXS9~|?E\7c_ 8c[y:ķ#X{KGwCM=LfTUx!~?'syI nmg?Ή.Hc_gӽJ$/W{RMN!B4hr.Qp:jX%,jvL3uEz \o=7"Θ?;?/ҸsGy7,Z1/&h<}YGHqns3qHhy<{%ݏEjJuvG5\ް}lK V\ \R#,Z=j(/:j-o#?2՞RI^c_SwXڏY.A/3̖ԩOBJgfnW- kn=.3 ^Օk3GΗ͔gQCZ%tkVdy>Bcc 6; s,BCJ,缱':by v! ϑ 0 X6w2jdԅ '/Z1EsX_MЩWsG>6̜Ɇ%V|kzvN`Ml9mh*X2M as_!aբg$1si`&'ѭ掠q6lG}}:,w,z1?6cڦԅ~v(o3l.G\ܳF7fpv o)\6YY<)t<-E[ɦiB}f%uUB޽4q\ڵN-ۙ !`TVsW]R@'%V !*9;d,|\,)8.۟{XItfϻmL~}RY1w^ӓށ-ýn⏚sr 1fMq49חL=GЪeR|f4򂚧+ZuJ+>b%r?p9y$'9P \yj1O=gQq#L])Q_.??s ?"0k!#i{Z-BNQVrc!BRlyj i˓$8h%жS "u'y'h#I޼dcg~WL%zҩIM'ͩ˷]Q?3 EJY̨ vV"f o𐖞o3ggEBsI%zT 1=B!߼:ܟ*u-".(,̏E oyO9 m'3;zcWfϟ$ [AmwtnǜşUvjy^=1?zboRnS}1$$Z-[{Σy P `ő\=0OߪO΃׼ *9B!aICYe`!E !< /lAh撯ݴIH)SxKҼGwy2^:"5]6sy54,|IRGpCI%z6{rv݁͞HOO+9v&\Hnhl|y!By!ޡqb;nµcB,a@r1v$sDWNl00aPD#yQo>Yb"㨆yȒe9_z]zrq7>} f1k3OR7X&";ԗ͚5-,7vuGO!?nF9XϱB!^l"`WAqo]^%U6aV_A?Nb^Зd3b$lv{c.E|󞜬k8Zt>5۰'5 txӭ;t&}9i)ZC>e%l[u߲ǥޞ|\fOjХ{`o7 }.D(aUp,L;ȒbЖӶR_B ĵFZS>FƤ Nxcl?HHL~'A{k'Z/P8AۿͮJ!BTY\F+_1ɭZ'h-zZ?'͆KQh|'z@mT,,ǿ-?OQqzלYF 1s9&dVp&V ]∄c;>i" ރŕ /O<:f}Ff%ѾK;Bm~ugG7˹3$ddϓwS~Ü9W&?}6ˇsϽq홴5i8MT75yhpoϊusy﮴`9bLy2dM(]ͩD^Z}.-F?&pOl6" a,VLwq & [} ^.^MD}NxG^*ң?C:zQ[O9۲d뼎 X!c+X|[ٸnぺ4Tr]#X|$y C߿'ԳÙzѠۿy+hl9wjw~X4;_3=;cNOG3걗tzv'Q/|Q6I{'}wn _`Pzx rרP?6U.;_y7vGsX%_շwƳ3vF<4;j2 |B_y5 &}mK>(%FSxWXnS/GE3a6|u:r#wbk My)^@4C&,&N^7ǞC IDAT䠾4Esŭ8}Ls|h{<7j,͛Y$\y#[sqiUx_07ͺ7 63ǚV <=(mGV2GO]"-M7d|쒩ߊ.Ǘ3#,O}ο"S}U?3? N7kpLB)O19v![f瑙DWVFOl?- mxTf4.?]G v*z? γ/,@ݚD.ʰaS o.b lTЃ\|~ RE Ӧlj7>}@wBw}6m*{㤣`:l;\;wpIB!4cp'x>lx]A1hOu3{+YIͮ?fZ f~u/GOۉobp2+'hY'ԥyoO̘6NŷohUNomگ&/}|U(Z/|O:[>Ә<&͜šV1{י0.!>-lh ?ֺ?G1I lZ>Ga̟vv޺F>ɸOΌϮB oœ ;)q0w1|<7fOŵIxb,֡wrb6LnaVHlUΞ H 3@牓;5։ƨ$NE ot՗;s%-xXq $Dm9<96*֔`Mr_=9!|"Z›H\JB_|qJ 1lRtgrǭ])]o39'uhu=k\oB!$.*XuN|#W:^ϩ\ϓ#Vj u>/x2:pRDd_RixiLB6ߊ,ϻ Tò8863o]woAo'Ѻf<leڱOK^- _ycG MoUOB}hu5?͚\sdƃUoS19˦hO|xGxIHm@5ݢ)qad,:mzv~b'. iHl؃{p&mup|+]܅mf:OqShVќqJKvoZ|Rrˣr]niXD/OIiت+^yCFΛH;;u=dtARXOcT+nǎ4t]rӾ<}ztoCZ)$x=xI}Eg/sAEr+:\4GFr<j797<Lj7k #O៏[/gFd&x&PA3:ǭO ㋷I^{kd; GL!GbZ}Zt;ccVZ;zu4UgwE${)GΦmqUbαv~G:jS=!5hD_'jEX!DTޚoo-sGos[353;K2<5htZy=|6rQD.%{Om2o3⭏iv =^|;QP _Øi-ΪcœG*v䰫z}iO] ?۟d<֭Gԧt<PV[^/jiO~x<`llo/_yWjSG0x=+>:L%Ѡs_nܗ[ͮ(ĵ̰"ܗr/L;F;FE2g<Ͱފ޷6"`$/%ݵ`}7π59ɲEg Ӄ>*WN}s5] ,O@ٿ+h7YX4UPnB s9⹹i37UVy#f/ԓTTtx#呵cㆻCވDEM"gʓm<3@fgegCthSf˵L&ńÍ V OhKй[ڍk\qp.E-(+5wçѱO{Ps _H SdBFXVSNT|mQޝ]82qP#0}qcT@"yp&>2WcшM4xt!B h@9K2J3675^+dd8iH8o26=##Μ=K̓uIsA_vaUj,؝_dA2H*Dilq',B!]\!.eIf󦯍y}ʼ+׍zy5%8dd:ogմ4䔝BӬJŶM Z!BTD!aǰiI 裸pk/˗ؙ_`͜ `']d͔Lz{1i8 <6>Kǥ3_B,q!^X ..ZYc0<ǤN888g\IO6h]=gdSduez5(ՠ ajGw'©֏6!%{PU5K(޽KllyȅԧvxVenMM>"~ z6'J񧬛xu37r1YTQd)BhTQX;oĜc[VQrnYEvsXQu8q6>s=+$}2W_6CqϞÚ3a)GT"ϭgey sf1pqf唑/I7wӬ9ljMEA"V̼+c4.[?bięCc,r&#mԈe>/8o !tαzŌlR$.ؕ?fø$dqǮ߇ jqsxfKzhAޝMƻ*o Ajn yS֝!HuXh,6c.vN=7cS6M*'GY0y6[=&^k2G|S΢oÙEy jYni#^3Vi=GƴcmOx2v\Y._~L2)z '61cCɎe0 ;:dnK;f[x‚dM cb R  h\·CSMg, :ظPr[Ms'(ڒ)=Qi;l4Chsy}[nAnE:;ץLrфM֦"tìWCUA=&N^O"__,I ȟCC͚W IT.ś&A5vYIFM[ǫaNHĨ(bQذl-\KY4jCݽi԰7NjvGZ#Xsc~^nM]0!]>e=j<ջqYԿsGFMHdΊ.L;NO9CFy+]"P#/}Jb{$bC|(q)\iӡ2[{Y t46ofejXgD./Kz{6MÙ|b/3Yfi~C,'gc~H&oSi~cgP˝|fv.v&.:MMELv?o#[`bBS~_wets|;r5wL`ō:ҽ~_fu&A k|[4.D|?u :q"_7zvwm6c7tWX)gf4d\OwzX%zwnc5uf\0u֟zaw0Y)Џ%wt:$d_yA[D¯\ƒsO~s[gQ7wLey/M~iAv51#7nE5ۼQlڼ70{)\|ߢc,#9v#׽lS[呁70?laϒ))ŹM8wIޔo93lݫ_$'> <̙v7gnE-S|Ќlga&lيg U[wg7T5{BQ };xLaҙL:ZwmsZrH̼]fV_Ƚk8Qv(˷eϪ~:9Y#?ʔ4~\19ùgq:NHg>DSE-5(#شwΧW..zl΂ *^̍pn9hUT6r#[Y' e^Ӣ)؉6o9*x2'e.0L׫'r)2?s.cXz IϽlK^~x[uFrE^Xv8yѧqAl-5,~AV (9EAk:uؾ3:ߥŮoYr#)*xSJcgc32&m|5`El[˵*ÛB4[|nm{6Ih4Nkߚҷr~[ТYvJ>xH+th_ݭQ i*lxS7zXH(>m8 =h[E%whUe*tyZкK846[}jm }aZ|ОǷr8TŐ[ݎ)ꀢ8RnUTm28k`j&l*Ѻ=w&PNZ: Ψ%^͸ʼn3el_k\ *#rߨz/Z~!u 9cog? xW; hY$IO!+@G+$`^̇m*)@:%SYTU k%j%$(}.iARP"41\ @2kdVdڂMֲ(xp?8K*V g.s)"Q !'r%z Z(6TjԈ6q.Gۦ"8 NQGXx);Eqt`<۾)m@Y6&Ҡ4( ζi2gi(DL^rqqp *@``YN2///\\\JnEF7ūAq.IO0q>ф pi]ZcJY5)C8!$^_VKOR66]xyqx>$uc 79jlr$ -M9~-LjaꅧuJ!/r3PĪE4oU%ܦvºxo"6CEm{{vЯѢ1dbSYYoc9DŽ!2HmC`^61F4o+xq+gbˆ1D=fLA%7-KjwW"#ZBCPNNS6gyLi\pIh#71BSU AOƒ: CFmU4jADBj2tǘ}'cfhA˂D>OV)9Ψsy8ֻ~NSה}DƟ!'Mr0E!~B`_ eWuQ 27wz4y$ge('/Nt 89*)ߪQ24f1e!Dj\x~32mY%f~z#b¬W>]ke5Rx]5V$'ْxt PY%4ڲ͊>EJa+Af}F:j}(}:yxR3ʅ]9LJx^ܼZ€I9!,ȔȊ+WTp ]]]quuMnRG[Ow“G4ȶ*SbMh;̃8` Un<1zqg5v& y*b4,x(AEM `(wۍ&uZUesG-XʙDTTtQ\.GZZ\ta[I)/\#kWlqf*j޺![r:HWL⌛B൛CŭcϜ߂%ĦPYiť2Z\Tyr| ۮY?hzasuu뎥mLjI@ǮyTuܔLڪ- s…Ka$c/MɣeJqal_@ypcg M~d_'MJNćuָe,ɼq~4zڣ;K2~&2h7{KSYπݰ?eΧڍ 5^/Pl+ӠZrͪHC%6c>?M̸O.Ӓ%־=% Κϼ9='#p݂n 9ѳ2gLA[~YoBdąȖtcJW|y e%>>>+WK,i,S.jU6OY˸{Dmp+I|Eqoǒ4c61$ yw4{\Ƨ%#!cw _9~8SfҫWDΔ4y}߼M+pj25CkgN;*?NcjFr)D#_#M},sVoyok;SAjՎ6Ed|4KJ-7}o2cS.gwh: }fNu3x@}e iѸ Sx6܈@!32(O(|^g' գms_\=Yy?t #s!D mI% ?r-MN|>;?la (_:mR@K\~JRڵ 2Z kTOKù6]:[sj2S{LҍZ}Og[shՁ%ӹf >+ؿbVy*F^{| /_!Z,(͘nt|25^+N127NR&|gXxwdљgiPyFTT>H"6uDDppp{2-sHHlllN T$&& Z2Z-Z65xameV<(1EN !BSXp/!w]Bw6K1_-=5\\\2,o)?11DJ.ӳX)BbRbVB!r|RyPk_:V!nbH ̓2IGWXYYe~B!"sݘyB$p!R@<ҥKi͕+W40ޏ"00,ϟ??in֩jE!B!īK"/1}mSYJ3hNPEB!B/" -̔-[<) 'Ϟ6b. K!B!. \l0qq!PtiZ-/_6J~IYB!BW.De%0k3XIYB!BW.D`H}mn+ͼr~B!B!^}f R^a~?^B!B% -&OӐt:yt:08;9g clm(S Fα uq&X-3B-isƳp ΅V{Cѣic]qǷ}ݓl54"nUĴqɖ) 2{~,9AcW+Na͚|9+J[sv`V@w|m92cn(@"?3}T˪A弢_[%A&(ωCi'.3/|Sߟ9SqkV\Ѻqk6}MRbyt B!DΒ_"[TU`0`0$_m~yFVGd899:ETTkg~&v4 dHwsB˓/20LpYZYW-hJвy%(شm}pCéҶ 5(iȗ~O#xr/nGuH!RoVW-(hغq]~(6c<(`Yέs I4uѤ=@&)z4gm_A >{1s,h~ĝw~qwwρ+ޣiӦ46N{3F5U%ҮG}ـb[Ks>pxz7ȋ S.iyPB? h\Zr ը V(8EUP}!ن"$ 5(C ,ڃ>&q5Y ј5x.kXto~F_7B!DN6i/X**%JDYi)$p/84O !8 Wg GH'st术~Lig-;(N.8#"=!68Lo&`vN+4t:|-V=)ߢ7囿4}>nӆPID K4Di댳w7P(*!!ĹUH-ڎdBBl6w1jbʌꮙnlСzEfM-Y9| 87G aK >6*af0b*9<%4"̞VKmߧL,Fw}jF&wHIBGR^끇oj?$z(.;EQ㢈2'bn{ 7{~FS/7B!^XߺBd<@7nNm,j+BqrJ\ I 5rE4q hTTEhF!g-1:Sk T%oJ 1wٽw2}$sbf.&y̭pT57bOт#8C;5>NAꔲRpO{X *$κm7)V׏|[* v~P"yp!ƺ*ָ;G.u?I\Ȯv1#-H&,B%_xۀ{{.ar!I&4ԬOXt4$TŪ=>~5t8÷<=ckHPpqw!u'b]FX*"v3%[UuKG[oA"t3$]}3uykkؿ|cTЅʍ5ǒLm ܉HBEkqѓdB!,"S,2挝$^U u>dhJV.ɆQ<)\_־T qhlT}G[J6.7RKСw"HOiԦ17ƥ.>=kJv7,exk@똏o~B<8> ^kCvE}wkiugkO6 ^pGbX[>[jC&"JO:$+E1F^setfm-7 ' 2UZ<t^炽sIZ6iJ}-y#;m«t P) oե+Nv@+@t:=hbn>O\ NҮ6;dCL~9z S(&Hd@5~" SAm-iVfv'*9+)t ((T۶'Цu+TZ޾s^R"PBAB! \lRUB!Bų"GH@!B! !B!BZrxaaaa$$$ɏ޴C՚{' !B!xIBsa5ONDTTy%&&' Ǫ IDAT҄rYd!@钥hbIiZr-Q3etFvkooO|̓B!Bb$p!E0(!B!K/B!B\KB!B!ȵ$p!B!B\KB!B!ȵ$p!B!B\K*""t\v,>jY!"'9::[, $p!"׹v: $yB!K\F9߲Y #!NtL-Bɛ7" !B!BZB!B!D% !B!BZB!B!D% !B!BZB!B!D% !B!BZBFwiZ3tyxDn=`'B!2" !+"GG>hXǏj5iu\%J5/{e'L4OωE~TP~hso͋,Co9IPF +OirϦ -μdb/mguB!$p!^P"G.;Kl#Q*OϰXplzf~R>᳟`(-;8^]Gsĵ,鳧8'FukIZ9Jk 3~>NPf)MQ_y/$O1yLDqx$^Q7B!sgAʕoVFF3O_QkǃQU1)%X=g/^'2c5 cEz0 k|E~jx6\M]T|ۧ-A GoNLJ|yҬQ#T9<9O;Ŀ> ;gkї-Rǿ 'L| [аACZֻ)]䷅Cѡ5M5L'Ub..w=S2qǧte D\Xmiذ O'ZXVgޢym֕\!XE묻ȴNa>npbhT:ͻ3r]]VN\HS՛T+䆝nJRImJDtYl;$bX7vI|ܥ9kƯ~K[Vѯb.Y͛Ҥ|.gZjStpN@6M[&~{2~cj{rt4lҚasҥjÿ}?f NԶ' oc̻\ӷ!BWQQŦXN\s'u'9;s˵pFѮ0U0Ó9 c45/#U6<5n3uOod$.U6;Ufl?Y5l8~Ίص+ꊯr$p^"'~9H/83lϾ=6Rz[c߻N0e1'Wkǰunu#` .ur~|GN7`hR[E_G{aoѩ}]x 4Ui@uG>JY_ wYE}GQq]H D@@IPzH ]@b RD(H/(R {tT@$BBHrw# ` o_+;^ggZ)NR8{E2̸AOvUjRr*TNiG~ ك8>5Er|zMT4t>,-]`lp!J ^~enK@\L|+nL9F"K=+7W88 : KȏoQf΁X1<{ҽ ;'_ꠑ ^wBlz9U~bnCǮY*< h|zch.-exz:_w1vlùkm8iJ)"12.ޞąO﫣>Lf Nsq,`1۹̝>G"أOa]b,цKR'mR#U'A7ͼny!#_йޜQkqx8<֌o_NXv) ookEsNOf,}"zsRc\F͟>V=ʹl} -f<%Ä@+´^nâ W￈MGsٲuMM8ZY{ګ{)CC^櫳Sag+3vmִjӖΓGa`fJrjVĀ`v7n ݆#ÉrE@ګ~~x Mj ׮Mخ_zʳ-ʳd!xZяas66 [BlMakN$oHv~ )bDujͷ_ ,a )\ 9s؉Gn~X {*g0ObϞQѸQ~[i䌯M?_=|4t1g)'^&N9N<`fR<Ư8%;`…cG8):lLܬtCaqXv/'R/Wzsj>mW8h1_KS^,L^`'W*%#2|6] 'W'ɗ o?u)\:b‰RӢhڄ~EOKTAe)mKq2|Y\px>i`ۚ.es,o&|6%oi6vI\xfD5A͗_b YJI&)J`Q""""vnbiˎ7X74ӔҔS3]ԲSʒv=>u1c2h޽T~cF{Z-&6HxEͰmXLנ0+? E ̑k3&TwubRo-}!8szX=yNFԍ.?I$Ui}Rd7~zGͶM{rU|X993:-cg>ȸVdY|tV$:wfi!|֭: )m݂XLj$~AR2!pu{:K-w (c7Qti]ٳw/ʗs >m݇>KP1c0i0Bx)vTW;vzH~׊ȃjM:OݱsW#) Hr(]O)RVmiFJ,uq%Uڲc]Ʈs׈r\|(\)cFw}{iZ Ӫ[k@<ɑIիOM Wo9d8DvS1^՛ ٹ d&nEKK#..g; _xx,nЊ^}_{dHV"""riEuǑ*ҖRe4vX%( {|3gx =\M#;e^Ă"""""U)q!0;a[a9o;*ubLj9n*""""""$%.]gc\DDDDDDCdYJ\Hąd9n;O;ww79/=.DD$ *ZCsQ*{ݝaO,l6SXcXDDDDA*""""""""Y"""""""e)q!"""""""Y"""""""e)q!"""""""Y"""""""e)q!"""""""Yc@DD~Z9rظ8*{-AAͺ֟(q!""YΑ#GU""""ܹsa:|bAUr(}$""YNl\"""rΝXǰ'q!75LտVaU-F\}ƓL~1,""""""r%.Hڙv(y!""""""7ą7gc9%/DDDDDDt o_QYv]pX1$""""""Yr_E]Nbǩ(ǰ"""""""")q!"H2Xއ7ݱ.X0msoKtyY3:&9$K\;Z2ͱ&kOgr jV@5߮ńW\K`-vq!5a)H.i2łfiRֈ°yq!._C̈fn4Qu{bnnj6+VgST6y#VNYʾݜȿ2_/l e&YSߤIp|Ēuű6N.cҗ;?5SZ^붻L60 ;n3.u0z [9d(o;Ve`~֝[29ݓ?7""""N7GBx'[.1JNǰHɿ\>xSZgF8en1F96ݻLϒy:0pfn:MbǩԺ9>5d66cs9Gap.]‹ Ԇ1?2/~9Jxɐ>p6' Wd6/`CD$9aM_DZh G#{B&+qc>/ˊ}*f9d#g%3>Eɛ9#2c|NoD=;O`(KfoLI_sޓ#b;0FoG~ .6SԊuUG/Щ9zɂOP#z NǸt9C2c)ܦ:$tOjP-9HB_gHn- ed|8c udz~H>՝Dl8-+9NFSF&g/ hGSXy"{E 끣 M glfѡi’6q"ʎxox/jy`T1%7f~ z\æSqUֽ?x;,yhąSFBR!E02?]OIZ\V&}:rO1d5y5k&:O"{&ǔ:|t-Mh|~8fچɯ0Ͼ<f⡔91?G\u7[cުuokc]O5lXt90a;}%KWŠ 9?eR5z',eEn/PŬ[cGfWz%_oO72`_s9o0?N\3gS*V(Ey<.`Jm%2WHn<[> f+;VN l:'#3@i-v,'Kc&ӀϖofM%-L~5s~W: X͢(_&W\oڋKaۖy|+O|u*B9QK6stv]);Ht)Iݨ]bq<| 5qzt -@3dUg >~:Œe8g#)HgeNp+Rg$pK`ߙs`6s(z|RwΉ($bJPmg:ɝu)kGcP Vel_+6_ۗ%UZ?ٜ⭛tt-_O~ِHtN3d -)z쬿di85^zR^Lhղ<֭H>rԤk<靝.i/`d ڰ>f ~ߌ7qEƁT)YR՞Hj@"ُg ,R).v_`B0ِĞ>Mgq{9OK dRkfؔoyhPҩ;R|i/éKt%G6~H`& )FsN}eQD\_&?8 IDAT|S۱Yͯa wZ~=bny4h̝5P+|3'sqxLX3&,˜ S3#Ö1\ٍ=>'P:.^~1}knO0;aq-iEʟ0uI^z-嫢ѳ^F /8䡜_$2և&R5h6Ԝ=[cSr < d?>lxf?.ƙ/{K=4&eւ.s0)ler8ق$=Vڈ5׮-f۰MD]'4څN5&Zx:..Χ3۫;O$G9$L`SX0vc$oK흚9`=H>J,qI?OF/%w0a DϤk-ɔ9&rǛJ߇3rz|vS&1;f~ƴϵ/;ExRTyP&3??޹1xޗIſ3tx/cd6HöFGcOC՛0bJ~ \ &SftS6̞xGs!ڱ3crp'ύXƀr r݇~:Lwxvz2=d |׿' s rYzf7}SWjτ.۰h;nc=ϭ<2]"QHٜp_ƃ+noz ){gW(,iխ5{vw$'j o¹ϐP* Iw՞9wF|Ϩ1ݨ?4+܌~%qkydF,O츤Son"ym4e4 dKSvJYҮ֧}.FLٻ768JS  p _trB:ZqeJv ߕ={R|9ǰLJz5Oy3;w=kEDD$k[qSSwܕiy{y"Hjl@C9zj=MٖR<=lKS6Rb@.ҖRe4vtnvc5\:?X^w,H|5~%MZąH֑Zƍ˱ M.\-""""J:nr!E3kX!""""PBOW:HC""""""SBҹ.5+~H֦ąs/ff!""""""%.${1!3̌6DDDDDDӓtRp7n݅vݍs""""sD#.${ѩό63 y0-ʡC9|c=NPPQǰ'J\H:{!Ȍ63 y0f v #H IǸc2hCDDDDDD,J\H:&ff!""""""%.${Ȍ63 y(q!܋ ff!""""""%.${Ȍ63 y(q!܋ ff!""""""%.${ff!""""""%.$=N~1 V"`Z9rظ8*{-AAf*tE~n|`!]!"#G/0DDDDs8tł>PH12y[-i,D`J"ɺb┴&w\:>ш I^N ,X""""""pPBҹym3_B+!"""""":%.${1a7ܼ| FZr/Pc_e>ȃI IP"tB IǮ̅dfǀ,":9t֗Չ5zO[4`$ byBv 6~QFv ߕ fQJwY;`ϧ-2xK""""It XDnSy]CV@jhG,;m JV @{Y ϖ*Ӗ`cxG[z7?o42$ a ǀNYo0 Ty[SfK/1el&pʙJS:;gnTXu׌zTwNՊژo"`ԬqE]~_u?Ck1pkI<ͪ1Ѱz*TO 9^N͢]]UD8`37>mRr5j4ĭǺэ3z4|*PqW&0Xإ"f̊\#v^ۯP6\~aDsZ7UHi7h>s78N\>dɲ߳,RC Yl)+~E2hіj9l<ڍI OflJcAIqka2+׮b^V?Yʱoz wݰy 3۫, Z[D?߶s#V.}Gt66}$ҝJ 9PaK6}DKH,a?##xaj&E#Ay^-s){bo~L+ؾF3s\=)_)NC\/)⶝[w&TeJj .Noͼ:vnZȈrrrWmNǝAV# qg2evr7Gn."""wA IxDے-&O'3&4|i0_n~#?ߠdwuƌ<%+S'&Ws!\ nE*Q?ۺTmܲ|g=v- 0R3r5%J$)\L|*xGr^2)iaeM(Q,#ԾTu3ذK|9wu -Zş) sWZv~}_Y4/H)/ &BjY r$y ?yɟu؜%]b[5 wfgBŶ)&w֩Js8c3BE}.CulV7eQlEv+#-2;Vmƣ+4";&Sv7L"4/vc֋T([r{̣-=f""""A@$p =7tܒ)4:G|55LᔗtŚ3Y 3Nڊ%^:/L 24 `W">tf dvN#Xfѧrmԑu'S@nD^$t7'%'o/qaDj$H𦙗[_IF8Q|9!o#2<40;nQD=3fra&f/fED_]6v{"vħ,ZIpO]씘5qqOiv7n,OT"vǺmxW@a '<uzH+e,)8)_T! jQ7H8S^>ǦGCPdlSMxxR%Mjcz!p+.>sFDFg`䋓/~>xn2n2@4/߄.۰h;-)gȁS&1~* נb46ry)[W<,D\ WrȈR->kb"GvjNSuF;!""";""HŚ='ex.<)'^&N9N<7/عK`,`ᷕ9E$֋,Hp~wߵS;&<=(gHI;/ X_imSA;krwEHA?;_#3~C)rW_±#w|arߋЯ>39!ͨz{&:emdWn\)}gYqˆ哋8u*n2c~d4iƪI35覦fCP.;N _CJ{dNp-EH,Uٯ씫SȥYq&ra7,>⏨_J;9Q&""""O  0bht7oP 4jz`2 /gӻ4՘~+"Ӎln6!gӮu:tR;py+ jӎ^e؞`VH"`&oh#/{&#^?#q;_Oti"MeAXAwy/Ѫ}':B!Mexöؾqr268-|!ըҘWǬԻL./ޙ|ձ7 h|L_BJnbll%PtG?WDIl1 &ӢË u$ݚ %|3MeUrwFdMy{,w~TN#WpTβ :skZ\HIΟlSnz2`2mk4⭥T,82#$y7 #=)ǔrGY$q$ÄK4 `N}ąܽle:z;Ƴ&cey)#m24UDDDDDDDD,%.DDDDDDD$RBDDDDDDD,%.DDDDDDD$RBDDww7Ν s 'Ν;cX}d9AEra=X%"""rϹT1,""f v #HSEDDDDDDD$RBDDDDDDD,%.DDDDDDD$RBDDDDDDD,%.DDDDDDD$RBDDDDDDD,%.F ^/EѧLqKJxwjN;n3"wxilW#VNYʾKFDDDDDDA%Y7!132g쇴y/w*;ai =R2"Z9rظ8*{-AAͺ֟(q2;{xC\[ޘI0~4#X(E~tl%~?\ïg/P'M8Bߌߺ ΩYi?,:t9Eh8_\x^7_(L+t z\æSqUֽ?Idu'AgH׆0}qK\6jٓߓ˛Q`.stɽ_>n90;Cfؒl_=g}>gY4fQMg~V%C:W$_"ɠظ8%-DDDɝ;aOx9IR%̶e5Zqnj~e_Y\fҵ6 %}qvʎNS1/d]A붥c`lRd4avu؜%]b[5 wfglJwH2}SgS©(ϵx alMK%o6(솙l:mvY_Y4/H)/ &BjY r 7F`s h\$"""""rK"ErjDDDevlSQP. Mͥ _\ɂb3絶f,Ͱ~!h2;h8 \3i>NXvdh,<9J\d2iOY`3fr[a ',"M1u{"vsRc\F͟>V=ʹ%""""""FśMi.9sJ"s"lvBxXx&fWKr IDATQ80e$ o_\JaьOůg\ۙۦMu XyPI4y!$HN8/p.̆^.瓋F,c@lWۻ&7b_>=|"-|eEDDDDDiCv9c׆;-„+4Ŏ=3яb8 x %s@$b#`t1҄J'0vqbl t|q7`ۃG8p,``$XrRD-׿Y| .GbٵSԮf4iƪI35c7.qQ`v'_P!LI$^^VDJ\M#y B.3hBr]0pb@ZT|}{i""""""rKmhRiӖ&GkNSvJSN]@4e%zj}j7bdО{ ^1,YU]b/壪)ߋJ"߯͘\X-衽7 ŷ2,]1@ІoDҥwe޽T(_1,;wwW7nyꎝ29-o/Ͼ@`MYl@C9zj=MٖR<>lKS6Rb׍,ҖRe4vXt֙tZy,ZD'i59t֗)0>mрۓ+lLN 6~QFv ߕ؂H;'%ךCX}c83!6qE0dɄ'=Yfovr~wǺ\*[9o4cQB=Z y~cxG14]X(""""r]D$s ٽk[WΦHȻϐ@]q ^*ĄwrKw@*.H&ѩ<L8B&L3w:5&$&!xon"̣&ԪY6Ӡue?Ģӿ1&4h. ЏyE*UJH|=`dǴwhl n CN[2>KZh3}i[޼ B:+Py n<Z!5C~FsC9}Bv2$ipZN:_'o xiUp)ƥ|#b13-C2>c+~Y><17U}M~˸+Ǿwu%%""""rhą<Ĭy+}tq{ $*jVkAkNV]JiKQUMKmCH"BȸGc5B<|$׽||O``ujԣ;uyDoYނV7Y,:u' e`4xu2ٽz/ѩn.Y{>؇26&ggiHV,,ۉТig׊u>GٰZ=):6u&0b:a4۟K)/>NlTI\H`s[sz2/LHHn+™U zc _U[rp ez|MYd /G@1QD;< z{&#Ŭm ^39.L L~s1;g%Oj˜ܛ+z8H|ܵn00wWe RW`'_p4v箎 .D[-rz~$o8)S!^`%.D?ȊO.F X .S+` r~Tn*yFdS~n͎WN+E}xF+p!mxStw-kyw8Ր,+*"S,u'7 1|D\_J<%D,g8|J!ո%~nkV*Ԫ@Y}"D¶-`@V4os#vA3, {lWEΝ7S$Șwz+W} s[?ˋ{1|)'onOSBD0h\{, Өv0!~DT(ƴ/ՈyA0m:MrY"=Q-U76?5}D}sƍFo3:4υPSP!>orɤWih{jרAPg)R,ӭ8-Z>Y$g->ytBCp,1ɳ2u%oŗ: ssuxk^,-\ve `sTwq-Vթ8bΏ&ݷ5aL'""[2Zr9@hPP|ys_ٻoU*W289vߎaVs۹kkEDDڸyMܵ#;"]; $vS=9n'zSH5,i47@s\`0D >]DDDDѩ{I{߮_GR1Tt5w=J\ȿZ>K649dZJ\HądZJ\Hąd:""""DXX'zd:%KC:r$"""ryzzRd sX%.DD$ӱZ.] *"""""""""""""""i)q!""""""""""""""i)q!""""""""""""""i)q!"""""""9 ""rv>Ÿ8s]ᑍR%Kb@ %K62ÿ0DpOns]C)]IDD$ӹ7spEsX<ϗm7;f>k$22*5BDDDDDrK|:x9 <??_sXDDDDDD0q!$HR!=psrHFq!"""""""F\}q1Λ;vpiK@ԉbE"%.JJJbԻcXp!#Cs,r1۵[puuGDDDDDD[{&))Ď;X,oזvmRX芣GE,\%?O?䅈渐{fԻcرs'l& BR%quuՕRJΐ!l&عc3oF$Sr.5油%3KdM?J b s_CKFijuD :N;@rZ$"+ąGc…X,Ə}*+R2b 8z옹ȽgMX*S9(ݑkr;nX sCe+L=iQB閽=Id? 3t[L؈p+Ep8h׶ +U27_Jʴm晛E5{vdYfnwY} ?%{yY<)V#R^w`x`1~`ɹ/[oAwәw8$""""wrOcڴ5\_+d\jסNh'ޘ ѹi(ҨIcjVՔ$ñ83`lfwOnҫ C<7rǮu+&jI~Rz4ClEk8e77*uZ-cDLl̋-eZPZ*z V ݄ۤz|,HOL=K+RuF3xȦxHԞY:9?g2bnjh\Շl#dKzATLޟ|9}קjjSMIblNc^{**U<5""""%%.H{iD7#oں"suWY lv+ޅqlV|6 vdOIpXX KS)L6 N2V/G웙2[ Y3g8/ʹG/^o6'We:4 ?K~>=CF3mȁO0'yg:6.@甤ƭ2^/&ubІSC;Nr*O-Vt>o>=|^%LW _;lSƣvݷ,Lժc^@E1l$sbΕF9׿קyśiN9o s3L#&ʺ+Xт髷kG40n U gfqFϪC:-!f/رOgƨ*3$"""pRBDurSuO-MɯS@GsbU)+ącT+Xs>I2DED_t|< [ex>Xެ^W\×{ZOIX,ߙoKa쿲ru$A]:S6lYM8z̖K472nTk .!RաMXsԤU3,YziX:6lxWCi>m`%w@ !av kM+6!وaο(SZ7Kw׼ilq~X>x;+Y&\@rճ$OeO2 [>Eb[-saݮ,vxJ.`D [;)px4ҵo~h.I|"ٳ[oG{/H9zY0賄]S9 \Nr.ج\c ۣTőcx}HL?+Ž@3DdtZO]ב#RzšOq;ǕW_Ity6C1xVj=Fׄ?߬WՑ|׋CH 'r,r bn)`BԶK 9 bNü}SΠWy,6||i>l * bMnŸ)Yr?)Ŵgw96sc6zPN֯Od`'oT;bZiY~lXk ەS$X,Whx= xY!K|i;rWG,済 4S E_s.sUvŢ/cZyS'sHf&.{aJJ2ײ="eCL/EK ֳvӌ9r.```$¹X\1maT| j\ʽѱ?+eS.Ӥ>͞D '8p,ꖟa釟w^ǜLݗ:DT< ]S6fz,?s"1-Nje9s֤NQ# lTJ1؊4y]|/=^O9CF sHnsxTKj7z(8!t] N,(6H&4jҔzcFF [Ieg@ك{A5jQw8nB0V yQ 6"GCQ|W0IXڍ.\÷dX'^%l٨$b2h5gV|4N8qaV:yau*Jد&-`݌ѓ;a5VLj7oEDDDskVeyI;^llNZ.N :]RrZ{Z\1ܤ\9+^4;`jyIII%v܉bmh߶]C=ƂE Yb àj` LyͻNb*s&͡t7oBw>Td+-C3 'uj[s6z?]6O Ue-7us;~+g? .@\NkOzeq1Nu#5-l\gI\7XBWWW>x:Ǽ pї,\V:~%*0 #,y춈ȭUS 81w<~رSN)Oӝ:%yz>,1aSMDDDDD%%.(VM?]DDV >樈,}!&"""""""rK׬w֙ÙwQfMsXDDDDDD0J\-bap3t0"#ayh )i-^4QAyhąd:""""DXX'q!D#D^(YБ#&ӓ%Kr(q!""jtR氈VɴLK ɴLK ɴLK ɴLS֞L *anɴ|m4f1o7sHu8&5' -nn@#kJZ;'J\HądZJ\HądZJ\HądZJ\Hą.E0]/Z;Z_f_7Ȗ!~[{xߋtm`;dW%W!""""%.D2ue,_J7ߙ䣋ggI}ViS{ubN Ӡ{OZt5wb3 T"BfLjwj7.`)x<|=-T\*ɔg+ 9VR ~B61I)}*Mte\Nr^fzFQjGn' E/f\/u)SHd4A`~]6''7<J|rf=_ ۫[<:^_CΜ勈#V͆fłՖRZ$dݤWiRZ!yn2]6o_0KSj׮Gvo0}G$n o_ xY3L;4%86M֬=D}oqp^hBZu>t:D m+ҠvMw䭅r@9MҨI(#b~HoOaHj{W&9vhƫ 'pov~:i҅!9N|N}Xs„V# ky5rqOn?+兊جxoGY'XpGP|ؾU#اOafX㺔?k,c ΋/Z7S~Dp&KɕԀAty|ql6sfj0dOIfX,k[^) 1tiW .]- 䰁%+K!gb< F2G7n|gx olV~.׳hcJ#dZJ\C"aԯOul\>ӓ$z:"2EX5߯^07S{NL]9{krXay{802ޟoش;{ɧNȎk~SVoȊ86yKOolRd\Kc(Վ6\+ޅqlV|6 vdϸ ~>=CF3m8E|vĘ^ `#-br\'&mH1n (ʣ".Is҅&VFݨup,[ͤ;?PjdʇՇ?8y"ڷÈ<ĔWV$Kgbq-+iG3\EDo^yZҵ^~XlTiM\{~k\ DoYނV7Y,:uw\fMdmM<=Rq0R8ƒ+T>"cZ1+r2ajiHW#G*=`"Jø6ӑ[N\ea;O {s뭳f͆{ecpeAL'Gldqb?G.;OCВd.7c,CXQ`X ܽsO)fWn/cрmƑBvi^,;V O4xiEI৹s8*IK<92eo bܪ 3g`A50(tmD7Ek' w~oDDD?G y8|%` 6lǛ,bԧyaD8bxq>qN+gbNMLs`p6'L3^OyT-Zʳ-,39mFAL-;^=yQKGQ/4F<7ǖTf8Ӟ-ƿ_)J`cpaoe?L&T&*~,./}3†g k[iwrRV~4Z~) kńPIi$'p Ջ=AԿuII.9͒-3Zh1j&͆oSTT}Wʷ#ZN=3Ϥnzx 9d"""" FD.Ӥ>͞D '8p,4'M|w.8GdLL8ҭ8GF >[ȱL~psx'9^0!;ʭh\egMZ ߾g1l)E'ӻ#I!J<ӮX !䬡11SҨJ8IEm+_ڒ5s1%m:8=Hf8,xd|FsVT -!~>&GrzD =LD,^j8nOt0lPsNijhM{-H(#C3$[ccD:b`.C#X LlӃaɸ(L`|b R7+"""r@wXZܹ\7/irk-_SũXWK\NkO9?w>k0E2n]ڊ!B46mܼ ˛}R9,&K\e 7H/5EDDD2~<ܵ#;K2d;NԺ0)CR2D7l\gI\7Xs*wA7)e.W=D.EqȽe 8uރ1!""""n'ɄmƨK~,xWo F YR~s,xWL\供O1tc"kgIK Ig]7Go.9K9n>[a]Q<7|5aDc%# aŨY1rOg &!/^TM륌8Ϯ{>AYF#.D6EXST+_Wf)&8:צ3cXw|;MR-ᮋ)7D%`n4Y*5q )BЛjs4Y !?oaD?tGi> \HM4\a{/Mb-X.~QWϤb$_ŧ='صsVz0_o߼IyWd*J\>c=z)/4t{I͖ũV6z'l£ҧFAqB TBsuhTxAO!Wlgx`\ `i%7<-(V)L],Y(XB9,`e+"aq/B*svN;X 6ff}8vL4Džd`^hrjTu'jB>l Z-\8y -ӏYwb6lI?J@x\끺Xosggi0"77:<0m?> XZ3" :ϖ9m:G"\JLX}r᛾? .6+[dvJ\ȵPE?9ɻ^oL>oZDWIHЌ76OAyo|Jveff"UV ~Q%BړatpVrokc|ܧ7M}} a` `Dnuq\<ŽM""""֡QB%u><^4?9 "Z7?fDX.Ĺx_GV $/AAVD'KR#_V}ϱ}dr>WI {` J&<vS@v\}P"K,B=1u}Jn$Ǟ`x6J5@DFYs2OęDDDD2-6/rEo|5jGgwë:7F#^鶍`mvOM2eTܛ'кtrf6 u\e.'oT+Yܽ)pCkg8)^bY,Y%* V>%G!_%.D++ԇܾ?~׋ŝu6Ae `sTwq-Vթ8bΏ&ݷ5aL'""s8݊!B46mܼ ˛}R9,""""@عk?Gv핳Sd Tw.;ɩu;`8ՓFj,q%sܖfc""""""""i)q!""""""""""""""i)q!""""""""""""""i)q!"""""""9 ""rv>Ÿ8sHᑍR%Kb@ k>Bonɴ9x0K47}5┴N\xD ɴLK ɴLK ɴLK ɴy.E$an1ljRk.ijuD :N;@2Qpw-].怈܀75b6+xʼ9zY(ݲ CN [Bٞ tD'-,x&(f (G-cljfK[X-@AJ& \]D f0BŚ))__5ia$ncTP5IYլBbD6 VpC[o2@lEk8eeyy4e;d^ Hdz<5ie/֨EDDDD(%.DDW4y_b^`?N<jb`L-`,2V_`Z0~Pʈ(~s7(""""rS󱱴liѪccM"qs /I.70.u;Y5}zu b3LP8ΰ|j2 0cIh鼸[ z"Xr]Ww1g Sa*Mp|yvH<ǟyM\B0pQ}DDDDD0%.1rOL g(Jҥ8} #Gv^E$e=ON]| oF2dC\!oN) t9N-{O G|~Վ3TmTb{lAo2FLL ^^^X,WȽ|t&oDz󈚤*""""r_(q!w]||<+V%_gΤs&,,,CYd m۴AHY=QD&c/0aB V\Ÿ߿*I7oˏWNbbs;v{>~HǎO_DDDDDD.J\]q62o{c6ժѬiSjUi+bbbزu˖/g$''N=S6 `֜9dΔRZUVDDDDDDaąq+xp %aTVڽ rˋMhڄ>:_-!997lxU+3EDDDDDąQ{HHHdɒ3Ezf'wTP3lP<ݙ7СC5ɓ搈<$;رctGzҢyf :wwwSϫ- ">J-t'dBѢEX8 e֪Y3C]D2OOɝ;$"""ia}ą.\X:oMn;>oC pwwgwɖ-+ .jLkHfQD <ġ#GM""""'%K0>QBǧ? Ahq{Μ9Cޯ FXV ĹsXw8f!DβZ.]iVs@VٳE_. _޼;jV}i}:c&zH=r$y EDDDDD!qg.?i1 ClL=e+VѴxxx0w0 ILv*"""""" %._9t0v zuWfqgM<~ȸ;wrQ""""""PB_|^~.N-wa7~|z.W9w޼<e⺊ IDAT-ϗMwǞ={aj?_>6oMDDDDDDJ\m;~oZ*Yz @ $s7y)q!m}*UZ7|2{>=]DDDDDDabܬ3agEqju{v`ܹLpJJn$22rM1}9sDdwOI4<1;Yl^qjuٳg畗_ɓ,s5E=Kܹ3;ܕc= rNz}'OѣԪYMZy(q!J:u˳qj7f͞^SS< ^ݺ˛/,ĉwω'bBKuM=D vy/0 jU_lwȖxj!MwԭLjٽ[SVmt"""""%._qssz=cǏnO"ZL=aM<;>RH' ]#ҋty,(* D@T HW.4iBH!>]8.H z-݄6[& FҺI3LيwPMҖb iobC9cb{OK;]ܿnF&Mi7ٹ&~aijZ\ݑG&ylS<=%-ZAfvj&o͛ҰUwnyn\ [V4i֒cm4ix;^3A=ju/ 4aS\""""V_ѷOjլ {{K%jղX< #,˪G4w)ֲy-8>W!vY;r>1cE[Dz݉:7:C_A ]+I=B*qdq_VّȎG7qz}Č?9fe|~W0 ӳ|gP0OđX~۲mmƔXE0 ^zq\^*V*UtV^ݳߟǍ0t)_L;:w'd|֤Jv]V3Ħ܇:ҡ`x=78ø;ۭ3 7r%19ucckv#6.7;u}no Kgyqad7'MW-fcֹ+ۆ{n˟DV+W*H>r5_953[DnQY!٫}κKv€+1`_כ`տA,az %Q>[3ښZ=oǙ'uV\ogHX,DoAi+!]4~b:?_+M"}DWSAk"-tS,@Z*i=/<}?cjgc3sNM㯏s^[6?AiٔZ]˘Wp\n09ŸxMb?d/}gxMgse99|86e*7z˖##iӺwBYz5&Ǝ;Д#3;Jʥ cO< WXR&;4k!lYH tx eJc& фPw2c!CNeP7%Ri8Kߕ#] 2{.~360]JsdehvzLH&>FT(DGppGyw`DQL;S#S[}0L{)gTfA)IZZhq`}Dp+AA=k<*ykBDS>s$/ |>F2HYcZ,?OM?xNF !̟>sNawE+jȣŽ;s0Z4o΀ұcGBO5 sp$˗/9smݺ ^8{K\5&-XM?ir"NЀX{cd$%%1֭#8'Lp>Ax,aᄞV7ȗoL<-!D.EhDej^ngY!DF{4hWb11'(a؉ ;c68ƑX?D|8{֪WP9f3Rn} Z5}R>Y}eeb3;ΣIp]^}V AN7kl~COYrh/nf&I:~}xw;6JQ#%""""&;7sԱC{|5ݺvNm:$Znxw9|z;[o۴Oֵ+sZAR4۷/6:+BD۾\}[[rt2c~vTqճrg^ŒѸC3 eYL[$H'vNznEN$}< 03O.PRPs(QzWoPprd;by&(E>]-oN͟2t^ɪg{I;ӫY񶾍 ]g33? _"ܭ_ӧ:&{A|-4@ `&nڽXq%NUIMM%5-;v[Cd:{ V~w;Ҡ^40oη|7[5?@'?dst 9S )6UTfڔغu+_̺֯^/Hfx4h;K|g/XԺ/ryfՍ'%R" 4%^k. x3 "i4`O+UW^PfSWGSqEpE{y*yD*+^n9ݚ'Hks 'm''RgL,j8Sˏ]mF_I&2sDy 1iVJC=AQ8Y?3-b Na9D"\ߖ)~Tlq#cꇛ9;:w*ÿ#WN?lI4 ҈NうX g&-/rph}ygbf-TSBDDDCnJs{\^ܷF.-8>|=}\kw{=Dɗ)6ѡ][d)#Gt2~^6hִ ;uSǎ/_޻±cLjv i tU4i;lܴ͛y'%),ߟ )""r88 uSxǁ8Rv k;nwcnSy6X<׽ v|,"""R-qC֮MZvg/"% 0`Zݙqi3z)EDDDbI7=Up<>=؃>s bRjϽ[v#L_Ò=`9]yg#v!O?< m|H4 {9G@*:7b_7_ V%3<1/[ڟޠy-d8LO3YsGQL$De&0V4lci-|[~MIDDDD2=IU^ŀw`'~k( 0Bhp}_Zʊ]M7\7TtMCtG|q֔+ҩ}-WIl uJd%1L:q3C mi׶y h4*mR:؜eK {0o5 -ׁW:pr)߲~:6_kq[#_"Hv\|4Dž%ּяPDG bS9n8Ȱ^F QZW;paDR&|'b.:|5eZH >9+ݑ }9~U*ԇTWdˆ"2fj~c"d8OCds}=k^gڢ?I VQ4 c;_OrG Tqp&ʠ'ԯS>ہMiㄕ]L[|l_χ_O?``~W1`h,a;ϯsM' wp6#oXc~0e}y_2~U{o_+gLM֞9w6&6;I_70%'Ĩz'e$zj>LϽ1aU}5!!,PA )vq(Mn^&@k|G<6̈gN 9kQjL&7vα9jtnk/ؑl-3b{~B7?`]L&&l Rll}s\4+<BxD)ט~bִGҝōH굺 FӪUMH*w+ĭYC90ޗ;GGEmPJrkg5Xhqݢ6tC2FTL\ϼs0 R-**l!""""O=.$Oʧڎeoo=< O`ʑ V#caSyeCtG:{-_M ڌqW7W-ix<+V]xFi9{>4Zѣ3pڟ/NAXDxv$a' V &`?Oߛ ʵ, pas;XfDFEbIU*f">62" ꦤbz3ފӏ.FۋA ^HRBç ʴE󽳘hINJ5qddoD5j]-=^KDDDD2BuMuP̸jNc;סԠ5]Ի3ا1v txڇ2s׀֬}z5x4LE qdP:}5&Θ=߯Q 2恆ODDDDD].s[鞯=׽=k H>|=}\kw{=Dɗ)6ѡ][dرcDGG{'g[B$z靔mU4i;lܴ͛y'%u7SDDD.JW*}o=akY^랯uki<+IVشӜ""""""""I )K )K )K )6A=,"""R=z d@|`N)qN9Ԯ;رkwHL:QBDDaԫW;YDDDD4TDDDDDDDDJ,.DDDDDDDRBDDDDDDDJ,.DDDDDDDRBDDDDDDDJ,.DDDDDDDRBDDDDDDDJ,b_,I4 Efs.SRDDDDJ@֩a@ 9DΘE6 I8M)";wQREEG{gXGư}Nխ%rބT !+Z8˅Tb"rHNIQBDDD.:ʕeǮ]ɘö! IDATr(p!EYOKseas kc^/O9dRDDDDDD+bW9JSAtɡ$;qv^Y(hbRU¬X-&5tDDDDDDF )VQV*bRKX9L8 jT+C gbi64HbcXVTOI6;hažӆT+m{6O)p!ŦBhH0{K?i'11,T%+"""""_V \<&dymYsP%WrO~1^ץOR,<(SD Y渐 IZݰ] 3a-wl^r͛Q,z^mqAv/""""r 96o}*ón)Y &`n5Ծ[͊_cd4mqVLNnŘ}﬍%C~Co:wH۞],6^xy} f4?ݻt5y$|fvs+]wC17潿@&oI\3Sp7tu6{tLd1x@/ԁ}1qY)>EФ)~DYg"Q9źӀ46LѶ6W dkLz~83vl,K3kx4Wq՛<~y;'a;``>V,K2w؜ `^5^?̢Huw S,e3w\{3IZkfe,r8N`%˚\˓姥?2R,x3UHRBI4#}R :<95iė붓Ҧu%nKm+XhoAXS?CJDiv@`Piܳh| 3ZƷ :-߯jZ]jqT<1qɒet|nr }]¨ԍ[{U%߲pჱipYë?*jFLjկ> "E!%$fRBigʉ 0qHãUE΍ Z6$=!-aiM*ra27CM 8;62l>MIud$vD'q"b ,T~2D'q2f;| 6r(ՂՒM'8NS-e˻^lՂp,Y58{N)F \H9dzɌ,lg8Sajةp(V`;yKi85Ѧeki1<(|@x l`š&R1LSfj,1IT 3çַdB` L$0ƒJ,<&괳'xnM;O}8[o]PDDDDXhc)ǘX]k-\Y-P/Y(p!%)-aDTiӊ߳6)-Avhw!8҉ݽCB vp$/--jFe=x6|iGVl Tn` ĭ_̯'֣S[+?ߩ&86;6d=#NĿR(mG"=BDDDDbcm\~cW|} ZKkRN+D<͛E:mpjv\1 /QϿƔ7! JU&Ԥג!|87[pyGOU~ 0ѾfˑT_èh3ȳ7"$гZbŃ/1mit4 Zzg—7=H1 ]ͻH(߹+͝s{qp~Eyk ~ǺǺ{1_uڝ^'7mEfbk?Fc2Y5 +FMYskuЮwH|Bݧn}#{ /8pW[6dy{v;G ZD;ێeS[bɶcHgp;#`""""""".Z=E\8h*Yt%v, 3|c8߃go4(p!gjn/~GdL"9zY%9ӹ/wjn_s{,\V=W/Lɟ!fW\VT},Tд-"""""".DY)|&g#<-l&p?XA٠ӟj"""""""/.Y-T ;8pFjãǜU¬W 66;YDDDDċ%0(;Yj͞31dW$;[1,T TNع{7{)тUw1.m'!#ړE~ ?Nk ) àNZ""""""lA|H2OsY1,h KRh\ЩK7= 4L""""""7.Ђ,ُ?M2I(9-3LR]@},)t!"""""r1SB -S~BμxP )p!wr)-<ߛz\\B $e{|""""""rPv;'4M.m21, Z\B;|#WDDDDDDp4TDDDDDDDDJ,.DDDDDDDRBDDDDDDDJ,.DDDDDDDRBDDDDDDDJ,.DDDDDDDRBDDDDDDDJ,.DDDDDDD/.LEDDDDDD$Oc/Ϟ\dyu/v$OH!\rmb%Y/lڵ,)VJhhwil6'Yr F+ =ɺDDDD bKVf[#bYLN\\?s;0oc?qqqޛ0&?B{h!KN&R^MÒ(W;;W◱nNض0fOWs3ц:Ć; }yi<;`\QZ:#{@g$sz8y/u[oobdLl_rߍx>~3/~ g֓kpF);p߀^8{fټL{أ?c'rϷ13Ia}d3~gSϲهQ?Hrݿ]%33#G2cy9G?:Ӣic]ݙky6p1O0V<@vy_ߍ>NwE-LdO֭w=i݆Dm6ԯ_y722:?g3"RScN-t?D3=8-? ]^Dvm=pYɟ s5;$~G:B&>̝L1f1xsV<wh+,/}/ƲsvpcZƫ8_Kr,!ϤW9dVԘł^:Nz.7$ֽY5IY5?jY˙pn׫Obz=ۙ ;15*ǒ-v MΙ_dx_ȥVٶ vnI̫.t+g VZ}3Ik~Ӫ~+2~(Al4߭\j`v=f9qp94 M 5!&U~>Ԓ>Sڷ0ٺz+[DH#+ p8-1F~tkFUO4coٝ38f""""r&LL󾤧gCՉZ}r\1;ǎcpjDStZ<㯷s8hww~,h{mH09-B\͟CYf4nOÆ N+c y矖ɉZ9-'>M$}?Obث \]?0}>䮒$İ/aK?ݺu-8W,~ۛGη[NtaLO26'9TSُs"$&f#3'^s~'/u+W4@0DԊau`syr$ %H^ ey:c&""""gP3 XV z[7#je}վ џgsT u2̊{$ܒ%={[M6^4nM6.WNmݗ+ǿ,F{͂i,7U8uK~{r*3FV7g^{o.k̈́!gQyiה>ˑkx>Yl~o*ÞǪ_vb瓩￟O[hٳ}xC434;͙='3pQX&, O~ R:~)Iw&6(`2 G~$sEDDD$[g7|={Pjt|x8aaa<%WТ O&D6IH6!ξ^`#Ks[1txTWbr,b<:jδsК_jZ+vaP*@t[ןb1q.?ɉ߳\?fvKPoLwRR 1o]B,m3A\f۷1ᄈ֧2" \ycϸw~~+_Qv~wr>1y|z dݦUw|g p<͆#=}'`[uZy5ws~dTZVÊhR?gʧ:ӏ= 90z#?&4j/I0܅lOVl`{cTnC HɲyI- <'r|n38f0qv}o΋zΡػo&}>Dxx8ƿa& (,d< yҳLnyK4 l_~ Ͻ{T325ىt=qy8hlOjO?եەΞdx+1)v!ss[5>uNNy'fQm[ϕoF^rS$g*w%Dsԧϓ#I$OM7Y ਹquz4_{ s]ڽӶŷ)]nm{Ӯut#"""".fݥ0,:S0ykDGEرX 7ASꜘͲ?U9l_ 0juDTLxm {*\Do>3GM⸱<5iƍ}?~}zl%y-2xڛ Ts㘷v9{Qly;0 0]׎pDbnB]5SS&GΉ),/EgF9{[;QQqȯ=a ]ҽY+Ea/B^{3m0 8Mg= IDATu\zy@_eݩU}2/C\붍X~3gD43蕽)W<|r =S^֏!Sen^ߠ.Syg_F#-GΠGz\!cve^YBDDDDV| aX޵+ƾjp40~~4@@~_㾆_ɩo՝?C=Ȅa\hZS iwុ7F|W6o 籶bw>lP*п[[=_5.f&u(5w(9g6=i'U r9!jP!XO}zt g[h=0b}חg0 ׂںy.[3)[l3paR`D^3/uϓN+x%eC}1wt , """"/krJ4l0n`xiWddSAn674t"m/2yn\CfܓrE#+ssqpˠ]6`|G4JY X<z>N9s]{P,>܍ޮtP pZ~CE&v#FGR9{-8>*r*DIe4&jbbh-bC;&{ҠacP #5"BOEaQ޽l5jo}~Ŝsg"a9LClx?jnw3O+~n}#"~:~/$>2{G'/๧G?[TGΕ{MXjԺ٪Ak4sm\k׭㎌>I,wg^㗿ox<| |/3|oq>K˿+qLb {^g}ïx6b?xFL= /}K1} s[VO_|dף[~{?⅏?/~qI=~+"+Vv,c{.lDz8`}d+٘xcΫF؆cq7Oqu:ҹ?ekaqq]omk_bx>)V#=nƪ#*Sf9Fb]MC/m,ݰk;""oDĪi1;"O?Kin,t:v6j\tݠ ez:z"5}{}O\`W<бsC95ո7-r_@Ɯkp]n*߻>kۺ9t㢋񘯓?Tmdyu593]M¯n^7u#ꘛR3١cnHxSnddYu/M{kG8:v4n\bct_%:xw֑r>eXY]ZpANB;t݅픮!^|z^ib圍.߮_9z$GE"]]]W)FWWW+0O< x ._$wލy|x0єSO=xyg4{2=mSU^}9צGu.]u1fsιbᘍZZsG+|Ko[֏VNZ}^옍 7WFusD=m_Z*b:u)Bj4W{VUq]{b㍋ax:C1͊w!{bbS-fƅ?!UMӣy*\eXsϕs5W1c'4.e[h=еvҼ؈q~^ 9͟թE+ʷf/"cX]+G?_?|?{Y"ӽte,hƁ3՛ :7C"},Gy9vs5m>D?3c/Ek{h59XsYxybj,7.\·s/cܣX5r~Q!GķbQ&G1͇bynnjt؊-QblNh!k蹼^͉~̘||Z8e㢋͍t5^͇y >G?>Er u'?OH~uyV ngc:Q#6˸_kA󦅟;԰#dl.Uj:ٸDCX}I˵=of[֝X*XecEl60y>X5K|5ꡱ{3}! zdܛޜ:>u}bovFZU26j/!@6-4Q뼯Ţ:bٕ73rbNcUn"߫9Xr1T*(p)>}Z \b iwzoT|}H;]{jbL7dXHy]fik}^ymmTTuX\y㮊W1t?X1^9͏@y64xƪF$M{]y=<ޔršt6"6s~̹=Ges#LX_GM /so@ъiqU js\]|cU5צBhjS~sm-UCcnSL׭e6|Ow~ˢDz>=txs}n\t1G/X愿YXb.wGG<'X%x57gs?*E0٠<&sڨikydR+>.T.ʹ}2W=|ؚ_ĺݐyE l2t\Ak#u}>GƢu<|pTC\Ni\uh3Bcr>lZd>}s||Z:UuΘιǢ_[~ټx^/ X_y}ÜKO_ZyJbp>0%ߴsk?l6D&ɘZGҵ>UŎ.oV_Fl,h]sy!s!v[yhGͻ\.9T{1CTtcZ 2׺=M絽5c̩=S6.(Z +~ͅg6%yMm`\\x)y赫Z5sZ떩upnS7^kEl}̹X#!^olh.:F?V gmjX>C7.XCYH,u6}\!9xH*Bu#XUL[k-|ZŻFG=fBƢ{6#<1^?!j1WūؐݸEr~]l6 <_76 7)Y#׿srN6925ιSͩ`>V vE'5!s=6&sCyVybQqH{>p\}hX7 t םĴɐhcC_ ѯ񡱥ojm[֘:9r74r#яc`kqڍPY5Z=yXkuhm="\{\vcyn6Ҟuҍ|ϻ~lBT?6,k?iNc:9E~FX/X_ը,D7߾~\ꍋNj֚e|hLxvp[UX;s5.Xou^ɼ>4=W _ĺ9dzbHx\sJbzhnJ,,c|˾yn|scҸxNXUW- ZcK^x1ݸbsX>L=?e^ؔ\UlhT07୵#sCch}>*ޚ\x~Թ߸X h!qGs2j>6!c5 rp rW1]k]Uqy>k1y?Cop7hoګMul77Z9䱱M5:bPXϙӸuUP~(7ˡ7CʥjC_|cUqW5X}S:_[7MWw̵<5q{\j2T3ЛܱطƜ{|(9{׵>WU\.9:UzCcx'VUM}똆Iv';uTs}b 'y~CjC].š6~jcS'1s]So[U3%q]tukVGcj"Fl߷h#snhʵT1]*c=˽0ŔkR3 u>&FGVk}=>uB5OUǤCT|וCLv kNخ6^ӵ竚QU\*>!ppīyu|L|1eJݔɎqz]&D y.C稪z]hʹ{]p=^k}us;Sj"Z U,yG5v꜈:^"`mh3U*Q7:UbynR7fcn|^{׺VPc:gn9>֕Cmwi5.W15TWGԵ>-ߩמZ]Ks` QW嫘:jm=>NU㠊V:_y:2vj, ϹڪDj#5jմVOc! hع|+Z͂\jZsժXej]ļYs9CkϩV]k<>w=fn}nM&z9^?wZM Ս̩S;˩6S3.yܵjT TS+8f㾎cijssscO٩6soܵubj,߲ypS캙;W15sssc]?)7suz+^3w=fj:4S7S]WflQdž~' Ͻ:9uDhwuMwvzUcT5uD3;[>Okʗz \TuSc̭˹6s;>Λb-CC95pS7CuC9WV1sϛ[sqv٠rNj{]ǜ:P)v9wsvEn]QCrxppz>tVMs3zP.b<fM5v= .es\5v|Ĵ4p~s6SjjSs}=KSkMϵ9.u!s;PI{Ss}=K=}ϹgSϹS{}?y>gӡsTm|{c5u݃cc_ʱ Ǿ݄ ~Sp;pMی9}\MsnKL.1piom#}~^t#6<e5M q<#16Иy@3p?9ŲQIENDB`kraft-1.1/manual/images/nl/context1.png000066400000000000000000000307541450127457600201140ustar00rootroot00000000000000PNG  IHDR w pHYs+ IDATx^wtfw@HBI5B B(VTDUxAET{ *{:!{Ov3 v>x>350yd[olB DԒŋ lM h8BqS'̙$d2)AW<==0Ć(7+% ]a5+v l67jJ0o !7|Hq͙fnFAAAÇZŦᄫC*&ԀY`CHD/3_4Ŷ97p J\INZ^QJ[?p^={p6aקoW*X]IiQ%jݕJIm&umOͿ3$0sR\+M.kFlpu{\؁NWb48v{ \52$>Enl JNhOeNaIOQjOWBg0ceWDU=Hdǯn ٵ$ŕ4Tꌋ\AFa8 Wv8@uf{EɉR !=>áLJ2Z`8۳Mo>kvїI$G5oGe rrg[WBh`8u56Dn e^NolE@S҃!+| BڣD])N͠Ruw낏tBΜө#TNDIIs ~CD@鋻mg|T?pGua%jqmם+["*M2\UIZ|"Zr+Pgce&{ >9Ȱ Zl=O~P\@m/fh#瑑WJ$*H!@=\ I:CIKL;-h}]BbFf,IO-5Z bjX}!&#yU!USTGp2+/fitAkud7s)WaUh]iӹ]۪5}b>xM+vcDOG[>'Çr5Ϡ |Ft|4vDھ<»P4u(f7G/'.]pҏ^9qFQg".Rr 6v T4d69|%@XaٷO ul6RNn]\aBZZJVC j(aWX % ]a5+vP®JVC j(aWXGY1Hf3,#TT*DQwׯV`0|INQVZ ;t}t P( $I:x4 @Aa!G6 EBq.O|cvYIJJ"/?:ѯ_?Bt!K"## $==^vrI6vbJ+7ɲLnn.:ll.V "##}|.0~͑AAcwPu@uS֯`Uk$ @~~>*\Lê T*>|8*QDZnA2R8Ko n%k~+rIЂqBOYJN]ũ޳=mȬ4"c 5u.%fRRUYܓޡh1SzDz(lNBv7j~lD  Lb ]PMޱ}HC6O:AAq_.5S,˸3r$9CPp0>>g(boo£y3d3UdT hлNDn>ih:fp!#ld(lΥ֯s+cL?En@pDgo>2|篡: †mODq]J#y.$CII F"dI:;({+/Qxd-d Y_: Xz4pai:IIW7ItĻxR`ot/Ua-:DYB֯VW })Rץ.pdO9~8GK.h42R9... lN1; jpE..΄eg6<A Wyh)% $G0NШ+^֯}sp  &RpF%&`$o>Τ쌫+$Y޽; r%I[֑ǀ֞r.k2޽;...$'o//;t˫"7-Y_L^A2$Ki֪TBZ~g4 "IRؽu7S)Uf@B@uſW8AV +VnTCZeec5S®JVC j(aWX % ]a5lR @K6FQ)ߖ*JVC j(aWX % ]a5+vP®JV& {5[L_1VzuQ7\ݻ e},R-A>Ir!e}e:D ~{1mtM^֑0G_^z+|_g׃/;"œ"bZs>}UGxq~|=kwRȡC̲df2O& ٟUc-L}~ I_o)Sc- E:1JU< {0|:Б<6iY JM9s_U*gd9Nw>grl}ù큎'O#4rh=LzFԜL{O=Οc= W/H5[ǒ3p_FזunNnC2Ex~^{r ^Y9?c9SBF3> ^392 ȇx t ޲ ۶wb#f}*{_zM|YCT(8(< t -錾[ϲ&،K8^xk2ލ6hճzDD8~VᥜdeM_$-LGYR,cW/>> lfkELڸgÊukVo??$_xulYYQi|2vV`>ł_ckf?ܻkȗIy6 =Y/"fSRUl-9DjC9Qcp*X;SEsVmX͢X ʩpG _{1oCxFeE\ d߳lzV~KfIeN1k;DǼ5iqO.cWRys?ٴq=~xDCC5 _Oc摞:611fWRR~Iײe]oP}vCak]Lbg\qq4PRZ }n."h1_{T 6xD)̺]pGG{DDk6iYzmOwŵ,m@J^X$jt{N|^ʖB)e3ùT`ړIZ :1^Vl.D V͸vnYy|ZA[zeC|y]K~?omMu~$ mVm#<ٿieM 94# YHN~M:ᇽsOt ײضgۖ@[t+4;A~{7sPn4_ HEz:M>ѕעaLsAU?S% )ʴ8;վmETQ!q@D\b*DAZA*"ԕ`z艏c)SwvD/o<" dE׸,4>";&Vm$wXNތ:=µ)yñ f7lRQ- h'\8{|@SB Ng9[[JPEvPY$  r(ǀ(ByFî??YCv;OMya^l}9F$T־g* $ I+Ea_./@Ixؼ ֎-*7ܓ6 kE7<5Aǚgrn'GȩMM 7Qrũ2BPyRE9rS_m =| XdOmsaԿP#抶x~?Fj97=Ra2oA"7;R]Ou<${M^oGc+TQ̯[n]9l4^yՁpsַ0=qkq9h0fzpf`p=/Ugyrw8Hfm_{|eӕ1,6T} pE #,f'FRY!U@4!>aJ%*No۩7$aL3;1:Xx CE|e ;yfVTÜ2UeD C.USq!ti瀈=;?Y_Lam{\p,Hxd:Gs';x6UcƘ8{}=ȘJHH*hТ#'15Ͼ}dP* ň|:.ICy̘CN N. ił^G9 FØ0sz"VeOȉzv gU\wa*(UQ®JVC j(aWX % ]a5+vP®JVC jdaLƪ7)ZvM_iѯ9uڋpr#{2uڋ '7Ain(&ô7{2LpOÇk{E|"Lx|kg4Cenya" f`t;D~yq3C5m:]3\J/21͐qO0{!8 J=//ǭk]EŖ71ۀmo.; 䫩9lL兇kzSf,S&2SV!-;fW8f8rhn͟ogT03_fV fayvBRj|55EaڠÕnGt'7mEPyѿ'5is!nj4C\$Z'btlY @.u,;ij%u!jOM5a-C }g&<8af6]/^ը@;5u՜V]|m?LkW,SN~zbE3|"ˀ!u;R(ETakBMXܟZŎA޺~qk$sk斌U5ao Wdz!wO G)iն*2L!vYJ6W`[WsZv87`)PjMЁ+7^di,n ^?eJ3'7w 泹oEt<@"sk@ hGY4iTEW!aʼn [zAM ~[/ :yC"s;<7o/ܲoӔިv۾lL:?7톓P7s >=+0bKOqǿte9Ut7GSo ?Gr2:~gO;4 + h/1`_Ϝ5̇Q/{ (}q2>e^mKu 9}yweJ= W/'g_o H+@- ?6zN.{n L-$_ymHi xdr:ֳ짿I)66ޚL{AEĽI\K_oiRW~ZUK7@5;_-`m{#g}+BѤax1)E3.S\}:B`jN*"j|ּ3Q$<%ӚB籱1vm( Dt,?ApRv# *"$s/˛./jiڮ#{nrvs+XD6:G]*D$Ia1]Xf滞's˻>ELk sox[f؃]q?1?̤Da^!p삺LTT,u]_aϾݪi5R0mu<%} u8I'7Gm큵Ws*? w.-8.nh{hRFS7Eti5"De ҫAoje[p`XaRJȈ8wQg3ǓdHҏo<б8Yc&/ӕ(IOW6@팋6Ieu]K{ǣ?^YB$6,nyokڴF~5&gK;AEYsi3w7I/jJ ~HsLNFӃ@pdȃfT↍_[=?\i׳YӛOt SeMeӾl~sCo.IlZQ_4Zzy`_vZ۵{OJ7k0Q( % ]a5+vP®JVC j(aWX % ]a5+vh_=2s :uD޽-~)ױV),,d?BΦdJm`MId/gmBq{I:'N ::NN#::(22lX'K~_]);l ɪA^|4 J^YQNYQYQQo Š0OT.7GA*8 Y-:Ba 'ND2i;!*9*m#AñGHɯBRݱ=:A";~Ia8 փ=@BZ&\uo6i/cOSV$.?X"d62Zvt_M!Ƕ%€y5'U.DEhg$>$GSN'r  [Sw.ߏ>?m?);}3)1 h xm Def{RT-uiK{s$J"܌s'{OBlh0Qrqhu/?;p"J ;ޖӍ\Nx2{3l7}ws~8*@"7962Q0ao3l q.xm}q LJ%~g =GBTeTK#$cx" W5d0-oxuAv' #`۞*]랕#$w#rdolTs㨞cr)J=I8 A(OfO|VTz=[=kMƾ"SAއnxڟ=1`9|5 'uI-vC7"`ז@#,D򵼣Z ;Z~NU>{tJ3 GktR!+OePѕ|S8ǙTea"/=u l_'ڝW_Bᬲ,?@g-(idWvgd,ѡ1rk Yصgx vy&%`"Å|5d9CksnTiF;% R˵`yѰZƠ7NmZƠG/c ;ZlggDd~YA֣[/hFd}F&*w"vIH;6TWWή `E1TJiɺeIhDQ㒷1uUaIh2/mm?\kVJ2ԌB0VVaҺ\H jZQ3FMU[VkS(:5ʌ\`Bz 2jc6ilA l[\7C.VAp#)G0ɀK ַޕ)$fT`l q hKkhU~hg/ i'I0So[ml$,3(+*);[o\JR8GL$~*&`WiGΔbٌF;lǍ1ʓgdGB>bvQ'fdz˛}%e%{7{?l gm_3/}84уnٷe+!Q׃e9q r)il= ;ʡ$T@ũM8ZjCpwDcQDGH5O(oȑ>nj K;G`] 뭆\IҖu1 f̍U`JOF>gڹ%V\a;qJIݟȮ2+ jEjP~p:r|P\iJVC j(aWX % ]a5+vP®JVC jocn{$|$rQGv??m3nc ;N/q/5Lf3fl6"ٽ3svύao*MMk& 4TώV*ϙ~9i 9io#7ǞWpU>5Bkn䐲ؾ|ysOqYhХ9 Ol\߮ZG*vbwbwkX4j9ܿ  ߤ2~4'/gz^Շ֢#{J!LSψ8ZÚLَUl gt/-Pɥx >a]f)mo6oLboj͙M '"}ԌGrȷئf#?eIQXUeOj3ǐy[X/䫩9lL兇)f,S&2SV]t㝝FI2uSdze|)k #^Zwe܈hL`9|CT0nyKv_&Ԣ_nG4#X& 3\֕;pGwLOysdżR}Ü"pelFv"%~?E2Ϧ}f1 wE=ѣqY|:K6n`׏b{ ǥT*|Ok6?Ĝme5~#>^y/Pu .>]e_=Lp˔3XnՃc? [Byudq%̮I\2?kVhp+} =C5a`(:α$mfkfhd' pBgkK}?ϡ*0n<gY FZ4f1h<'Ws (DJ˯"sbՎ!$ b+dllؾ/bϱJeG Os vkOnuiL*)oKf.ȥχwdn2FRxukQ刳 H|2n:(]_Df%UG\l % ntD _{"g{ Dغ)#}yM5Ktv2ԖJ)-Cxϙhtm8٨ 9w_5̊u\QZ#nE'1zxM{/:" / Wr4fYZzFEPbH =w$U`Q^,He/J Ϸ^%Yilq> I7,#\+auQ)M[AS/ߜШ(=ěKH:'c0N*;"w'/^\Jcn2G>d=wQ-Of`0n<-YFU<1/aĤ/8,_+kq#\ x}CL\3Q :7V5H2TQ`DM&goq/sy}z_pXgսd#NWԮBq5)aWX QTy|͕BqSC$aԨQ_:IΤP DQL[#cM9ޞIENDB`kraft-1.1/manual/images/nl/context2.png000066400000000000000000000114021450127457600201020ustar00rootroot00000000000000PNG  IHDRN pHYs+IDATx^wxTU?NdCh!&ERV:a!$EEUREY ,RXetB !mi~$Lb]y6V:-<mSgX|u#F>PGRpHW #[ XdSL{;'@!@e+ b)\2NLcq^/sx ˓9YnΊ j?V7iPhvs!TҔDzoi9TA"%שn3ĿOU&֗ ՈR(Ԉ `^2},SY( yd,%E2H(422VE-%H@ -+>TU1I(e v7Bqt5 [j9qs/`rH JkŅZC~IaU7[(~332ٞHYL"Wz!|V׷{;&OƖZߍYN4rpoEo$0tUw ,`fpT߼ŨĞtٟ* T)lç pLlE1GϘp .űpq2varn~%(){3nF")Y5rGY1wu^Z˞7T)nΎ @AEzDK:=k#2M7c+V'='7l4_#ѭgb%}=:~}z-a-9L,qmL}p47$Exϭr=1jRXlnO5MVԉ";x$ ,ŃR5l8Mi0v7ZQ4z'&"v8oL!eh*\h"ӆ_ncצyKOP$=4/oNʤEɦXΈٵ{ XjxDd|- b^ډD͛X3Oh捥5ϭĦSQTڕ`!fqy$N:ʬJHu{.׻1kbȃ r Voec 0xp;rwlqc_ôKnOtx1E*AӴw WQoG!(7Lh#YEYjn((- RldOU<2ز͓]E'&z^-;lfCȒ?!abNzԴ:ͻK~x 5fuus͏#ydS:ҜK :c\˘}8gYBضcܱ|asx9a凋V2^4*05 43tE pݡÕJRЪQ(M X =4j*U:w)@ jHdPߍZ{99999999999-q`ϰᵹQjա Vண%{ l /߸ P5x}wj,XN"'HN -!9%rE;(syC}QӷjyW읙>_8do:2uXU_v ?*fo O*+ p^F\9jt B, nUL7yrרͻؿ+>Ӛ+KRn kzRt/Q#hj%rx͟䖰hk$ {/m'j mGl>F]G֫ o"9q~O=tX"=6K͠O,8@9 #C^JOb(/i#չ+mLbR2Ծ32j=zG(^4#c:WG gx%s+1IcXV)y R/zh*pU\HY8z5Bo׃>UNzY{zfwK8LL/vHI_mܺmdګ/z9ϾA#?{YEs9+ٞʜ>ď\)lټ%O4!S!emIP?ԝ;zSm”5)7 <;RYB R_yMYe%8ksK*";*RaJDԩʆK2xkRE%F݆}z [@$G6R[0ϝVVotٻDяLrG<Q:R󫙾#?N3qo*G el:hPtGsj6.I2=9Pk0O%E#(8GؑVb"di/xc|&P9R`ϰa>.6 VJ0NE!`"$C{M[4ς%taPLf -%٭tޭȳxdL`~ђۉ^|Y"b΄ +f~j"m1D0}L <;LjrF]uSIs[a&R?1ߞ*7(enk/+q\H.(t(gȔ hC ٽ2O/3a\BȨ0,KC;/a?}{–z&I(yjl=(ZKr)CN-ɗcY><"p:Em#cͺ-->"Èmғhh?x5ѯNHoGAot§ g)~eJ.Jq#E)Z=׬n|.)3j, %;9|_O>㻨nh{ĺKjH9݊D@O a!.U64Ǘ0=:T@Dׁ>s-m!+[|v=E%jrHrΞ!x5aƔGxs2~~ͩhc]vkE":FT {˂Vp|*fIK<=ྛ?(֤{g/Mxf!چ LXZUˆXQ""E<̙{BGDW%#C l@.`'Iς1Y/dzL{{s%qI[Cg㊬)& `œ&-g!^_L[قO4#?FY M\ .p!2FQ) W٩amnw{hIy/)~(3HiP` MB]`bR$Uo;uT[JD[[GPM-rhdIFP >/pP J6y eKƯ[0]?' ?Gܜ\ 9_~'M~y$ } (ޜ1=Gh x IENDB`kraft-1.1/manual/images/nl/documentype.png000066400000000000000000003070211450127457600206750ustar00rootroot00000000000000PNG  IHDR.( pHYs+ IDATx^w|l wE@EbkCx++VP*by*jHo! y='g$d~gs nrDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDT) 5@ǛvUN+ǐa8Lj* ^pRc@DDDDDD.lnQt3jD>_[(>'"""""" \(B9UXmHW멮QhbBu7jÄ^CU퇈NUU\T:]'""""""ҩ"Ceo?joem"*PY 4as v)?X)X۩T5aK=""""" wU?`/X۩*.UL+*_)Bu\Uu t vH/X@h*݊[)BmR\SuUn< ܊|sGEUu*T&yYWk;r@r2'WqUd;Y7(Ba\Pd޶m 8.&6nEuO˳#ݘ]>V&uo۳Q˳NPT$<.:ݺ{:Q2I$W['XqgSa5It vx6&7*toyT\] _G}@S9jxy{{DDDDDD]'v՘1cNV@|5櫯|󈈈?N@:j>ySRU@S@2u,о.GSjN}TjN}:hߗXUMrݏyh_&yd158UIW>&cj1:h+ʞ,@r.Ϯ-S} 4(:DDDDDDIy&Ӂ vm<_}_$7 = d \>Ǯ-˱k؍_Td]"""""PTɲu]!-˱krty@`ɬ7(X[WnܡԸ`'"""""e7W751zv㢭[(׭k\Rd]<]1AmD\[p=D[^mn\U:!""""""&ɱ+y~\^z[ۺ*];/ 9gejRn)M:>q6u1@_ djTSۺ XeL|fyt5𞧎}Ru1Au}g"""""Qy&:v5t1.E[j['O v_*c6&jPvL]/S۲`mU`LQ-f,%O_ЫK5+.qH[G7-/]ܮmX@5@ ?!6PZP{ۮW@u;v1;ƽf&]rZTK9Om]L(cvm//5n7n>kk;&ɼܗj[cr\B}9PrLއn)'""""""I]_eҮAB}ʑjnL^ ][m =SeHy'v멓zH ?D ._-` uUc?'> $:2τ\QWԇ"&r3'K]yn;vqn2.ӵ/Zh!C=`E1ݸWUt5Yt\ո C(X@Ssuu1-cjLm؍VW\Z PԸZtPc,ty"Wqu".q:*8nk.~y ^ !AE]L\1!0/棢8]Lcsː{Qێ.&61Wו!pՂp=$I9b\PW7&'Sյ_}\'\"""""d.W-,\Kz>PZЭ+j c896DLUsոԸMotX@ &ZP e pV\pD5{I+Yy,+OxjɓGDy(:J\K:w 9.㭸 ʭaj.b<&Rq+- ⱄWF+uEun$a?29F_mUBP/4y\.B9C*C, U}͈^Bb s>Ϗ@ b~+vWc9ѯRQPJ7+˅1&rW" @ U}瀈,VB9\? "X 1An\*R_|yy)K -rL'X9<>CJ?zG\ុY0z(T/D\1 @[B:.q9O.b  pQ?1z#&d p Ftt"""t^+Qev퉎 )1p"#[򕫱asZ?ېnrBܠኋ11Vw"Ŷ15_kRTuB ..1-*N-E[03*,(@FvI`fipG`kP/v""""""ڧIF{خ:&)$1.plہKCl9PQ1}LDwB\m<֍1>^)]_?tY|9v}q2oQΘZ,CRTXv"V4<ۄ,gGġu;n+mQӱ]Loԡ2:kg)Lǖm;a</ĸPQe/b*e㺘7{…7r\{؍Q]6FYl0- p3JXc=u+sU\G^.\XiQ1x8s8|֠~{Õ~cЅ罹 A}wDvjҸ&v4JN+VYs"Z)22N'22Opa@&1lsNO<35Vϣd&wbǮ(,*BL[!2"mZBtT&L~Eʗ%(-*4&py(M A!.1jAm5&xmrC|Bۿ W vCLQ[lM ZuVWG^kF w5] "3 eCؘ:I l&aİxpSs$>z SSYxOR85T㍼Rڢ}3~G\X#uf<|HnoMx0\gX_n{[o`޵3Nsޙ5\`Yʿux⹗PTcoM[ЭK'߻3 XcnAPN8xx'2ЄMqMk_}pt W?Q-s5 A]Vx "#gu^~\u߉ǟ x^kcҫ-];{/)d:ogZ\V&EҘsMdJUՅ |DqAז15W}x gp}H`B#^+_,i;#ېq uEJ3;ҐSw+:\έcb}//a"" !ÁǏLg~՟oڍBԩWg}-Sa?ۊ(*.GI8o6w[= ؗˆaCĔmNt +Wũ\s ݇Xԫ[G;ؽkF GmpFqq1}pr8>d{_-ZŌ?ĻAB|<>R7nƊU.:}9~y{dxh|[xC˖;qՈaxxfx'0o7c%#.6ߙ)mЬI 7rs/#;'GM˖m17107Dbob˶c#mOJPCJϼ8 <mpnC@劫s`<&bq W_+[u.tāv(\1&ڎ2E- 0M Gɵr1 h5y;Dz!EhM ,rfc4C+#Ħlfen܂_~h,Z/ 6lIi%X)߷k^ddfa8z<g٢\V^wm،SrҨҶcq%1oqx:]\Կ/ޚ99 >ܗ+_};~8M[Y0 hۦ5l0Mc?lٺ.\R51Jד^Lvqxчg_b/WΥn܂_{s^|ЭsGL3Vv۱oEY`6=wǎh䏏64}ub<$paw |tq'br!Xyjy5:,Ddr>i@Qv1Ș+a@l,j`N; o4eMQq1_>+-j Xz>%^~ <-Zr! AGTT]Xg{藺-'2by}Wmn*7~~Ɖ Eיzʞuvu9-nlںY8pNdfbkoI#mNص5 (8Em0ǟf+ȹsi9Rg[L< sr0x|zux`~i+F>ӞÆ\o+,,8o0Z{ 'CaQ\|N[Ζjh 7`3/h (,*3S_1ԍWQXTkڔLB(Tn)lJj/1?v"}n)`*;c_.*8P".uyL(V@X˘,3 )Zlor˵OmZ¶;QPX={홭`YNfDbBu$,’ѣp=v1HJL_{Cl^~mz3`20exegqIsbjNH;3ϝcFp8bDD5тIݰ lWh_6oݦlO 8߼u@!߰s{|oWp]]}J  9y D_<y\RS5Olm9Oz,0lѠIXX- ufE ";os/挋IE;Mظ9 ׭̓Oa۝Wj:|tP(님pGEf(.*0Y~['O}O`¤x|\?xɈ'᯿{lWݯt`㖴x4a&?W_G^gcۯW`{zQnx2n،iЩQ0!t} 7m|'1WQ?[(rےrLŘW9B~ʳ[[RB.:}%rz\aRZ IDAT%dGtODDDDDTt]:u'~ iys&>>KhG,\KjҔ#TsDgUXDĺch9kiۊ=;ҧSfDDDDDDssOߢqK?gܱ:aӖxmƻWZH 8 9…Z-bXBٱWXe.TUS\}+,+t _ƛĶ4$s-""""""8I=];{K_? ~lou6Gn1 Pjs_ +.5 EBޱ.kۭW骲p#J[n1AtWi z3ҏa?=b(..B7E8DqK"""""" ea X~:T]Po}qAΓcv ]JTvB_<ۆz|2ucPaj"""""""y"(-J}іq_yVf^m\>:b\P+Tr6?ZÎݸ㕢 :^|0{yVuP8DDDDDDD:℈C:ǫUE&FXPO\cDDDDDDD*Wܷtq]L>U='y-#aDX奠!oRTvv/P=RfwRtcr[%"""""" %jScRe2UUP_][K5{[ """""" 9˫^5WPcFU **F=Xt.wZ\{5DK:5sᛝp{o8;pQ|y.;;0f@ #QfUyqU-)\i7&8jp-@հz䛅?aixfDKD)`L:ο i0{g]kqǀFj a漂":!&.;ݘ.F~ѽ; i.9y & S8i~ocXCʼn25D?꤯`?qWM+>V#UgᢼuDnpD'%#9C )[91ƛW;kV>|{ 8 UܬL!*>1*:̬< * QʍB\B[74(8\ցF+Ʊ9(`D!~c0& s2U8l8e^\"lJ2' IH@T[_+Vo? 0fa=([;:ķ8=1 wx@Ώ0UDt/uga?v<eQ>ڞnw++{;2_,NX4|1oSۏZ?Z]0-FD wa h(_G)t>`|B|7Xb3䚰` <1:knCۊ+a ٘\,ݞ Q(Z?1ýG.] ǜ?#>q!~;Fxf 1#}Řo[ucK 06 iAqTrG2<c3)#}pa6stP>̿'W?`ƽ(0QM۠kq%C1gs_DDDD.歾r GՀ *Ñc" rj d]zfV= JE^jhگ47|(<R-/o|}:E:;wTS4hqq 6E$<8k]'9[9Jq#'ueBV7 &Ķ 7צ!Ǟe{1R_p2"ФLcz4Fg1wK.,@\+1ahmmXƓxi~[=Qפ8~|9Clu2#98 Mp7xWd,+[漅#^CN c_>g ,^,X0/1hcZ"یOމ ['"0Îucɢ8zHtS @rk P-mQƭw!:m8P3Y`b$\0>h$6^[E:׷ϱ"׵?բ5;7\g6kfma7aw7ƈEr0q <1ʼn~vKԏB\J\5i,ĸU]worY|,}KxڞhؿGbUXqUFt3t!:5MDLT,;\O܆ +Jo<6lZ*Vz,\z} @Z,-}=0bg‹x8391Ihk4{vB-Z&8 Zo? W9 v.ԯI k^QCZRSY~vv6n|^yqZ2!G,<xPi':0ȷ3k\"Pe֊~8'*MB"t@{ ,=ab&rN@L[\U#ɫɝ%ށ&`c(հM>3p$wAUBVIςBC}7yv.tqEʡr9 C.*[r4f`ΫGJbC32[ >%2=֯סRi[d6o=n-q Ld,|wX7ΛGqߌBDDDo<"ccwP#o+X%/ iDnn^بzu d9 i _ڡ0Щ ;c{ 3wgY>ݺVp4oռD6,7EF RLuC*\WoWK35L䦟@țAv UuJ%f8Z`e]nZ@X&m knC%h-qFn.wn`C&;zocG~ XU0ݕhll/`]4z!]1#'u>[N+&'jQHMFN/8t =y4 th@TbB+#! w: Y'˓9G"$V[z> ԩWGEfVa",2GL,l%J82hw,كŋ8k,y U3FT򵯂 :S&`f!dGΣX]xu 8+!ԅx0jxȬTqjuāQ*&''ipl/-\4jV¤,o?NV}oJJE 8z=gauxQ?(v~y`EX_^ߑCE*.ǷJ,K0`#Gdtc{G+ }[ @FP_0OYI"""JT5"@ŋyݻc#e 8pVO PȱX9v yҏqp !1 ŔN ϰΧV(G pL?=k.Dҏ_  w ?W,8<דXY21qqHq3kl35 <0V|>ÂkZU= ୋz>ϝjl[Q֧ysI0;d|{u7↳]3S#; fR|8\[`q~ Vϝ?2t9 $$^V^/~5isy硅\ƼW?<$I!m^=eơ,dK"< '|3Id7\6 cЂ+;9 b{@f|V(­㳕yg{{4#S<x5Eq@< |]r /Gtuk&_<\^ɭ't!6zSqd[*; 'a}1Krq#=3`qcwEbع fɭvFqyuYS>XJ|Gd뇡Wݛnx? E`!˻qdZ|{v]%ڍs+r`D󶭸:Q(@؝VoWΈFJJ<8@Ɏxg&ؚz-F\ΑѴQpiHىp=d@8:\z)4w!-gOĄpnhg"}̚>ieĠyaM^?\Um݇ )pB῰5u9~q9v$܈?jV̸9 @ǖ)Hv c?Wf- z7=&>6fJuBy==ߩqq/>͕]TOt%V=0 -XEGrsX93@T[Jozup-o=~5qOőAw7,Iy>s=# vwlS Ӌ گtwGM2WW\Ñ}aCѹ^+9߹%`fo?pvw/ b(.䥲 IDAT5%m/6~cXX: 4(E3q(R-e1el5~qN,7ye1bPZ{#Q0w%N:0qh7nLpn)+}xZtsh]p48v-YH苉m7@eZ~j@@šijoL¥-쏍қwET1?Y7<ѭlDhK1dGL"x0v3N=4@X:?{ge }={""" jgEElR#4k>]r!nkF{s/ϿVcc.p^Rc . .j8ad!<,\K|ݺGQ^ Z91t/nhAguyj_8UH9^|9F_ JE>+}\ui{p83FѬu'uޅ2:7~H%]g㓅#udu߰:]0]:gov?ƷY(A^ $ s_?Z DtK?CdP2~~\O6gߥ+H4f ¢`CH?UC|&hձz-qsvwXloߋPhnl}4ig_0#G\>+DDDDdTuyv1r_}׉CK}pyѳ臻r[~̬)jhb3>k^RLElݼI~MwQ$''aG<SCn}DSM\wL.`EI_Q 5W\bჃ/wYUD"""? @:bף@җbܔΛ9s,_"-WLܰMm[6Ac1j|v! C/ldDDDD#"<>@B+pa?""""Mx "" Iy{aCv5C0g3y% #X-j=.(㿸u(R04~/n JDDDD?*BDD5=3DDDD ^qADD!@ݔv|v@fgu~h/!""":mpADD!@ҀxDuOQoGE(dpADDDDDDD! """"""" Y,\QbႈBU3v[^  *HUDDDDDDDAďQ!cMjX hjo₈B*hb5TaQCDDDDDDT˰pAU !"""""""Q""""""" Y*m܊a]Uݻ;a""""""""DDDDDDDX """""",.(dpADDDDDDD! """"""" Y,\QbႈB DDDDDDDQ*ǖ4:DDDU0еKW{;v\u(EECvpO"%- h1 !""hd5\n[nÆpVꐇ;vQFh؀DT;v[oG!&,!QQbcтڴoY8ˢX 6@Sj DDDDDDDX """""",.(dpADDDDDDD! " :b<:+ :T.Np/z[ꘓyC<3_ E>>DTӘ-i[ÒaRlI ;.(qM/bk:FDDvnێ;wعs'nۮQMQo\7.77|QE E.VG* DT_E؟lu6 5BDDwQToM%zo#=@HME(t*tAHHD)^Iy?$lT_OyŞ2g'3yhţG̳K8]sCo Zɝt堡t,oi^"cx©}vBtBD]Z( U SX.J]Y; cA<~MGyCMS9,<p/(Kt<:< ~Dy3X} B"I0RvM5>E_P}'+Iʒpx8Bibe*<=4 xP5捔FNe>8r">|РDc D{_ hev[xo8} k<:džhNMhʛӵIKi}6g $.Ŀ-!!<<1MdDcO~< ̣tmܡ(KVs9 -zAUȊ 3e,[ ۿEٻU}}$xcJ̙,\N L>b)M6˘q!a>m'0SC4:tw%?[1)ȭ5օO׽C1`~]9d6H@%v7GikI,\BwѸ7c#zS&pxFml>ѩ4%ly~u3D4H΃L٥y~e.'D)jlBtWs.hv.]ONmB(#&lC63?M.^CO({u>%ֲ3Gyfϰl5Jƞto.c&>.ė`J^YݪA>,ΎF0S?+)m2r! r2 k9ŷSNnI:]W Z_{\զݞC N@\^@7aZTp…qL>B)Ђ a[}W y7ޠbQ'h)^a@wֵ'RϮ63m[ F؂BNXY%qm4*nFcO6m)r(>5`+вoclX{.`_JءA|#9=%YӋ&QPؘOҕg'B!^qXU$kgmHϙz*st՘O`Ndc vNi?v'b"Q-*ePIAcSNjrwu5~rC0xiwOӫiATbrH1j^m<,Ac[7vn 9yE3],,*FAGfnTpP(u-ߚ5\=qDr0<n;mOKURy 487Iwj~t~ƒ'9=Ұ+C|xYUC8(`]>uGI,Hsz4 7|.m(nAcWs~?VҹT>Ş]R1N+j"%*]Wzv8NT9ȯ "]PY*/|K=n|dvyQl+ZSnS;H+i?e{q`D_DzVpDjp" ؕqFh+4_V` { 늃Bdp*/r8ۧ,Z3a {4+lzo :("#`O!Τa)8lKn˙V"҆{.?MD 9k{(( ߏHbTjf(@!^&TeiiPC85-g$ vyn;ِm]Ɨp2 ~[I^><;Yф‫ %,>lj$/+JKZ4sIl8{1Ls\C_> SBMڪD) 8z;GP4DE%dW|E@Οl;hr`E#9EN3cI4|+ĩclgîkbC='OwX>bWNfS۳<4^g]9Vx[o虰A۬>Xp 3o5RZ"͜<{oÁltʦ#9cl`: ˆ2ju}\.:^`o'8{޵͗ߜ#Ѻ*"zIX渧;(+x7mKk;9jlAвޥ ݡ)(1ψ.ң 3fpw (Μ#Q˹iuw\g_ yuP.Y>*F|VTqʹmiO zo<(Gqy)=A/6/ljShe 5bQOd~~ GɥZ)#h+r1(] M \+.xxxDZ=^ȸuwm4ȦuW0![78U)ތv宱۳%'WnI64pۜJ?5>ā֛B^!\I>EFNoGgBr+DE/ #k t/ew/Fulݮ 1;z8:oZܿg!K2&GzVl_ɊYW>nUq:@Pz5Slgp@)&/N>G** €%éJ:H*ԬJq;껧$_,IVV`u_ _%?ZDJC:JZ2}zgS~ϟxZh3;wA`t ;MSiwN^A4s|hF5.=}"ioy{[BqJҭk--XT˻~(Jsr:Hy?ISiihzŎ^ɉvSsRr֤t68Q㗌h_p˚fXQmT Ռ}˘(GhjL6ƾ-l1Ao5Yͮyl)t5a^E&t܄nfUFI>FUfj2r[Mo~{FYm!xX0pWhdx?Wp*R-`H[qъ0v\fmɃ=Eo"K'_Ʊ*UOKޛ6)ci9NTyrRӦ7s}Z!{q-o,##ZM@g[c1λ]?{>^W<](ӠU~MƚkY}hwf`,՜%1w*f,g$&̥oxz8^-J4/;0˞,~+cb3!: \jT6e݆VfBc`󚀁?lA;-ڤ*.HѢnYCD8QO7>gMrlBd+?j8! !y8ST6\Ljhm_TT]B#91Ǎ 1صK/a2#U'ⵤ+<)M(PnmUiӼIBn3yE%o?.K)֏OSfV<iY ú{ |/-ÄmL\Ӂ*n50c_+~Y߿nj21؝P՜J-l[2-,cJm+gLj u9ʗ40IbQ&_-eIKyڊCq$COoO;%B-3ɿI6d,mM | IeW^|ǟ&# IDATf^`ᆻ]c\}`ْf7~0ð K7(26B!ّ[Z9xߟFO"~8ppSH)67 wLłj O컐m/[դ!{WxTyrr;ozWcP.gk)c DEb]]`f&?l:1Nmyt,+떟YqoO# ڒMiQ"qcC.u !zxŅ;Т2qhw2~/Iydmvq~;QɽWkJc|0wg#̘;ƥL6B!ٓ+DՇqiuz՚4zgWˏb73iK4ķbܑ{1`c귭n4ێgvXVnD-v /MV);6;oӮ[Oz|"y=Kxg8MͣKt{k${ Ke%>=RgGҢn=ZHDˮT766rm1ޚ=ӯ. {, `Q&SytoUuf$bAw9n%=tgA,˛24$[T/`ZO?jԬCN#Xy1,g(jgpnLjC&YG!B!9QM/ծ{ 5W1I[/ƴEܘv A'y <= Ig̹(,v4Jxw(=Oet2V%jg !D),{MkmY?Aͳӹt2kgB ֽ,.NP@IfirIZ֑j76}ԡR*Tm[_$B!B$p!bϰߑNGz:Ƽ%Y칝.!f~HF\.+͓ӦUAP=[P^u’t0]/fl^ʠM]~ƱsP96s pjz7kØAal uݲS\{sg0K.41>b4|+ĩclgîkED56n8{+D Y5|4n.<gnjؑeCt:_>Khx.C\ᅑ2>cGY k4Uyo,) <0v="t\3lF]ڂ4nR'.`܆ۙIC9#>Ĩ1x鳁lS+71~l5I\XƯ#6 z|+Juo ON551kEɖN \S wnXZ quYp5Wqq,|4b]';큇.XBB(yhG;'~"zn~cO5f)TwѢ-=zH)Р1 NSҤ^tq5y+OcUpN^ih]; |jVnL"ܦ@17=hPRhptvD &9,P!ȒN/󿜨[jRl̋D" !D⿍Eڱ7S/Γ[Ҹ2l*:{z=ŢDQjeꌥll1IxrkOoV2w_ FY GMȂdSZKx+{Xʴok'Kwe>=ˇOitc[ұ-?MOK'4rѐEȄfLl9Nbopx,}֜)oW@ CsQߘ D 4@~6Cr3YBl\W ,M {7ܡ|ٲ88|Yy.DJdd$II---qrrB٭lg|:~ir@K)j{3qW*␙L&sߐ̦HL[jrY#.4ge\z|Z0z Y8x@N|Čwt%#y\17I)y>L^Fi2楓g!QlWF^j[dB!呡"o+P66wⰲB5f0d9H'̅B!^'rcAdFO"0nފ?bŊg gQ !!=no""O  EB!*sD}#ϓUU1  l^ct:ϟ?7/B!BPk,2h4Ԟͩ2"B!^-*r(2&{E' +Afk׮.cё"EdX^pa&ˇJZ4Z-\? Yv7} lckkcNuroW.D ef5^TbE OOO|||2\txxxad ^!v !ՓٛTfŀ } 'm25cv[jh4*EUETgJ~-*fiW|J5&$ɎR>b6tΈ0`z^9yCЪK,7k7|?{N&]L|ae}CY-D>^p$rvl@6_"vKƓXJzD6BI: pO*$-7kdMmMJT=No.x.笱o25CjO pDJ̋z*K.ey//2+D^" kƠDVu^3<|05mcc:߅N˰}B!xu)~u?ݥeЪ8pKlu|WF3`NV&9o=Q5DŨZ7Ɏv<[]_1}&L]=87{.=Hŝqe}O6G@|S]2/Sl` $qy\}4ͣ`MH1ՈӋ7wrt6/}b 0[=M{nN׺k:Ѽ]@)@+ʸ<6 ITIYQn9q_cD0#,0x ͟a^^\z5]e],`EoP$"+HJ>lիA "Lb73zjHF<==qtt̴~F剉$&&RlYR5 IHPE!/zo;k6 !x%0ãɜxz <uxT7q5}O,V`"+.: 4 !3zr "4"`AJ!)CݸGIersMN6i籖n8i 0oSP'j)AGEMTU"pv(}}LۢԔSJUsg'X"Æ e 60lP*V '2 \\1Vd<+K7/OLLʰwE'Jm5o#7)_-S޿ߤ›S&t͒xTNٳp\wVqqVW%&ִd>1FF5\DFD=ACSne!.5]Si¬>%28:;a `a&V48:cU3t=MΆqL9Yc:R(%"R3{DYsRJ 6ɓ0~8*Uur-r4xagY_ȥb^]jEv}@ !ʚo6E9 nWuSUjk*ݍŀײ;-[7 gKƵ;%:BmfJx@M.ߊ~/qJf-yUˎ0}e O0o"V2;O}K" `mV|[S,Oq!rʹG{c:;((2EQL#hGu{Tt>ӟPyOVwd̿ޏ~>B>,+X#Rrh;,fȎ, aYcg1 c/c]fk #EtVe ʊƽ%C\dҘtvũ(%=mqޚ5I38"u +c,xe|QDž3ۼyEyMBtg%@hɸY %<ʴfR!xkAnp|:4rM:yk+NΔߔJˍmRUTUwt:1m¾86+tPEw3ogT/L:ƴ d^hMUL&iK!1m2}o,7#"gC lfڈ䯿D%1S>^P]6E5 إEcEg0v37&/]_f*@#izb)]=9: /b- p$&\gI,?E [pAC '`uBUJ6I:Q6eȶ *v'wz|5^Z@YL_p=yh7&h>x9r [?%'+BTvǂgжMkTGF\|ڵjgoq`uǂ6?BpI||*޹{Y\F.Ҧ>%#9gLMjJ{5iڼ(yo2EQTӼj@ٲejܸqü 646ׄ_[_S5ndv-l&r_;淊>3w[w‡)^]6IW[d2!8;F$?,1OL n.e|kKv Fw~/B!?;SDZώۥhW1mBo!y.D$0PBFɰ쟔]lڄQ QlҹfK~mz8\j4zl:OIo^4|5mI^Wv Ѹ~Ts%ֵpkxb-+Myrz#s3 $_t/m7̔=WTjg!g=î+gIk 3E3f!;Ts"WL׫>OR "Z͛_У'G!$]Yv+w䗍9RnQm8;?K@EEWuuBCDͦPcKt{Vv t^oӦhprq["mSv6>lE1Ӣާ8i2,P]|e*ܚ岙Lǟ1,R)+(>ov;5^(CY<|ښyIXyU h@8j*{'4H+C!&g"3o}Q``0`0R4g/eM"Q׈Rw7]|@)6Ͻ~}?5qB[k̈ǫ/bkYЅ4jƱbtFKl)n kڍ1/@qoĨe^ B!H% +e˖5ʱͪ<"Jԝܳ-CBhu\X=gOĥHeuB!>>\~;wט#J:ev'ɩ5iƠ){{{4MeqpHfT_d@,_ipo< eB9;;Sr%bbb̋k:BMa~qpp ))<[[[wsssK}B!"ospp T!$p!r-y^F;̕+WtO~!p[mB!BwIB|c^zYquuhѢ?6 !B!$p!rU RB!Bm^ !B!9 \\3*bd0^BB!Bs$p!r%3gΘgeL2ܾ}֭۬۷ M+S O1m_N)B!& k9 a|tUfz{{ Td%B!"oUU1 sS\]]&)) ]O >/'!B!y.De0"d4\VCCԩӧO3 X)SWWtyB!BIByiРvکuQ]UU)UJ2/JigeȜ( e˖}g155SSwEPmmyNn9HxƟ?Q.|p'3o}}8fkĥ5kS4l[Ԧ h%?!pF;9Pчcs'!|@~Jx4cSsW7 7\4>ԭoS>:dj )ۮQD*50u:M֡>sXӶOꇔUbrAT§ |XwGM5߷˗|򽓞ݒ[7󢹳m/h)-_mmގVa҉UFEm7XL#.N!ODÉp""פ 6ξ~K h >J^͐WSgsz,[A |.K{bˉsNGӭ3fфGj ĥh;zVX[~{ɮQD*PpTcmm@P jߓ˗XXe{*`l@\ z=DZ ~35V3N>TϬT4dae>7zNDw_yR k cw[Ɩ}NeuZ K8<G5_1&9'A;ԖXZl6etK]T B!koŗ cƒrDSZ,LBӖ" hԖ,t@zx4\ZdUǯ) rU 1r'<DŽ~VBIOY;ɧ2®7dRߏZ[=T['-$gSx 4T`QSbPr.MrgY<7' 2!5nvG2Ʈ'[j$ɽ[%=՗$h#[*/~j2)(#=+E)KqEȣ؜ ._Ni_g^]/9l^H뿝i]/z"6;}]Od~=}*uTrP"t3^xAHHe˖$/yhh(FFFu^^^TXQ'Ghh(Fɾu2`ۿנn^Utx2ɿC~pZ y_Si1 [U §C7oq޽,ie˖R Y2 >zڵj&gq!$& gΞ`]Ţ0 HY:}{ZٷͣdZdZWiwt_+9,2nK۴,_vEuU9) T+f:5srƦ6R f?fKy75uDBrxEHAO\Z&))ݱDT9:(H~ČǢ 'Q;Q){uPZtAȑ$ITX=,AI4ͅ#P *˗/3tH=-| kaqAAAO\ښefcce}^ccc .,   1"p!|I^   D_zAAAA>Y"p!   'K.AAAAd    ,AAA%    |DBAAAO\    A۔sR/1׍On%rtL#ZλʿxtA^aW-t*YwKÌpϔBpf/+e!VF"p!g S}5sIOs{=6g,Ci{A{fͻu̍_-vh? Q1!U[O)q១.w4'D9² ѭ~mjzwv!>m+.ǻFUִ2(\ՉoV?z{ۤk۶5-~ǜ3Ѥ=!' *Bw-Aj~-'n}/*\Ԩ OlRPtS7{Kr ݪ`9ac~Uq.yAҨQхZFs?+M5/rYάyc~=~nwTPSU{;Uw |[K62c~[wT@p3sեod -\q58v@UV,yF^WG_A8-/ۖږ䖃g4Fcѻ?!#r @)޴yߏd+썫O6>K$x 7axkkգXHڡ]h]{\w4-2 y\v-ݜ׷47M1>?t3vai` Ϝ~W@M¹ySP{ ;3 R@~sS'3I.:N ?̏#Qx&N:Ħ!ؿ0qhfeˑ=PJ[/8z>9q"9O9p>!I!k @l9r#QV bʑX؃̚rsq7N[iŬXhoZ- YwtPf@![ Lb+sv&׽ʝV \É*?=w r o)_-ӳ(܃Y{sdlZ>ɴ̵%CtcWB!99,ׇMzra8`&.zsh;gka.ջ*Ej7g;8pVw6bϯk)@&ѥ mf_6ƺCdM:-d@`K ~%ڊjSE'dCP)rwPVPT*Ϊg*F5Fd@FQIvYi۴à\~`T9Gu"F[cxۖ{/? IVïy3ZƱ}/҈ݚQGS}u!O A4͝l{FHhm;oH*Sؘ`HTsBF PPbl[w+fV[᪰)]Kl9zhL)R q 0~T1@2ZGm QcEhtTb}ΑM{ yeY*5N/* -hXݐW6ߑo -RSQ7Zm?TJc"~!ܿTx8o*_<,O$$з^HFz}4Lus QZM#VRqo:Jc :RMٓז0=7~awZ:*;tP 6A2c- ԢYJI`Xүy"1L\bRaT_7s;͒DTGR2*49"T|Q CoPei9z"YU|k/y|:Fvv '7lnǴusWV_@KK*D\kW8+VEZln{Wf~9pZ@)4ǻI >\Md'unz-|?q)ۈ2Ѳ-OU|)I.˺B w$qa.n>Tm\v$ uy=AK4S /IV,\JjI)숢DG)i즄%RTkfX{B!<Ƞj`2@~XE-#LJx~nSƓȀرt cBކCóDvA&"d# D$IEx ͗5R IDAT 9TlؼmJVX s%K2 Pe寗/C&%em6SUXhkMa1 'ҳhRM,Tg*dY֭>&"hlml \H[ZdWIjoM@$e?0[amkr.X'$>"hRz@"NྦJDEtkݼWg&Q9."`!L]?Tpml=3q;ŌS%_T1=oPUuOK"xIV L;XL(V #o܌j+|+.ܘe_AGK/=XG {;R@Tï:/F5+R֢!spcwD\7zN;}&,j\Z}Y?0tX>ʯ:MT%]z2V7-*C\3!;DEP0-M#$@& 5:s4 S"_4aRbMjK,-mi6nj>@I_GzOMQ[Xca̷;'N6IONU[N0"(F0Tȟ Wg)'Mj+FFl}TXa])]:$uQSl G3!K'#ymE%T juZ/T;~c+'|PR0Z&X+%83iZR |Wd`QviڵsxY]B[-,A(/є5 SPH5%xA#qE5ݱs{bA, sN Jv"_+T[P'0mmiN[Xv2T D;|E&eNAAy*!9AN"g6b4\\.F]֛fβxn0Od@Ckz IOv% Ȗ L  mni@QJ⋪E1VA?8vPY1u=g&Zc%,yBb@͕m4y}|A>{Uq8f Hu IOL Z((< wK`q[q9J{Фy-<{qۯzy($<Ͳ=vK,QDjc?{2Ƿ(/gξ{ʀH؝[KS2 Od^uRڀB>[8 WԣPƅTʗeBX>0GSjet&hNۘ& `2N _S[B-'u"p!E:Ohk{"ũT ^7-Ҩ)ď Dn#ihߋav4zˠ.X_za6pu9kKN4mӞv}V%J3y\o]C7xv]\YÀNԵwaܲw|^fqWO0x)EM@]XDw;ju?OgW9zٔFuԕ=hnW,ѻ ӲWt&U3濔MªяLo_ }X˷1L{2&jJN]<||A>w&L|{l4mLR鵔{dTMCGgۏ`EHd.ՕZ5E_yWrwP㔉xD.GchG_䶀wJikHOMDE|vSW W m.]P`5eľHT};=z|;#I&O(}RQAxf枭K6Pz|?|?fP3夫Xƽa+&tmɊhY:nX9PoH Hqi]$4i͝X!',w唖uu%#ki]/z"K׭^GO%%rJ794:HZW 5UͲfL(wf\~3s~k{99y4r5 bkFy&26 ]r^ Q79pmv+z "xUQ~Ϊ-8:~f[wtй>zڵj&gq!$& hW.jO!qQ%|F7d+?g`\&l]K:R< ?fn_اry+~C6:s/̇@v):_oOvyLL6-.2nK۴,D5g2W.si,Iɐ) 풶?-c˧vg?K-M~V+_21WtYڷ_Zϡ -T(FK"xjB5Lc0(XC~ͻkyC& R- dḙlyIbU9M}07:_q Z]l|/14̓9$ɶ~@iJɣԦU ,מMIMɆ/I5.H~%UbMT]__c߱ )/QTq4M(>n&EQah[?Oc'O/ §#x"`CzO+T+{d-C*2Qr.t3ɴL TӉ[B1م jN"p!hi{rGR C@Oc<|)>Exsb2CGShX&rmOZ˶T6KNlyt?zhv0T–#X0SJlg!ɵ{qXCUL93νeY'M&%1yC3?] ¿OE8T7]{ bO ˢ?袛H6~ MotӅN\%5V&B )B/Қ^^1TkKc}nFɚj_RHuA*J¦tqR/]1H2XgHQJTѐ/T8],kugGLX@vܨF"^uQ ¥Gn4x繙\AAA z\8fG&1&d6mJLX8I7e6Bjqq(:R_d5NF~Ž(DfX{B!<Ƞj`HX[^/!@ 'ʴ o;X[S@9<3Lsfv0>㱕6V~z%dR   $Т=Zխ,1՞杁o_8rLg' (Dn=)ڝI]y}m##gZLvJ*T|vqH$Y1K6dae>7zN9Cق   §!_r)qj~ K u':  W(xU۫A&eNAAy*!9E*ݸCDܜ3+R)'>9?wɉ&gy&F7 I&ep.RBBpqrMArs_|kMBHMA3Μ=Ea@]4@zӺ]dm%Ӻ&ӺMKZk%%]umr,aI<<^bnaQ2   B 0W'c뼌ARv舩nVAAA!O !3^[7]AAA\"    |DB4崫۟ l̘I>kĞ΋$Plesdht7(lw[#><]}3A8!R]M*VNjթe=ta܏͜ 2L[$3~U*TBŪ-{Bdݜua܉z=,]?? ,wM2Oȩ sR /#9/X}Qd^Z߶ͱ!v>qwhBV # =i5`1g"ɑ\4mic.\wm$0A#v =hW>K,U"p!BGA\r~ls,N㫞˹*3pvE.1R)xWB8k6`urGPtF›c2bDpZ>Ȩ{ A{ȟi1i3'{#b@C}G96G=i7G>y"p!gC20D\8'7<ng}0fۈ~f'S;<9iHџptDЄdAV898`ю.i#r6 o}zް~z55,%j}2۴w0_{ W3v8aw)S_aN68ׯ͗]i18o@w_1uz5w~|#nŃői=0S?b,hD{>JbO縱;kǍmGgWdޑdPfZxE^3^'sl7]dOpsd^m%?cyٚ Nqqϝ]g7oZEP][ѿ)xĢ:=FH,DkOg2~/]uoKQ"ߥ-nj>| z𠡫7-zʞCpqdbvcvNf84˄jsh1>o& Sfxr=)o8pcf!8Px [*Ur$V;^9srvffƴu#`T˙bU~Ý"}IkG%=S,%D0ٲwhAseFd\Z~Rӏ=ٲWW̩}̨iq!^;9$/3w |4څƵݴ9h;W#(΀%Q#X? .ד$..[5)2 t\,),?kb@x])q"[{,bܮWiw|Ob0gpVUQx PuZCQΕBDdod?G63Bލ\,]hZ??oiP8HH~!}d%?ΘC"XiȍBlNUog0PLݐffyPDi[8u`~´~T~GȡB}Y!v83==U楨Ys9QT§I5 r-D~Tĭw}o֢1&PbOp _HqVxE!8"MQvW~j]Mh9ȡI&$*?by:TQN߰v0+{cRѠMAmA8ʡfAߩ ؎? Jd0{ۻj8ƍe9S$Օn سW <KNT/Ɍmt]g߆gZ֢ &&jKzƩAa7:Q9'O7Z3AQU*=±"T|Q Cot. >y4+eJeHQ4)MO& @PU*4c ȓ\ݝ aD/Za/o)L$/K5gOr@2~`hXQMq82ɜZ ų=X>"0=7~awZ:*;tyV)dx7yO7WcҙD"D=2QalHB741;'?UݿBLW=1{7!!'GKKRyͱ^Mo'ȦM׽1>U4:Q^NoBj'a33$D%0tԯ҂~8 %'>z,ۚ ;%є*@CxX8I7e6Bjqqh‰2-L @eLo׍m5utvA*p ]@.i2oLŦMZI,cAYLZɆB)܌C )Q(qǣ` PCygZɺ-XAI=|]4Lݤr̰'e )z,F,d"NͦxNwГ  MB8weT܇PUǯ) rU 1r'I2Sׯ"!;fڗ4.zӬY I h{~[/wk]qnLnKePTLCvVK]b4Ht N)k؟3nr[ ,odˑڛ~3vd[Z¼$ΞvQ㔉:$:U¤p5ڍ?*s9LRp#-".<7Zv3~NotLwxU̦FB)BoI("RD?PT, "Hł(AH"HW:"% |d7l& DH }y2ܻwgfwfgPA_?aήˤ2}_DžX9GN]0n̰U^IA9g!5skWmleb沮&]l[TѮ`]moLlTV7 Q-oe64{!6tZ708xH[^̀y|ޢ96f/8ao?w!/۶YӦp6$e cX5?g"G6_w!nn7[wx{yu>sjEn<&lrOY !(`?c y8!Evcy|a=_Fu!ȍBBESj8rgk!I7o2fe:ky̫=>!D$ !(d_nk Mv1*81_1.Ŕ$.D<1TTo^s+B!zSB1,B!Bd# qW5b#( !B!yąkħ&IB!B!DtcR`5:X]}CB!B! I\*&%cBWOB!BQ,ȥ"B!B!(dƅB!El#$&Kk( \][6==UąB!EءGXҏLjlBQ:BO' Q$,qjXZuk[qٙ;P4|q%K{=~e (LFĆyUqFg=}5 L9z 8kB!($q! -a&ѮeS5iJtd-DapɘYhkՄT#$ [aY3M@JZ(B  q{5TIB*qc薴mٔ6-q1"0DQLL&įEiÔ3X;ߜ'S(h27>ɰ84 ԧVtW>C-ykoR yw'xBO^푲5'xw$Zng;U/juzWAi̇v $L GH=9SpA.&Qf.IcdN8nT zxфTr̾B!B9J4od -f>+ZpI‘oWtY1Tm#>NI;wݿfxucG7+vMW1bČM~1D`[ ]k5t6gW4koxÌe{T~,wcƲYNrXN: ;k [/jj]0㾤 2!Nq!/ątpl`-η0U`м%<LCin׶T,,p C64/a:3w5T #]|x1͹)}B]nIm;▰|iCs\S.l#X՝^vO`>º t46\*WHaꍘz.`@mwT[_ F%")!($i!P' Ebcp`KE&,g TwuꀪY/a8c>^LJ WZz/߬'Rp0h8RW< i:TZ&#q/kSLec ["8oj.≸ma4SyZ$ھ!BqIB 7qtL2qaWIA~f3j?<'̨jw{喿07'L5{r_YyNWl#%xKU_:fJ!ZԱC+.bSW !(P:rC^=ş9hcMGuW@Bu /o1Ug\9UqH*`BzGrn3@OqMo:ؐЮlx#3@K%5WZFsYv,3Esyw^!D:k_ҿ=qwh/㩾s'P-<.-eXWؘbl'Ŀ' Yqk?GyjmwYI4"6szKFscܨv ldt%%LU2}:!Ա5-gaFfrߙ'F;2-\JGghݢͻ<ĄN/BQ|5B/ud;tk'p9m=G;H h3ǛEu;/~^CؐKED2Q71B> 8ZT1vl-L՟`~[L! ?k;;xJ?5 ~-{ypt(>p_oH&S@F >ZgbBQLH,޸+}Sd~ThFs\uY.v+0+毤¬n/u?v@W_ڦbu]]}ut2o}$ CA]Yn1tKj !Bxy7S)9bŁ>cv@;>Nڱdvo~-A|0s9{/%9RL[/MfͥhG>2<6w }˥q槹L_ gMxa丑tۥ繱 kY v՗oˏ%3ͧ1njƾ,XT7jxFw!O]Z;ʠh=pׄc&2 ,x6EtCޡYYxLY\3Ly`X>XG3;yDq! CadD{uO?/B!(T6gyZ8vm܋w94pI9:s j82~ hWW_I?=odp$R98!3gA5= Q}#TȔWWGtL>]UK+,؆'߯n3Ww-~f,#~ ĤofC#9b=)U&=ƘY1UfKȲ'TJÐPCR JthSK/%z p,ۚTԟvzҸMC\.s- N4ӏz*8WM*28:Wuec9c@g뱬}Us]劋+`9ջQvUUiu3[6sY:yR;gYŶV <> Nb ~>5PR۷lgU 1;ײ'~\'ńw˾t;ȶI ^mWUWŝmPֹ NհTƉwjwhMK\P 'Iţbm*1}"?877g끊W4 k5& cfCAY}!B;{T̘Ɇc=#UynI *&2dez-DB|= TxS⃯bŤnAQ=^GtF{i{*(}-st oOϧ*(JaFEAEGt̑D`C=%ihɰP&)>+X%O/KGrmA:=ٴ9#;Ac>bʯXCroɀpK?L}W-k\9^lk$LԵhO-^_۶KIIh3: >^~UUT4MCl cy}gUE,ob!_Ŗq,K_y4'Lw4z9gVgꁏ+a [Q/=})c3ProՍGn ܍yuQ%y1q$KEDz/ nwB!(nř!Pw|·&߅=;c+&a&W,KzO0U|[U,HT*P.$NgͶ Z3ݫ䋏wr9E4Lx^1hĜ;΅ tTJWEҭjP_~ s;z"N!*]՝dNx9ql::BI\ \"o87#AT"ϜrG i8z9 SZ0g^$_8 uq[}\T/”Nh0wi9rg( 2B+ ,>B!Mw]Oz{01aEeW/OaX]nu]G)ߗ\iOv6)ICu=!]+O=u)o a?^h9 ry|fZoj'2kY&1#FD\[3jϟp[&~WqvV%?LJa+uqut-e֦I69Q6ϾH/4a Cg``L9o=GhN>To$^_KfWxpziW߮Iy}˹z;N^ʱH 'gɸ 0 =J3q72oƴ16efp|l?ζRz|{Ֆc95:gsY%V~6vylquqPsYWOծ`W-*hWv.z[7&6n*{k~n~Sw=oӆ t 1Jҝ[Y7o 0%1(Vw فؾ1,"7_p+mAMlD>V@2vş$.D ,>B!DLb5j5]c\qHBP B!BQHBP3 ςC!ؑ7ABy {9|gA!ĭ#3`tzJB!D#B"J"/>wlh QZՇ/Ј6O1n,F~oSӀBqg[ !n?I\ };}VVkV$RyS谬j!%-pLPpecT!BQEz/bRT&- z%Q:&tW>t y8Idphz/Z_3G>E`gCP+Z ׾ᨵ l1)G^9C`3v{;IH Ӈӣ}ۅФ9m}Bq+\ CuYd_.ax0D1#3.Dz!JՠRX_hKN<2jw\Đ?tsGX)/wK;'/ʯM݌ XH~Óf),X«lg2_nD9-ˉG`.Xc_4پ!"{/Ǐ3*!M.]5k,Ċ3I\ #OoX!V(xʪ= IDATw|- n֙V[xEԴU̚_@c orn35e;U9jK/Qg [Xw >Bw(O5;hej`̝/4aa^"a$&&쌇̺($q!r(myͼTZUeU*~v0J]On!Y !Hbz曦1DhOb"q/GFH£j0mI ->5@B!nx !$q!r(|A``c zL_ܛ~dYEϏX|I:BX^X®W%^L:IDvOK{w-[8^ !B!nܜS`MI]ݙ>feЋ53AЧ\ S.nw\nӛ3!];ΕT=="84w/w6,}i/rt$ZB!% YDqmԓ_2zwBwj׃J7LU2}:!Ա5-ga? z Ag2}s=+ϓ3ˤ'xwPGhEP1|{ !Bqo[b}ٸؒ'j. W~vemQGu_ʾ1qSɧ[SŔЖ<}*c8SKCY:bugc9p ۷3B!"" nŶ;hִ1́ lBbc7[wx{yu^+[e3n& ׍?/lFq!roB!BqHB B!BQTHB y !B!E$.D.B!B9ȥ"B!B! :T%uB!Dpsw#Z1,Bk."{t@cH!Nڜ:usswNư$q!rz!BUU[1,BTD!B!E$.B!BQdIB!B!E$.B!BQdIB!B!E$.%/%~֍U9Q8]ZѲ|qblQֳ̇30C*'uyǸ[*B!]%_*(w~롕ebM:2rLjz*vYN}M<.Y0;Mgh}B!%$.%Ke+\Dx40L89 >B!% l1)rnG6m:1_&^׸m};CKxyP0ѡs} tMȨo5mɨ5^˜A!ؾ;ǯ@#}(MҴ}[aˁ#\`ڴnEޣX7-omk ,d^zxE60D!BB| ,;M^důDЉ|rJx6l`3Pߠ<vm㇗Yn ϛʁfXs'rbmw/xsh+*@^cwsx__-;5gvgX4e)',7愬Ć=lWfK겚I%P!BbFBra+l##w 訳m!Dtp%w6KJssŹ4Usz 6OZeq@u2}{@5*fwÙV 7jur\mЎwť :%KB!{\!J<-2Խۻbihm1oũy->桎1sII*eT=뾟tx+S>yﹷ_2DŠlnib_WsmA-'QM*h4IB!($q!(T2Sfp9MӁ8鷶V 2V̺)zMʬKk/Ok\Ӡb䅂L7/ɫ/!B!o-餥Yt2,ٯ0x6I IWs2, *~{f=CR8'$q݅L@-Ez5(dnQ)>1wy4$\ComB!%̸BsfMV}vML1mvGl{F y}6urTzdޟoE R)@OיF#CӉN` qs 3ξ8|%)::Gͤ)]֙)i,b!TG*(RXqn݈ffEfpt22gTak)3oBQVQeϙTn's)IZyy,glUB!B4qQ)8k) et"St<E "#fK0d5bү-:$fg&!T]T<]ޤ)TUEO˗S3L4Fju22's-<TEYe/mIEA5k*:{1+z9Lf5n[B!BI\pu5c!: |TTl' ~ >V:hJdcʎqiQ<[*QJܬ+~cR)AHq$TY2SQwXM׉I` ssn$L ܝ O3B!Bq睢PM*]ʝq), 9x1 *yI+jllW2(Uɕ=L򎠥ZWh虙PQt˿@Qipቊ&J)[ځrLŧ븖rjMVhq>gwxxE˖ )B niaW]3N:4vD]&|T@ 㿘 "B!"y({b=i:3)ga&"Z2t^<É|iED^wq<),ܓt>9f^,N׈MJ:ɥ_Sxˆ{dK<5:(.¿9Nѣ^:̊>sW'L`ܹvQ<{ꉴqH>ٯd/jU٪mu_;NlkP:ho(%4.nLv8UE @k֫^{ s, M8 !wz$%;PPU& I,;dUUWH7t)s"u:G3񾄄q|/MȒ'2p4h.X~MO⯕2wt #cpUOHO3wbsszVk!l|J^ xn6z׶Mc$sW/Gܵ !ف؛C؜:}gG_`y#ӓ=gfT}jڽnWdFȽ|BHa Z,kte蒿c¯obyl1<7MNyc0va~xt5ܳ?32aV6tgt2+lL'heJx c=ɔkNgy_ GaBQ$q!ŝ_Ox]6Mm&R-r#S^]fZ<Ǧcmdy寍f\hBCzv i .%x 6mZǒkǔq|ggc?Fש߳a2^opw'-U3y;O/f,z<[Nuܦ놘թV3;8f,Tei/ UUy}D6m'ͣvZƇ݀96­u:E} <6GїMdn&-jqabu vKu h\> i^aFla:]ώZDm>wcʷ"̷3}hP fcC:݈Xa?LjYs5+UZjܕҿm7krjšѽ/J^+zҞpWX~-o C/S;R##9tQ:UDozT}?lÖfkre V( ?N]fqwR!/I\!D!2LNhMM1xXKAqL})Oֈٹ=x 8)&[AHsw4@-\mуi߰G;*4yEnq̤[1?Jnj)ۃg명~h> m*jaHglSʉwjwhMK\CSϜa30 ߲u .\WI =~c;m svdVx(uec9c@gq|7M#;T>EЁ lB)1~ER޽c;ŭ-?ו^8nq+);z:ϵB(xHx5@30e tdp|bZK:C}e\]qvri:\&7@ܬt 7~%SE6B)d`\2tpvL|6ǿs8^Bh cw'G=`%uY- DǙkb󡌷bkNCwTJԬ}7c? m,B$ !(L>eJ:NDsp"U|pjKfL.ԃaւ,mix ND_C2X}}PU|\|nYڑ1QDk$%\d(ܭ~|gyah~^SJ{e]̞5;3-rcr-K~=hh>Y۽VLu-*TjCq )T'%Dg>L<>71Hb`j} [~N:0y n8.cf?j4Źm;9Ȉ{]vM֍Gudz9=Dk9.ڏ1B!J:=!BQQڙl>erV؝ /m{r>x RݍS9[7/?'zѹK7?Kviqttt|x\ϛKOqñ3OZ ՗!nlJnSv t݁{[6 \5IMuj6r3gV_<7't> Vwk^s9om?R!(( [b}ٸؒ'j. `ڕʶE~Vo+M%zoM޾ưENDDp{!6tZ.ڶmh۶1|Cس{1\Y89U[gVsNԩCrUYn6f===39Bؔ<z~ᵹѕ$EI~R!DDٻ訊M% $$ U @ ޤ ("AiJHWA&X @HBH{?RKUuΞ읙ޙ /+I}N}oK3mMN44FrZJM^)Nxܴh ZB8q$El _Fю//3g&[}HQD$]3H[~Gc50d R g:gYڇN`[>K+)""(p!""O͇Ϥ}f6Ū"""r?SDDDDDDD-.DDY㜏)#O)#ϞΓ.:gO{.EDD$.䱤mi%Kfvmߞ&7)_aaۭoɔ)E!::>KGG'<4XйqΥȓ%Ydf`8haaY"O~蜥_:7"""bO K{KՃCDDDDDD*""""""""Z\3qYΛǞ{t29rdl@mZ@vsH y:| .fݕwyΝ;ϢӲE ~GGǻʈE yjxݷDiѬ9 $8s, /b;~wOsLc\S3tۇ/ H8::H"lf} ݷa#F/FDDDDDD#jq!OřgYp!&1FRti"˔aБ,-4ٳgy"2dpK1?PBah٢C)˔y,\ـE9tY%}qZϜpY($OŞ{hѬ]΃l3HLl""""BlL}}A>-[R )""""""(p!OMߏիWiߡ#ĉ$$$'?p ;tի >#""ϫc|z#ϹUs<*_+=(bDD+#ӧNa؈|` -f0ʹzu~]""+3e=ێ,X7N|wNBaGD~AX &'_^,Y7{Ew2@)6Hh,V(mȣ'""OjT9::ҿ'޲sc޽\tH!ehӺ< x%dU8ܼoC3ɝP&}^^ۜ^ЗY?M3[Q6to4#1tSG~Ųp˒+M)؈i#-bhpE@n|52t~X9o7\Y>N4[9fvhǞ/kN^;ƍ#?~Yz"JPxrv1Z>3(jcXӯ,iۧ\Бs{7,dZR$=Ǥ l{9L.| yHLYi@ZCmL b o^iև!Kizveº]d̤A5_2BFL7[I \2b5EDZ%7Af E gD_I7,*Q-Ɏ?oa })V~X͖M y?^LM\J~hWK׳ud&̣4.Ɯޟ#Gwʶ_4~.=>_O#Nmfݖ--<|NjΧnrȈ6}㷴s^k4s.j)̉y<K+1mbwɺs:j#g֕ {w&MZ5W46`N`ɹLacd&Ĵf-#pnlFu)Z~ggF KWĆӝ 7RR%dI yySW2ko( ̙)Ze\`lٗH p(Jf%5 Zb޽fc (A7qkjunBa#b:nBj9p6_׺Wl$ iخٜ䜛JxjfաX8~!03X-نk42|rq`rDkP'Kڕ'廿8効~59 }t(BS\՚S93Q«^:SR}!#p+P>%.X~'e&Kndst@}s4{|;1M2S&2AttL99=իWZT n'v3ȿ!f{3p g+ ",,>YDDL/Qpjɉ5ԧ3F~GRwK i߱tf3IZ#vk΄W;h,^; Jb 㺛>wjf_?|H#DG`#KLv=0{+ͺ,ٰ@Jɻ2dƆ?h1#^E-EiS!39""T+"""6+oh%VKň&Aq#wle,k `ƒ[0*TUWO0nc%\ CE/3SmH񡻘28joPUoog0UK '#$`#ó3 5 ?֓(#:og&츘M;t+91x=|+aֱ;C3)SxVfcO):.Ѽo=ߣ~qrED_8s"ԂADDMF)Zs׈:ᙳ(U:{`FLiH.M8eG}W Nw8nM+S.F;l[F4尡9v}|Z3_0YLO0b.5e eD<[pzA :=Wݐ8LOFѹM%_si4)/3f!}J~t7FocK"իWMiN|>)UpWuO~jeJ'"ߡ^N!""R%K'?^@b $M}oK3mMN$)ڝ2mM34Н{iRqAN8g$1tO}=lЮ⇬e`\@ߺc|Ѹ&oF?t?cgųV3پ't=A(Sxf{=不' gFթJO 4Hx+]kʄW~2Y-y"SUm*Sb0ª 6#KwvIlWصמE0o;!wD' jTh;{n;F.i.mL|m\ɑlWJXqo޳m} |$~;ҿ7[DD$sOqm{-l˜9BF'k,YK>U1V2㕸U5sp  &w Tb?CL)oUL'5KcnW*URgMEꕩX>k`u);6~^ ccYR[8mkJXvQ`U j]1Bґ]\Ï'JѰ&8gU)W9AʮZ"0TPUĤݞA (G`O9翥Ul2ZoǬ7̡w-Wʍ1q~7蟿uP&I}o#dXn^*SB=:OGa!t98cLlL`,%X2~͇ܧ:37*R?c6"~-kP?}?a֤Zڕ*fn.[fg[D<ZS\9+բEeڨ0}\ŝ@&̨zT5N?ueҾH L=79/hO9_45+Rڿ˸-HbWw3{*/O|0gRo+)na zϘ;7M*5_/Ga`\̺ӥP~b'{hDYq{/>Mx)gaǮm,zÅe#gsj%%_P,۹15=lܑ,ryb%2I7ov/{Q&96;+˷wDj^KG $5ˮq.<1vÍ{]_DG:p&;w/ST47e`J6#\#qs _-]5i0csOklo);rtgl[%M` ]A?kmos||.-ga7~K; ~ b|[;glڴ1.1)[:Sɬݼz!ͭLs2#u&U9#?wf||%+vŌW46`N`ɹ6q{|w붰uar̈́QG?i5m-7.fh\خna^LG~=}o#{y9V9̀Vbņf2M~qkٻg'[ݪpJ^\6e8H~HɏWسGz͈);I>vq ÿ3~.~Bw`뮭,1e@s& %<0qXxHa߱qNN͍cYAѻ2/gƺu,ތwFYעt-k"GJo^4,咼v#`%W2eNoL} ,7lݳs൪K28Wj1nN6~mѓl0wg,>@xqs?n^؇Hqή IDATߢ͔5ݻiun0c\Np|qֱ4:9ְov|Rvg/~mQؚ~ɆٱKޫ'>Æl]lcv/oysqw38 >1Sdd66OSc YϘ21~*DDDGēcQ̘IN2S0Am>aB`(Hҹpٳ$^q&<4>A 9JV#&Uޟ|W+ozO'C\bO\$﷟nd/`Ζ\d^Eɘy2 (WQ`ryfMpmfN'G_̹kѡ~>21kjp|S,̱0'ON1q ^i_¿TN`Tr\&pPJmk> ļ{?-Q6o&<܄l=FĎu݄rl' uHj 0 U"sX1/t536mٜl5ٓodۿ >|0%y}s:^jTNyKQ8`­@YJDvSdL:y>g~ 0O[4LjÿzaK01<O}X:.8,]EP2$e-ZO!q~9R V4/3})5Zs^.*Y]`|$\3>.Udʼn[3{SȅBͩsɭf+beR^3)_i*),k~=bX,݀{~~}4h&G0MvlHAۂ.5rbxt]j S@~X\quϵeHnY=cuPE7}ϼ8zJgv;*'<fק59g]K ǞU[P3 cƁ,[l11Il\۾y^{Âdrp-k>rf2asKOL۷kм֍G{\4j]," [Uufs'U. -a`5؞{ͭ)uo2τŌW~%jwN#9f2t[*m)Ggڜ  їbpln`@RϜ LwbxŝCSkd|qMSLj$]dvIdT""}:IN@X Ǘyo,-Lr#|ň|cMXL hvxńfðEy݊o);kSf|XV~]ʽiH|WT?RZj1D1v|bi||WѽTmxeNjl|ITf "ђga¸}j*LN3HP,&q5Ĉ󢩧O(Z>`IJL]v 1I+Ai׷dGN{1MK|Ә31uŗqp=FDX8&?||nܳF>9{r=t]*Eәֻ!ҶG/:b̚e(d0~zcv#Kf;װ͚tJrcw:vgH*q|^8vsHL[U1~eƤ%V!DࡻM{ɂb&c9If,/rm؇m„X<ߛ7̩WS<2~>ыOv2uJzY>-N] 'C};#seXW2MQy~ؓngfxd*Uf< "ާ`>xkkf΅)j2NE~nI?׈tӮo+Bc ȔtBCjLo >ް76y4 !ƻ$i*edM4i%"I\HL@.e\zq6I=2 FJ9D?V-dJs{4-Y:>ˍ}2,iwZj6!~x31 ჻%%{ke,\~9jiW4I=l\Kz0/xdWA͐bKݹ{pJ@~ރҵgdY=7VV;FTjPac8[$Zc iK;SHNL"Krj׳q=ιP(Y3F~= r"[I_H{E p#1!^~]7M$Fؙyep~k:VKu3svf͎ n_ĺC)$K<{Fo,B^Q/̟ `:iKP^f+֧ܕ%Lx8Cw1eq $߾# 8z ([>T)HJu(w|7n[Μb8q"[6هpL'0g#,ì`$\ #EcJ؁u0WJU.E9pxBv-`ůn[zZ4Hs"~'Ρ-b?lHC1"dw^{5%[Vŗ ň&AEuJV!MTO0vY-Or!ָ`r&y 迄 '^ H:{Wa6vp#.^90Ncb9rGI0SNɰU8m!c2ۯ@#F)Zs׈:ᙳ(U:{`FLi*rfq#z`rUA"S­iu%|hrmˈq7Ԫ'9- K К (ƌBQ\sPPF̃^)Mm|ӹ.GBp}!;Wbh0<۸S e6[tӜ`*ܘ΁3Lь:в.iLm\ߖ2 0Q3$_4NŶZ/||ax홗 ƕu8J2F`똜\p۟".)u/K~ukΡm0<^npMl/x9k}MenF.iǣs>~ŚVۗQþd&=6M_@3Tv]_gu(;{*ҽJ>Ϳ!,2 ީ1n:›S [!_F1|ěT o>bmAm2}0ٖg?8KL֠R -8Ap<-uݞE`(!!k 8t)}ss!c;Q 2|ڍI¨qև &rJ)wKGwTV/j3&JKDD?3_}vk|&9ʹC锗)ɯSS3G^1Ts[2,իWMn}UN5?}R,~#~ 2c|Ѽ71/ަ~**'#ҪmO+""lݾ/ܷJO~&<3HN>%?ޝ-fښfHNKyfx+Eiv0YD0 l7/q=tIUDD31lߔ[Z' ? \sƍkOgƒ ا$QiItK ItK I Oy?FUDDDҵ… q)N}CSp!dQBDD5LѢEEDDD9""""""""n)p!""""""""""""""n)p!""""""""""""""n)p!""""""""""""""n9'$&&rDGGgs,+ DLDDDD5 \=|9g%ϱPN9CW#::ZA 1j#"""OZ\Ƚ 0SE@ׅ:+Vܕ^^=}җL3ޕ."OHz"݈Q&-XAƍe%"O 6DDD)SB!++Z dg)V(/_""""""")uʕ+---ʂpttQÆl՚_gMc^<#ɺܗ yB8Z4opttEfiˊg괘r}_dN^7VRj{/M ynDH}?)TZWKՒ\r߲"^Uh< *WqіP,Υ_ɵl8o,e9ȵG{yv]\\nC_r∋#$$+Wƾq_ڴo+}vj*_\)5edpeJwě=տ>'Tn'ekCDDDҏLVZM:ut]yٳgLԨDA)]|ػkbgƦ͛ OSZn>{v?'5r'zefh^Ϗň޴k\U\3b3s Ξ1ͨU16E7~Gv "E/ x/vf澵 Pd8v ҄ʕlܝiOu4Hu8z+!-b9|Tr`uK .̡C lo׫ӯ8n?Ĉ˨߸ jum|0 㾯a V:uZȔUSd4 ƍ б!5jSuo5elНfkT1o _ؤVV,Յ&ԀNCWg6"Y٫o3ylL@QL.[?064[jAuhw!'b .G9uo܀T^iKhЁO;F6|fYJ sypOէ8qt;4F@jcSg:|~ؖ`MTj 00~@s|K v1^ѳG'/uQzAl{M W\ MVJ+2zHŖ3k&Əg̙5-7o.FIX,^] A{TQ]]H*s2r?nqparTVBܶHgSbIu;K5lؼ9m]X֬]r+nvL݆['2#:C^qWj]~-漃a= Cn )SO?bU 摼fgט^LiO7vuuk.|1nǎرc|1n]t>[DDDSBcBf9p hѼ[7mdڔWvsIu6knHRla٩eo݊c!"wD@)G?IBaB\HceC+QN,[T5yioږʊ N&^R?_L&7 W,SI4-sl\ıF,5;8fw5Kؑ%ч:GquqJc~OUr c;X^_YJв]I,*[%;W7k:ÚɂWFTb0aͺpʷi˙̘\Q~IwlLrKK괪 fpHbp5f^{q,@֚+gf߰9rdN nOĿ/f:#WPӂϙm{2uYIJ Oo/K4eᤦd$^LieӅMa8 IDAT[/Dv|XSf7;M.2([YeIƘ߈ $?ktLFypU"gk{83u63M3s\3'.v|w|BBH(RD@ $TQ@Al\&kE@E^r *("HzFSAjBK B{6'OnM}?cz_s-,] P?; |oIvp.KAKZ'wB/r;t{ Ew ~^{|Dt؍4Dע९,vPt: ^9 V ^$=c#r_|b:V?3ƓA<jnSn_  9ݽX@sU%,lMJƥ-.ĉ.ZDDDD3pC8{_u%0AțCaԘ0} ݞ'UW"KfYz57oZ}5Qia&mFDLtGmT}wkL8(8S[ޘzV)X`c ʷ_~pS|2E`-\ygzJ0'eŗ^֧QIځZƅ,ZQsRc6n]t3Bŗ_FNЪUK֬Y6`]qc OQ0 $m|O؁3nU u݄'#",+pJIDzh=|>.DDDDDo|Y*@ .@|."[06oތuQ ?ZO#0>mA ""B޽pa@Np>`|_ $ӧQ>o`c,-pAyeV_L[rף޲G_S?DDDTX<;tߨQC-{7ǃSGCbb"vC^|pNʳǏUV2~|>L%&%f͚}Dk"X1GA\\LQv$1Ud@pAyDGkaʰQ9oLL/vI_E_k.2,** 5DxxL.("+GNSЮ];kNJII##7D-/ӧeʸpDFfpAy'&%pIII~("##@%""""(($j 5QYzu}~)\?_O{MDDDDDDTpAyֺukDy?]~w߉lYs(2%""""" 3˅ ;wbbFvz[\.1J2.(_zϙ;W{e4`^pAO=Qpo|y jzDDDDDDTP)_>c&^V Ϙ @XXADeơG~^  Cqp:w% oûo;wb79s0t9-{},[@&MЯo_18t8*R\LQp:5'v2E%NoNO?5瞟UWYjjL1NaQDDDeUJp.=]jBExj@ff&5 _/Y"fW_LSEb,\P{-k$̙X˰,K=˲0륗0f8={p]#kL""""""*MXzhh}haVY#foոAx7xޚ2nCxhh1J~8']wމƍc#55;F ;tףG%wdr2VX/}J*aѽ6J+.@ ?3^xKaFlظ. m۴AF8@bb"{nlٺ9J﫮¸Ơ^zDDDDDDTzpA~zxi ضmϘ6|xM|@:o>-[r,\Pkٲ%>>:/Ǧ[nDaaah߮-z쉞=zVZr ,\PU1x01x0,ɓ't(qqqE*Up8Dtt-^>1\2c!er|-Y>9ct\80yhz%WU*Mbbbpqƈ]ƍ͢Wcc૿i)DNh?#wHs3Km m~R:Q(pADVێMpx$zgeD]ՉJ7ڣ"ڹ (B^',peQt",}G\{#X8q5~nz+no+?c㶊hױ\V 6x-݅:3Ǵa݌ځx,$o=@Gxa]x<3tr'>~t"ִÛ WƮ5 VO~mMb3N[m!~]dn[ ٪ZMQ]0tvVpTBQ8 d ?j[C5odQc'R, -/ gfoŽ`SB'.H??l<Ivr8ɖGfsyP/7'ǹbX|ьs,5SpFnݪBD1op8](0wn7,w*ƠbRw㜳6ڤZ@E.@:C2q೗,. ~ΨDTr))~@lߩx7jޙ;=[=<olhu(]ꬄU#>UN+nH\5*faիXM""""R "**懿eQGq j#>6>Y)Aqp";u+/>ˢ]p>n7߱*۱i,ˉ]E?>K_)7Y$ځijў_د'N/x 2X'{NT&c}qXy̼CoqX_&Mwn7&'mQ82\5W$m'sI7>g N""""*X Y WC-ZޏWyѤG[@/aMau#IG$ ګơO~xpԸOθuХ{?|~)2~}G^8?/W +'݂ 3>-ȅ uڌp₁fte2}bb88/ћBB+qOcWkEu:k gƠ=u$_1 Qapnyv1X6۫wpi[6.Us06j\gdILLD\\ ߐ"C;FɐOǰg.4[nEe֟C:7QٴoA4 a&mFDLtGm΋Wy6=_]5Ɩ7K-cSe_y>.bႈ-.bႈ-.bႈ-. Cjj Qq:- aa2L%L9 ""*-jՌÉ8v"Y  C͚q2L% DDTj9NԮ]S[Ebႈ-.b EpsQQ28ʔ""""""*Eᜤğo}gnG K$""""""*,\Paݟš!RNX """"""PN.\9U" ;OW'csXyw2>hI) C9l0 m/<gNDDDDDD $ VOǽ/%KKn"Ll+t.xk=W`UGVa!&>`]eKW`ΈExMOޝ&!`Ś|lz ?53«Iڲذ5xr%VX#c6xjXLz')K?ĚcuX`}3M:O,\PߏGfѤYs4i ܃LuHtq%8hyS\s9V>QnG{S{?Uu\spG( zvk[8=^Uu nƲaߎVE(NCMyq3a6|(ZG7ꀤc7@E'PfwjeaDDDDDDDT<3.(Ocݫ!J 1) V܏n_hqUS-"guV˪9]N *\81Ɖ8[}oBF -RSaOh*#:ü#(KƪǮ.w:ܕ![pVE5;K(r{aDDDDDDT\pAqFzL{_cϳuOsށjU,xf9"r2e3[i)8u[x(W ի | RS SREM:e($&%RŊ2LE ɲ̄c5Nt>e;annQsǮdTos͉٘e[<֧gOu+^^ N<1hZ|_l:r-ѿo%<;j0̔ۑh޸<`M_;wbϟQHTT M.XpA9:^/8,a ~xc bzĬCpWC^`z.gx4}^{OQ.>.s*^`Tq:hڴ Q)yv1X6NC{֩ic՜krަU^8,Y|ߟa*'>7>$ aa 2LDDDDD$&ʣLX﫼[gz,m-oL}[6M2ˆ*BDDDDDDD DDDDDDDTlpADDDDDDD DDDDDDDTlpATFE?#"""""*J\QUmȭ 1"""""U Quepe-T`Ⴈ*tO SOfU-.bႈ-.bႈ-.bႈ-.bႈ-.bႈ-.*'Dk^?~PjU\X>ʗ//fQY*ۍ_}`-HOOϖ Cm1`{5p:PQY6੧]d'==k׭u0{ۘءFDDDDDDe T(zm0En_,<<͛5CZ/svڅG11r~DDDDDDTvpAn پqzp=޽QA 9sK.ko}v3q*3:\""""""*T.^hqM7b 0r- "\7t/Xx6ʂXD)Sɓ&!<<\eɓ&aԩO!9%%kQPױp2{s[g#[hh߾;VcѾ};B[DDDDDDe\uoi,\UҜ;wxyjSӉ ߇wQnM\Z>VJM7vmۢi&bF6ivmb-8}46mތ.]4""""*222sN!<<^x!d*6 IDAT /թpET@ƍާ)5ZP1mv_kBɛxl޲,\.vDuPfM >r{ _HϨ[Ր)*G=ѸQc5t/Z%B5/ɛ /cQpiԨQ3-V3Μ $Ejj*EFHK | Sb'.,yJ +)}-71cQ)aAy,XV0l~8.BySTd/DA տ.jVP]qJzΖ_gPA =' Bu+\ʅ˖},²e4`loTJfnQ*.p^?"<ʇf\:u`k^|;\urZP]ڻPN41J:// vRቋ`/h(yo̳ӐNrJ yvo|]#p䵶EDDDDŚ-o-,Z܃`zPE (OphxkL<{iiib4{8xaÆ8`EDDDDg{R( c'LQ.zn)D\.fxUl-;w9ع 6ou/x.K$"""B_~`y5Psݘ?>nݐЭvd7%xjWCť`r,䊲pQ]L)F!ҴI|~:x nyk֬FZZ֬Yyn+pa}st?O?~_xIiBѣ`"> >),݇G݊ )_E{[JӭUw_D*N oSqֳG|t(233pb,\] dr zuhժLQibQ$1f8@{a˿_mN =,[vÍwߋ[[Wuv 'ZL{2\; /i s!O, &NĶ1С}{_.!>]:wo?^}5ϠKOnŽ+y4ˮ nͫb( 4ߔ7PBpex:d drrEXX `т Tzz:Fy. M{FNc̻q'?n6a-~-  76.:mx}dm^ -bΥì3 iӦlyÁ{n7| 9Z|2FĂs !EBtϷ.\;gB}˖.KNB\l,tqc²Kأ ::ZJ% BogϞFxxfL\9z<|ASN P5"-O♛;;c:<7/e EC˛3ah߾=:'L͛q:m?pѢl,X .¦+p",r =]{%z\y=|k=LލDq_:$Nq=q׼C )a҈jQwy/>/9?富Mƕ܀]=g<s ,o3Lqx^Xf"7?+v9S\19VF 16V\_oï۷ax1rԨQCFDDDD+v<8z*U{ʹȓ-mf=\y4)7 o,8TW^Gcƞ=%ڵkg[䒦?rpEuߞhb,=|6\.|l׾ODrO?)p+XK|p,}|LT<~"w?ђ/1W?/0ϣסW;ۑ#T-y89rP9͗,\/3]p}lQ<1P0^}u_bgϞF#22 ӟ׹q:9*UmXI9cmidϏ&M'v.> "By "{\%0W+1%[ $߂-P>8Nk^=/@ÅpeVؒ;u` #"_/=. ƥUpThتMcidDqpN t䍱9s+O*_c0b]x7ѠA9s? W 九T% 8,nw<*.4}">y ӆNÄ4\X0+,4lx~7wڶmN )h׶~W\tQ?KO žēx28XiHYxm,Xx*.nn+7hYZgXq|#~f"3݅p[@l Εq ISnUu-w:FZffCX@s$BWΨi,穋,sBsL9/TN&'c͚5Xf k/;lXTV ^X;uFB|~Q`o7py^5 3g8<5e \NW[e;\r?кUIo߯ARpYewD]Lwj6mQPaď}჏?BΝԞh׶:0SLƻkNpKa`mR'>3 ߅6]+y'ʥdw:NƉup j4Z /@|0é%\1~9TglNť`Yg{ Gn~PyX'TΜ9̓s|0>[-}a? 0G)>7| ~]iG&"""Gv{q!L1/Ps{ᆽHN@z4o)pӽףS͇oLO530B fVr8ƛoyڶ)1桱P!m XuF5i5c@Xp%br"vm#\_r"'_Sn8{'y!ZU5),dڏ_8fٜ-y)gG $7s LA>qa!h",=}qWwky _a}S9W5;kXlB1aZ^~c8 +X{ (#^ wnvǔ1_mcE/2ť`嚩``bg㪯ozC5}ZLˉ{d,5&gsӧdrrx(t h۶ j\3gHb"lيUWcڵHNI6'J<øalq.11qqq2/=žd(֮]n]0~@ PV-YbeȲ,,\/}{E5@}ѿ_8%!zj4i}DW @hnx) } a z Ʋ)'.ISl!<"/ޗ OXKx'hm۴=w߅.;戈\X>._7 LY&#ge0ׯǤ'DDDD5/NLQRbk\3u2.@1`JA.Âhb"ț(,XcRc={ڶi1F}vq\蚐 شi3^xElٺpbo64k6i"$"""%֗A*4j1=(c̱"㔁BE7tdBXTԧ<عk +Z\.<4z4>;'_E }vp5޽0d0ܵK&"""R`s@~keB'1]L;/p y-ri\0lYԮ] |!kdN Ӊ{ |!j'dr2İ?,Ph}q}v 24GX1]TE꫼>'ۧ<8|0G)Z|8w.Zj)f^V-ܹѣ0t>|X$"""B--(|H=Dmo|B[ɸ̜p˘CU}56'ri 8t ..s}Ԯ-f jCa b VolykNjyW}mn}0 La.?~U`ҧ5k""*ཷg^zbV_{{6*T|E皵gYDDDDT2_r n<y횢leL"U & fwqOL~ y BbR}noH#Gx[G *d`!Z㦼1tr\h]b@VܡMq"WE7bjK1D\m8&ܹf=#*d(RRR{.rHԫWˇ-`$''GZjLQ!E / xt1Up@<ҩz-nUCX Yb:S˦8,A, *oN_,S[ٷu#[ Q>DEEqqi R 7k\O~kZWL$[.^h p~@YhB}XߪȸYOm[9Pdddnt%vĄ\ڭ#/JQ|ƅCuvT E!*nzEw7i}Ovkb_(p,/ˋn=L!""""""*U1}b2U_2Ŋ,\xv[Wc2 """"""*-V6NʾI|dB .>]qD٪}#~״/v^ɱ.d?3?,d}@WcySMS)smQq%ikLq},sFAV}9G1M1IyE8.CM},z;7's d_1XAIzHg\X|JvS7BK7ۇw7瑵O['0z8M , 4ϔcpULϓ z_=q7zLU OF @As9oMMAli1`剈@eS^[njki9SS9}<[ *v9sT_GK /D\S}KWb ɂy,j.nx* OQ(h"{aámb^ؐE5WmeLCԾj,ODDDDDTvbf5]}7^ jn9u,8^ۻU1=':9VⅢ0 /X}sTBYޜ>LV x*8:z=oSq57iň"m2oU3ŁSq=? zAO- A<7+pY`^DS^^45G^|<7Iϩ1dz~N3O&ց ɧ+d_L[;:$ؼi7= ă*2MeB'yq~Scxj+zL1].oY >6,1v#S & 0zLqz1XW6 hSUc d1CmM1IDDDDDD\IPmM1VTTa@﫦՚-,^1uyu55OQq_HV‚y.)dOS1}Yò^DbYJW#ӛ_YREsxcZ_=U_ʘ&DDDDDDŅ\Jzޮ-^0 ‚gxvzΕ 98lzSqEK>]< pXn,Ve_m-xnZYEr"[FޱoQMH }:M}EϙʼnJE^ԩ].dd&TL<aSy/*`Da.?Zlc}jrnV|˛6OB-nd=M?z…UO\O^9S9gUc9V"}]gZ7*r-)sQ*BBcj䅊ɢz-27ӷ>GyE"…BcUqbU[uu*۷9^pzgTdA/ZqVMLyS8Rk8)r(Uho:}SSy;2'NJ]< p!YȹV1Ǫ/cs#o^xg;ct:nuhyE:}551L1"""""LsLvU}=.r|A6t*6Ӌ,m\)Xʾ3 \Q.,Vs+o_pUxP7X}ul*,,o_.YdP9h}ulLOYVKrvQQ0i.טzS b>OmeNAd\[ԅ 3IDAT<9Neޟ ,\XȾPVc=Ǡurcj^ЋzQ@/`8IU䰼95G0d_QccʭWL؍;`׎rz*$B+soݚ&vsL1Ӹpa!wa|S yQZLƪ>GšŜ:* V7\#sȜeNdߜ@r3$0ȹjMsyrT̔3ͳ?GC#NJi.иPuBg!_ŀԁƒ*>9x z^7:}krvLyS4kAy՗[S3e_BϫYH)W$pa!kQMT^h:qu*NXZ_CBQcuя79i+}$7s\c7W1}*.S '/Xq5G[Bp;]\1-V |eLr [=Guvm4״ȗb]<1S3Se_sVMvX,VC˩炉A[Sd.o'y"""""FXn=.Ȝ33,dN)rS1}[luBſ\\ﯨ>OT^/os\!.c/_sNc_N\"""""$v9r4Oe.fWLq>i.P̔/4Z:݂\_d\-},z,rkrDDDDDD\ۍeș5ϧe_V18PQ?qx~W?Cy>*Ʀ~nצжɾ)f__4U<\9W}=(d_Vq| EiQ~ɼʾ"cR<Qih-@bi+c2(gcO9=7˕P/p_N1-M19ַz\Ms879S[ySNΓ@r;Y7- {nc5'2/z^Ms|sr%ԋ@m>7 {˸ɸ˸r+:SSe"""""}L9S 0/VqKe4G6P^*QXo>h^s11d\nM1Wtl7*T!"""""*.B81-e_ U,-&󲿿bjNPÇs慅 q5۪9͑cz40\ yMs8?<QiodY9})ܪ\qh3/s-yrPѷ\9΍KDDDDDTgq.S_1V㡚c>EMB5'h r3- gδ>y[)gׅ*8QabdNnKXd_nu'v̜5cu yoi>DDDDDDeQ^r/2nGV`ɱP JA.|9v0s r`.*bɭ.1M)9""""""o1m3M1\0trL9SL1͓}N0󂙓k ygW >&CDDDDDˮ: HPyֈ8ہ:=r W2K:WJz(_Ju\ʝٳR^]BD}~TЪp]GCtqZQY]z[l.9sl6ʵ.l)Li=GZa߳ F+򨷵ߪZV|D͕˦=fdK7[{g\g#|)z~ɕ!:SC뒡\FL>Myjȝ}lPEEo,ګkЪaRa;l{VY]GLT;\WQ_ju&>둻iOw׵:Rgl9ClPHKk=w/yzξ//%kV3VJ~~Au^Tk:eZ.%d{ |)힨>[[5z{ph/Elv'ۓ/Ԡ}o6heQ`jQ6de+CwWJ3CgW}ƕ+=>yqQʵJYת{ZR{3_ Cow;W>e4ܯf]=joWclth!2LvZ9gw +߳[=k6WJ.Sv=܌Vzz됻]+=s]5gg{7ū߶?c+BKKp<64팉~=>fy+oF*S لF΋ط-:nx>*lRzOB_YøLat$HA6B$M@$b_\޶n"iQ&t7$y 05ۙY ةt^޵&HCfbJ03]?qHE37kEƛ]5=0fuL00 T 0 Str38:}9AN0Kڷr;I֔0`*R7m<[7m-"*~umCM9?߅t# Y<2~zf>'_V({٫c72Ay ꭞ8viߓ$ cܹ۔.NIxejk?e$_U`괩&NJJJڲu|ޛw&B3OV1sMjG/_>+ɣ6r5߷):Ă >>>wclYuWz ه^9gu["J7үB/ƫGWr79 Cp):a W.HvcKF&b[tXXȡimH Ĭ;uѰct~.*|n /b'O^XfcGhn1nаmn |mesGc}ır&MaƤIII6n4qb!P!}!w9JJcW'qd֣cӜ, WS͆ra+s-2YF]Ft3V$n Yy rz*ν\B䬱2Eׂoe%X}܉]V$FVٳ9 xֲz6Zp+4-H`kis~ȥ$:Rk57`=W=ئ=iѹ s>H5+~vVjnS!TqS~)r,zKK˩SԎ©S;B4tQAz ׂT0@*ii[HIS U[(aHtǪА֨f ]\[sBݑljVaB< %be D^fZS[`Hm&^YDQj2 HWuM5a$ e A MAJOIHZL CV?(0 |2Ŕ)7l8edظʔ\wSB}%6ZqvZy\m-ݏtԵԕ:=̫7F n8:r~M:eoJB]Sk_zN* `RYK'MqnN&I* rk KRW}=jU?Ǣ2eҥ`8_B.(7l4o#$\ۧvY @ gU.Ƿu- =r9SȀ8ɐ8IÇⴺ˩3U92R@z7 ["nՓAT>%!>X,-,,8B58kpƬk]szIk /cgbRYZ^[:3BRif>Zݬ4#b񝿲r-OMZ5j;sq=1jn#5a@57h{cm 3Vl;pkڥM;Opg1jjMݼשCnjU&֡ 0 Cto){?6㣎aan2-!PcEH$>k"clmeSHWWWTk׮m@6! !BH o_ji"Pび!BHG˦~fVVp5f>BaeS?ii/ B!AނrYYz f 0*DOj<>٬Fرlnúǩ.++[vq!BN@D8:UظiqaCl]]= \UTB_ɧ V̞9F6efj(%ɓ4 6U-[p8\ B_7@@a),-<+555s3r !8|ۡ!/]ϼseP-***8"BO(K$nؼ1 B!1/YhB!_|'!H(ɆM<¹CB@QQ e3B!P|C0:'Okn߹#B!8|o!T.^eylB!P]-(׶v:T B!GnCâ%˖7 B5wݰ޽{!B>shZ$B!~ EH$\q ZJ %J6!BCC())Mz~kO~ϞhN6B1{T}kW BB5B̬lꇤ?O/B!̈́I !B!P&B!!BIahB!04D!BR"B!) B=x`b#Qz1bؽF-0wOs~{>Sxe H^ Ms'(X{:YK_IӸl= N޼}B;2dn}IC?~ r2 S$V6E_S;g?}"[<Tfg3ضlLU'zk ŻQZC=4Ԝ^DNj/b,[w/KS"o$<е>XB2N֦m9!Xpe[۸Qշb7T8n溻撔HrIkw%'ܘT/\pQyU;URJsX]evVñmtj#.}1%njʗlKw2$lB"vvo)8~ƚ;KE;/K!="/U2lKw_:O3#T;tX.DzsPW%%!<`ey"G󁾊'·[4Dxtf$U5e`w1'e+/ٔD̜ xl*믕MR/4R226 +2Cx gӄ,KvoS5#$/%-o>xHKz\:/)ݽ=ܤ˲KfkxbgŒ^w,-,x`HNekGZ3@~jH-wm>t~FW%Tfkwi5!6!x9(]t艄~}#O۶]w?Uoעe:~S۴e^.Ɛ@ @gESZ>N_/D8G c;c ܐMgqw_8ݍϸ}gM; *)ᙨލGV#ER&vv7,nk]4UVd.OOZ6M=߽ #ѧ]q. F?`S0j,>30hֹѹjlf: aiCo]Uэ41~{϶$Ei!j쿇{]GND3:ne܄/l^/HENL,#[U7TJ../Um:yrP6wh=+˼̌|y=J`:Ru`WU%媧M۞]t9Ҵwwfv:%CVq FPY mLU^ݿr.<&LU6vVԣc,TE]y`aD'%fF; -gV ոZ SRݳ z9w1TqR҄ETƽǥG6`({ħCg=y4]ѫVvkJʒҚzuW 6]z8 3^ѤB+J7*|> Ŵ@(BQY^TMh=S .[Gc_HAUL_S2=!舅B|t{! F$ B8J vk odѰ `q8սPIE* tfكҋq0_ro G m܄gig1:,|.*˕aGP$e[n HTTyL斢^}Ht}t7檨+e 0̙uA WS惰!Lڪmz#z[0lj, s qQ*ߊ L(&Z葐,{Iڝ),։B!\w5(2(Sk(]o`@|_Z"=%[3.נ I=Oy.aLEjKeLWA_G?z.n&K_6oXluYl`#xU<I-[.*uH 㶟#dq(h<{I7aS8t0PUjo.)ACIa-GoFC_Ȣ]Iz8]Bi@rv7}:*KJ&Y;YoJ.&U:`HޯV~OWe3^.Ie>{Iںu}vDЅ4h?eݲMc7ͩ 4tuXbW4ʖB?"w^k:dIi߻SS" shn3}1/"W+xK/ⴴkx1`ԡuZإ=`ĪmRx3lXUm]%2noD+wj^Dr _qn242qS=ǩ6^tVt׬ʼ{qK-jf1~vm+qQ-yz.lu7vUj%J*l7s(bG#!{r)B3*ڪ?+E -Gui߄+xXh:}l/Ev4qi~ZBU6C~߄kYe^QE:=۪(}]=`ZbO-|?b_h>ܣޥ۱.MȚwfK= w# m9zi~u<5')|5֍}{֖f o .aܒBY6kH&,*-d˙b~vUɳc6x/[܂gPo(gqRlhР6M(;W~sm\2NnP=FY+*tivR¤Y|E. sb`>Jv`'4ie\afZWYTe.gcͭ8 IDATvCKS'6OhzM‡{Kk6]@hrwt ;snɢJ>Z.z5}~#[KQr$&ttFTJlc /u\ȱ,Q;Q7klzA<M4bKl3/oUE:?@|ٳW#t+cCk5rfqnz# ,Cn?uX 1nTk^ c$⏥lI^v2ٻ5QOĩ).$V^#<"޲-Nv{v,^{3~XXnxO3tnM16̝Mj'N&{J8횽[J4Mg//tf}~r; _cotۄfSDZD"]xO!A J""#˖,0ȑ1v.Xo_y轞=IiѺljDgOv8{E<:. y[VϷu/u,MW Y|I㓿 /=fS{"PC_vA^+5DbG<<av"j'"gQl]o }}; C%AjXsq!StxYK#U2{ τ/oړ(T3פmrO@!H1׎gt "*(yH+o^;w\QoֶNDlm/܎&$04D"z! C>!5dSGz'tq?!B!B!!BIahB!04D!BR 寣@ϓ44Z5^+Pc Cïͯ B5B!04D!BR"B!) B!!BH CCB!$!B!!BIahB!04DI=;:vtʼtg&gdONnwt%SpmØNcSE7*c`U~pB$68V([)8è8$ +,)MJ1Ì+"w1&ڎ<@P^iiYn^lWRZZ&hѯM?b-W V`9;Dp6;9„zz4mP לe Vj-zL!6ʖ@Ɣ߹ϋlzqb,-znݴCt0KK]blc>~p?{miG)_eks&Nį>'Yi 7f6WuQ}F[4b#鋏o㖿unݲ>8Ll3 LaffY3+u$\2KR`D2s lYő-Z/:'ltR֧kk Tڸ{dVw,u51׏ >4~疧>fY )'_HLul+ɳ<4Ph2bNT.:eDӷw~F?Ǵ&i_jkaMxkcȦʌK0rLMvUIHm?n"8z];zE?6 UZw6|QPo3nA5<%]쓻oۥIϽ ӥ'Ϝ5*iP.S@mܿs3+e@9c;l0·30h?;;ٻvXR)8*^f8lʈgf -qy4HK{؍?`9>}z)z/0ީҖNp!U㺻w}OkM[/, 8>\}]X>:+hL@|wmώCk-b3Le*Vϡ) 4dKnɽ5=Ɖ[d;daЋţص/@ew}xQֽ6&Qrk5v[;;vp0ȃ7gn^ JhlΞnN}N$,۩S!Χˮ[еwrqt:lq*h٠*-pGN'mUBJ0aߌ!>NN:fIݵoN#Vљ~pw5~SL?8觮nΝ1"K06kNmѹ/>.vj#'@pjV*:CZ7HWu=LdigۤocZ8zNn 94F?'52hlj'xl_x dd'>dYLj:#=SU tv͋ h{7>^d^wk[5BS'}Vf /fՑ=7[z̠ͳg0]c}/v>{.3g<墑+ *?.l‘^oꜨkNw֑<跉ή>vС)c7p`F=&a`1_{"6)]1r"R =5 .UpB_p\X~KHomY䇇$45?=ܶ?i.;KTλYFpM/ON켐zHϿyrmͥ8 *A~pX,w)A4KIlɬ貖ͳ޻l&fCL;EN;1Ⱥl a7`ʮ)oKZI[Ǐ}ա1tٕUO]2Z⎄8nTIkxi(}|%]`nЭ鎮<(~WGm|ϲm/_/v_) =dg\Nns ]՗$mwϖlx-&3?x6<1cEG&ˤ>7gi{#}ȜUO;9d=7SۻNsLbZyw^]^4g-\1i[&lsdr?-hMQ|"}+& s;6_;dH>J5#.|tg5c$ LU/:H;1e+ԧbh-=n\g*7{>ΐAeSчU$l;n!WU"P)ya*\>_E|z{`Fm{u[3}RB]Sfѝ"H/B==κl&>MP8Έ+7u`Dm_=y,ºIoۄ_CO2o ߮"c&iyhkT̆;:1 ~{RH2mۮ ,a'Wjճ =i\x/sV*<_xPXؖLxA#^ٍh]>]ZcT%\W뵫_ >`yd֗7_f: `5tWJ=|"4UHR=%3+RײuqLUeyזyteo̐- 3h}_k$zkPFȠ+oW0% -+DU5KqLUUѡi/{Ǩv.췵7zk}Ņ4hz&).,㩫~ iJ ׼ҷx->./RKKO_)/AnhH SvDIJ`Tm\{ fZNc.\ImwI%hҩ)B3Ta ]CH)"jtW՜>B"8:W(9g\GGQxa{ͲvnWudQb]VXL9JO@jjtin^eV9ľEVScHy/ѪY$-kX=6ZY'M{Nn ضIeܡҤN݁`HΩASP3'ZZSԫـ..*U6Wj]_@' FRXB׌ҤYrkuBCRMCkjk2%E%TYAXNGOO8(MQIS: H$UԪ+"Yr湐\\"r]4wĒ#YzWJ@#H2`??ϴW,qm( *ʑgiJWUxc_XҬZu>]urusdj^ f* IOP51 {̌XsrGͷ$+t#ogko1<"cl 7[WoHlZpd&j#55&h,!t4+gW0N:r_`;oJI.\Zl{wN9ih.ZPZEsЖ@UV&Xrޭ@mdy"@ABph-9r `M6܌ZIESQq_kg*-`@.+Hhk[{zBͲP@<{k%{`ѫو;mj?f=ԫS Z:H25o_;"fJgR]]I@f*-)gHMm{CC3 M;m૫2y44N/)֪.(C:?7PPcjkss_J_ggjh,kYwD|hX9<9[L{.nҲvGpT]G޽V\>p*GXp60>l8iD:DN?c`CkUV~> T X f^U){HԁmS)t랛9BIiFғC/о;EPe)ǏŔ2@hyq}uj[*D[&ܜEx[ݨ_ΪVuQ^zYŀ03t\{oGeױΓi޳;ZGs'k}TH4ґmLЯYV]xTNSwҹ5y+HHЂO'XX5e̒yn1_beoki`PuoEG┓fUy5-OUXlE mu:auR^R)CݤR!5oXj4d٢9戕[z[;ՁO:71K8kp54^H2:eo|m%{7RZQ=k~ uk6=XL(Z_߶Za,kV-_7cF94r3ߊ͕uixf}kTVM7$bp*]-tֹZ襷sMNS\ K,_دSv%a;?>(3#T:v[:1%ՋrV;P;εJ*nڮٻ܅&B炵V s_-= @vkdsm|]A+hcr݃Zzz]zYw:o Hn.'TEYge:(LܼxC<^lNcmh%{8*X/ozw "P]O W0 ]DIUooޭB3)!Րx,3ɍۧ~A#ݪH 8%iM>:"#~ HfN7),|ht7˒u29s@{Uv4R4mԽ֫.=5- TˆoI''[:5ȆJvsQ~1f׃lLʦxF}g kD0aS_5&ZjHɰ1zfܲЋl"G7X}3F>~BHz?b}dhXmVE, Pc]'C2?9ӌ )u[3 H=ns^\^w}jZiԢewsNZXG傋g>nxb2Ss,yœYas$A&p~Dbڽ8+ j*`J/d%ڧl.y)pIU IDATP?6Jl6OXGiA$(45fmKsb~y%6͢P'u6:;2ݧ46V ޔ's'/"~Dr9?YB_v:tU_ DUҭ U\Lhk' djԄ$IJJ,h(Tt8SLPVoIIӲ ?ԓXHVo"B=j&jwfމ*?+42o\'#Y%W% U50/I S~Qeŕ̛"մT{_с_;Z"~Tv)CMFV3$ۉjuA}"F-(3´4h5^g/Dg] HnG[f x.`.* H]əd'Ɩ7I6a)7lco`0׹GL58yH=cF=+M}Z=><,.Kvn^=b^[zo![sszBAoQ">+ #-M3o͜t= G$-AadǤZ1osjnxsFTwcRYQ7Th${S`⢤W{WzN2H{[> fMњ#"MOHShqºYg#٤M11l̨Eau_ 2wh[~ ܯ()LQV'@HEɣǯQ@p>mpPY!>P޷4W[o ^qs|uGZY^/!vDȧDq@M:S,I|BvsTs{]ECSL¶ػ*6PXX"-v^[]nqkuwWkÃs3N5R>s__"8)c߆FTtv%a5U=PJԉzQxjF8LJq_ 2Ag'&KWA>yDjЮ ?ӂL4M55}e"WӍJSC2@ ʼ r)-.M C.GbB9%0̧V> fB44Rppx+3Udl$RáTN48ok!EFi]Jn eYtڕO3ѿrk^XK˟SBեRY֯K1^1>ifhaTQ2YPAtö[ʣ*+DC*ݤ`O^o)/$,AZ~磌^l=#W=q hhs;c9#!b5E*ޠ"O2bŠbBXZؒb.eΐ.idq"%7dф -w%!tr@@o0}vU1LBƣ?վӄGkgf%!-F 4|QMEx'\6PS:*eRՑ)k"#جk : yc X+3m>bK^'GDݟj@Uˇ)+衈%a0.6.% $%>M-JՐ&\U01!)/ Jy95%W2n=SWW Oy@c# ot|uE'Z8&LCe˚-,qE5eT#c#@F(/?V̦=3~h.Cl:ʁw Ɉ_U>*W—KU=c!+pDM 2u#rk"WXEGJ\Dq1dШLil;w ԕ0?9L qC5Z *4r L(uAڻ:3cvݜCnޤL~5+"eiL_8l;)O6$< f%^L&cweC?L8u~QQܘߍrz TқbɯrS"^_?@\ZDx'Y=@ʊCClGE<)aZԱy:2,u^M[>%'u(Í<ȳ2mmjdC=v̓".*_OX"Z;|AZI1U7ȳ* #G(.Փo/  p bXWtQyV+d,,z/OZ~Zk @RۣDKmy(ӎ;qȭ$s\ygHt |Q8# t)bܒ.hF$.S(4(,)B1HVzm|Oµ9&HL9"F`.^ !BYr8ш>JeJٲr0(+z!$Y 8FqW$!d%dܪYVE1bqV`'fEgX)|}TAɁoLxAL<doI]g~gj=L,,E]K \DJ!,s"ᬦ60(׫ϐ NA}KYEB@5 PCE}c CPX;L8!DA<$$`"mZ˷g]KJx0}CDCß >9\5 ɜ*wS3NexPBΨT\PF>θ~}<`D#G+|~{xfڲ@[xj@"C) IӃagW>I6W+-B"dz*b95zF&^艒Z_()+ h!:r||k0Ar@a=N5w^T]<6{ӋN5ܓќP^9V75:) I}uQu͘uhqX"bF44.<,EG)Pڪ9B7{VZ\U >-FėꐈWϖdm%Рfbm']Xw D<$f/Z;HE!jyEjc$!1XL8D\<$!a!Ws۰zCjH: wwPʌHRn]{ @pH׷BH \8eIB%T.؁@  *CT]`DlA&`>$A~0ޞ_ )eQExUVsnگBM}қk E| `Ȯ)$Z 3M?ٗ׶W~&>cʚ]Dm\ˆ`K64P﷢O^|M@rO|L}ZkHQV/+^[`/mwo<{ngWk] =~GV~=EЗBO~+qWթ#Z@6)!EQT>rB\MSdv Z:q?#1.!z6h5hѩPiUc_kGwnUݫQE!<1ܳά) __pKz/,Һw^fn~}|n~ [ Zv!8jgs֭Y_Ka?QO6i޸Crewu]Z5 v;xCqvж <6|qphMm}{uY7 Fҭ:5kԪˉ<1sA}5A(CI?wus@ KJ@EǶh[A8x){-{֥% @6M:}]WGUh^%|,NܭFSX\"O.|'m'98j?o7:7vtΞ=Wv˗̻U<a6 Ba&5-J(~> )Ɏ ?31gw 3ᤄ$4ctMVY^$ge"E$*s}RbXXn&0 c35ﮍhxҔ!1Eg0֊Z:ecJT/Nnr^H} .%9 8=@6Mgo1ۿyu:] Zo|H}g\EQ14.z)Tcico2, "aпS%Yg"nut(ȿ  =3,5E'1WSP|i .cW豙\˩|]J EQT.9&Ruw.2eߛ3$R9ʗ7|߹!}JXx¢QN =y(POut)FO {7Fizi^6cjr.NPH<W#e$`]ۈ EQʮP(ꇣACC(OV3~O߃XDhhHQ'JO,(Eg!Ņ`d=Rq[5T|9ҳOցӃuy{chBު}%?v bȢwST5=Jz~-nM Vo>||G7u'I`YѠZ]Ε_}f+5?u\b G׭qnx*:8f68سwY0ri_qI94oR0 @;ęNUַ#a;&myЖ7{FJ//kz  >WԽ>0EeBm8e&{_U;@Tny%#4.D1:**BHߠ:?&2}|XnkZo}jNxddN$c[:6"b8QǴj-@LEmTD2C I>}[T*c忷[VF}N w+yרj_*G-٨#?j,,O^ve411a Sw`yfa-lyZ׭c7m^ç#a IY˥$֯Q۽a9cMW. z}űU=͹mC kQowz]ҵ JK#â.Y+U1ԛ$\HvϽ(byq_YWcU~,}w\(M|tnض髩 )>u^=8bj .kc ?1mi懗ZfĽ2b;.k]E;Ѯ( {|W隣k"?'{tO޶B%~wm+L0k H>YXxc:#@b5Nm%;퍼UG636趡 ww¼?z(O6j^#=݊z%[7Yh?yN'fZ}&]q͡ kĠc :gxЬg7PݜMT1Xryj2 \F-niB -FYvر۷M]g[) 9C髢ϞW`:v{S÷!iZ8kVv$AQߨymvsm9sqƿs3@ .*~#azfNO\NjZ2.=ױ nIdeĽx:ZuRPxD=Yں\~*U X8zoX0?޽t|Ϡ#xx?. :V3uK.uer1I  Ynrl{ɥO0pG٧ `YWW +w]VזPA{%#.<4{!whJ-;ְbĥt_?CG5!n7^ܢK7S\;yþ.b|,jx*/n(G `ZBqV"Vgqձ(צh1Y~h\rcǎȻ1D8xd؆d4=ƪK3]5`#8%"&-h4K%ׯΑΔg.eEɝ/*ba6VYW0e`4Ÿ-ޜoprbiT-IILUSSv9kqIi'4fK1@a yUGӁ!Է[mW4EiάYp#Tf0t u:4my\ ŵaA6~Y֐X X[[ pb|ދt΃1WXdB$ÑHjr+`-IIW[4M!l9=S/a$N˼Ne2!`oFesGw{p,W|04|mޤ-&&+W^m۶]rUh;|MSexƞ<681xY.^ӻt9NK=Sao"JT |q+fnVã1&h,o{Vϭ5h^}Ցsom_h2;6.}b@GϟߩQ vnn: IG\~+5ݖjTSjƐ)Z֎8l_pKlز;ևhO9[!`8ݺ;-!䷡JҠ5ocz׹5&2Ѷʘ4ofuuӶ)`}Np-D+ ^og٬l&,RFN|u+zg׎GpƛCSzooXy%JwO_~v@f|zxgH?Dm] /W&0c-lsJ߾~glEQ׆`J5ȫ ̥=޹f(ᵻ):k"{s)QYwyNfO:{Ao71~wp16fn.]xmEg’V'Rْ}Q0?ǐ)O3[:EِܫAL` Y΋i,3Zrgng 0WY9K{L2:h vPac>ޢ0k<3ꍦ{Y 8}Ɠhfb-ǿ +(QFΚG!|/MJ'UTVWo%ݻiW"""ӧ=J+׮ר^=o*4[MQ!x\FVv+G [PM ^'yu)g69A9<2א[8px,˲,kY`|I 6(gׯ_ |]EttlZ7 !8=:*Mjf|QE}#Brׯw… |>m Y7sX5VTۢ~ῠ:7z;1*EQTA~ׯgϞP trpoCpޥYe;ExiǧԦU-9`JpppREHTYzZ=[b:Z?%Foήӽw]}2$6٫kj48b7+' p OOϘ (~FÎܽ{Sۦ49ǰ~rVcW4,(t϶ QюsCkt.m|7y&;!. 4mځB/*_347nt[(FCcO޼:(.!z6h5hѩЬtg mӽo^㨝==zūp^{a 'FaܾGN2ӯMݚoۨ71/ms-c:5k;bÝTBRZ2d5nzŬ瓎SЭOnMؼ-|=|v}*<3}Hณ+O[Ol\˳Mzvmk7roGo~2>6bY6o2Il*6sFEU!1E.=6'z=\;jj3\v\Ϩe# G}\n!l֢ܧs%ʋ>r}¥3X:`Ե vvu`e0N 5쥠m&>蕫gV5J۾pKlQo.ڣ9uxdd(o:;1uAuA/̄ JDya {._?E+//| Û˽fp.ڏ>yeW _K~~MQ6~?W  88sΚ9) B!7T㓠J]X˷Ȝ?~['AT}ԶB GOOŔ^f*zm#$-f| V}"ҽMC{}V<@uKF|nXF+Ѧ1!Az:<=q!4CîM$ xT&1Q XVm YL,|p9׼ -cvVv 0%}/׏M;ܳgOa+$cRbR!) g/j"9p)9ٕʜ1 +7gA89!YrKφ;MF%CMZZ3{ddS:룤EHS1X0 eLR1Ǻ ^1SugkuF3XvnB:mY O~*_ޥKG~*#oEQߞi_> q(IP0qώ$؊<歍yJlʰ8}Js<%>e? !䜷@ a״ι1-@3Ktncp`b3,[|r}>J e<2ϡFu}ٶ|gÿxD"^ڢEؼ (~X&d!0*5 mTͧ9&DTG|i{I)Q+&x{Q: O},c-t3ok^VeBr sr'2W:l^qw?-ױ2 lLf[ NL8NIX)<~9D-i0@vަk׮#o*EQԏg|U͚n ["h2oגN<TpJ';xs~u q}gshm$} _ЩM^F~~U SɌxGFiwQP.: wEnl™AEtdpʢhߠƾ>=&̙ߡK|H>r݊.Eҷ^=}J <"59/a=#.;@_${޾};| ""9ogsrrzMoʵ5Wϛ /iRDwZ9s(;u5mPn>GQEQEa(SN͛v7((ʡ_hxUREQE}mP((2А((DCC((* .w@ˉA)>/3>Yӥͼ[oy::EQTB6 CTlݲ҃Tpk7|\꙳fф_ڱqשۡ)]>*hk>O}'nZJoz,ePaJ(_ڲiQiXPбݳ6-4p~&.y>5ԥ/+M=[yCڝMh?`PC9~t<4oO]+$"gҰA>Ƹ;:}U[U7U+uG?vK5g.c '._;NcogUtk'm|| ֩#\;3b}{¶3WX՚*UjvY5B_UGtsn7^>Jv?_\HVûŏ'S% ۚ=gS;Uyt֟Q.P=_>cT{5+ -F/Z*ȬF>]mEYzb48⍇nWNU8 8TStsg+c{2oSFac6d%@̹Oy]tTJaHO10'/`x]#h|4Ƹuc:5lgϔpԮ>iu ky G_Z9]F;p9?L|DBι{)#Og%^ڿ}&}2\8Ʊ]4 kФ퀥Ws^0ftb˫+oR˿E%WL-{[j߼QV35>YѮɜ[;ջfj72?pkӸ. 1et$ԨF_8uco朎NٶYF-{Lw);k۶};5Rq!z[2yGݻx4mjv&OubgA )/Oo:Xqm0o~Tvb-9%!5449煊c?NPLN'ZU\8[7<o,;uiv_i$#9=a_ņn?}e{Ȕ IDATF938eu'\>iNǪ? qF}[8q=l8ʹ]>ѵssJhQ#\ԔT6]Kӛ4Myt kD`\+ي`mj)cHLTdX{t,84H9 YkI|E՛)/g@Pܣvɴwf LѪu)k:窎ao^HS*:&g#.zҡ ~ꑿdƜl.$ m=+CLtBaG<6 ȱI{o_O $Gśu Xܲy(;#ZDbaVP${7o7Ym+sma09:x˲^¢UV|~=/^7!7)XGoZVP~{10-WX${ZҼH,5RtHęվΗK.NpĊvy[\1Y0VY]X%B)0sW SM\JR& )bɩ*-b+qT[>]>fL ".zfX:aCR(#ς; KkE0<0CA.)>Ywoi+t"u.&yCCdnn`-,u859l Hlm#Qَ E"d@1BWFU?M7}h&\?{hx+W>}: OAOVh{GϹvÏcNrĂ7,YPC99#B厎l7ݲR08gzu;2:([kRuÉKa/.w`KEƓx5s8>.,=,du"fY9 +KfS^KmV?S߲@Bs[Лgǐg?4{F[I9>Yq nS=sˋVO @?^8%SZ8|{/rmUaZXYH6dB b#RS%` y}qu-D%kBoW z8Jesׄk {0cf['QcӰܣ}rX]"_7b_YIUjG:tÜmjZ~³I k*ڨQ)'z+Dځ9ò%}߽1低}JXxǫܸҦQmn?9L5ǎzUڈ^[_@2Rӈ] 6 갠ό84Ƭxfސ߶P@i) ,`sWC)YI{6\`~u\>b|~rDM}WIJ|-ktw{UʻN 7owEQ_h۲!qg/ߨ1No/gHx02M6._0k˝T=Qv{B9͓=8\ `xue,4~ZCZݦMGedf͚uRiݺuCBB222`Ν'NP20إ ǬMy>~l&ygCu䝞/Y? W0g֪n6EZx+Laϻc:1˰|SS hvc)Y8|NvG6#Fųw8sH]"ku]DE}5qfB (l ҋ vT,kA}pmXYEDڰW k6sHv>{9g&3$_9sゅM,+q.w@]]]Gd’~V_veKBY__:x {0mфvb:VjfGBf֭7>PB3XM:YN!AF3}SQSٵgJ_DܐuhWuTG _D}T6(//v6a>}N<9x`<!~ig;0E\6oܪ GT[p]su{#hFl9M!ӷ\z[:/5b,L8M:ONƑTs.z[L:\Ł'6w|'vuwPiN=>66#ʥ@d;B-pw>n!M^6scLͭ#;]yM̒#]llX\*.rnubGR)vFT)zspWw`k0hג'k=>UONrtQ OX8# ll7GK~ϼVnvɶ[۩scSQKE7⪯ \5wb~M (&J ^."r1lhؚ5zRWhe:r?$.SQװ޽+~AёE.[wQ|e#wƅq*:TnN f NSQ(y v-t凝SK֝uJtAw7Rbk$P*,Wc/nw{cl!ǐ-g{b{T*uzҘN+y*?ue[#5 [oz  ScKg(tA. M篅-4yYqK>֝/du2oUaE9sT> А+ @㜜 &TF@ZbaWoJ~%Ȗ#m06捻n>̹"A;XfgΏdCtνD mMi|;@tf,] {L rMZ OMLZL|\qwtL4'o]- }ߩ\㺩B!Cr*?8ϙjRUQEqy`y癪=c!n9@Ru/;R"JC[cWWT`}jM-`4%0vVFq)Nq1YuS 4"R-4+}}}9`Ȇ V.] gÆ !#$z5mt$[j).re.a^n h*?'thK-dkjV` aPPZʜbJTK2N-Z%d*V4%Ulpꐧi`q}ߞZ/>C=M;%#n9ozu`uܺۋ-8[XٍZr~'Ah.ZᘾkWP1w`lcvĕҵ`t M {=M%~Gs>&ƲGm\ycvkk(K^ڊs\y'U+VX![]c%׎Zc5@?h=zdPp러5OQQdVh(P$H飯!82d$b4~h/[*'"B~hxQuM5B!\B!~^CmmCɖ"B!Fľ}ʖ?~li p-CBzi(vvv۶mZ*cggg``P!Bj(PGG]vǡwFjAAAڵѩZB!d5h^^^im۶W,c^^^!B3 (v֭rL9111!!j}=$$$ܻ'Yή[nUB!P5P4??t]N]vvv~~~-B!PuV4;v, gg縸8Fsvv&9vXeB!TG +q|}}@ 35++K 6"\]]nj#n;n8٦!B .ܹs'vff˗5kSÄf͚]|933S\o߾sVmB!jNMM-mmm6=nܸ+Vܲe˪޿/ASRRZf "^~yMmTWWCFC===٢:8t~'AAA/_WeddHGj 0mر!%z5k߁Z:'?vIj^=_R}fbr`V OC{ד}mYUW4Jcǎ=zhBB~eo^__?!!ѣ B_qQQl*7-<ԦЗZolb=X*)CX27# L m3* si精ۡ4UVuֽ{w544zS.uV*i/B_IghXjW -;jJtnɫLf/;S#9n6N?`l_| S?@gPy1Ѣw?3{J?<Ә]8vSӯhJSNz{Thx mñGCWWWWWWofWX![B IRr38sXjŰ0PSS7DI_Ӟt| v}/ EQ[}ߟ yQsقʹu]gg YxtWUjf:>9vI&WGT,ʌ߻z{Bdӏ_e]-'od6 TVܞu1Jin#NV W]M3\~y{]ێG?X.ߨ״][G0H+ǟZ$T5pj.)9}M#@<&T{SN5PV9'7Er.r gͮO Z[W!M;n/v 7"^gwOJs9'z82jBZ9iNø'o/oc?} -'}W@r՘z:{/[zKA~剹qhNާ]^2 jêZp==kZEɱzRWlVϽ(|Vhp19]@B.HU+tAu*m,[2 F&w /G2=bC6ݶJ=hY'DGtO,z]<4ȿu:RcذFwoXMf nu\<5hk1gf&6n٘0_Ezi?Wm&Šoʅ |~3Q`2N + ln`h-ÚtA. M篅-4˓ jc+2nl=U^G!TG9'M(.z5]JhN!PӐ~PSWs7: '%wW^vv0a\tBc!n9@Ru/4qͰV, ; o/ t~|&C7'uE'F۪2`S'?+W7EC:k+)˕ SpMTnBSrn$jfiў^iVι+)&6ZP1j<*p?Z Z+|31.6P7c_ d:NGr Zk&O1]JpR5avre}-ܬtY@47TM׾^NTXU֮6~XΖ [iJ`!כv#I=g& !E4m5B*իiӧ$٪d+W6m޼os!PTPDT:pTE5OvmeNQ1%*%no'PջL@kkUeg2HOI`SyNcmICSG(*?'thcBcv4{(̢lhH-8"# kFӐ (!4;*I+W gYTru ̫LPԨ-_&]XPL4ҭ;chhIN2ti堰KCJOMAuزʳ^kK͔jz]˙V#/'_r 4Uu:/7&$Pbx. 2)hA]ɬ)I6H֓`hr%R*0 z¶ȸ|'LTͷ@uvT˃('n SNċQ~"з*,,ۧϲ%o۪W\8rm%C},x)׏,YxO{gO>*(?ږd{C("9Kvv]uH>6^?z;O}xR]o8U*)sUtjL(nՎu*r zY,4MZCQ2q<G8`AMP3U42  OϼqbLeWo.K uc8ۥyEΥ3^sxӐ<K0ofXxv,a4D **[Y78*Bnye5xھ-Qr k[tz|`q}ߞZ/> |o}l\Ҥlz(yA}NJgvzrS4T.B~ɶ?" 273wnAebϿ~SixcۙpMt0FojfGZ[;ڐgh_qw|(69lkT+"gn{q,ҡw,*O O|gu|wtH[sșX]6 ?Z0:xT&޹I 4 @uyd]Я kyw`Գl)FǸjɖ"~VD"P(޽O35%J{|zz>0O\3Z_{G̝;B;w[ld2 ? Rbtr 38!խ ^inmw"rz'BA@>>iRi5Kk0B!B5`̮se !$ B! !BH!B!hB!$0"B!G4>>t<:"~#}D5Rǯ?tSQ[!Bo#=6h۪ N]s|XFq uVR6]QhMo+B!TW?22:{_x0UA2Hn*|+ j !~w!GFCd2? m4,rMfq >aG6%X5q>C6Uw]f߅܊;=mc o (.og݉{(#~J?VGԢ1Mﭘz6vm wOLT]u6_ B! ڹy5an7~:u=2faZ$-{ވ!B? F%CjhHʶ$JDa4D!*u `?JQiNG/YA!B@!٨A? ]>~Cݣ!B!.H4FkI0z}GX(6A!B?֏]FBruO?2 \r>~e̎s0-S;h)0غ+g^v Wn'ۇ{;q@?;-RV;0"-j\2MrkRO-3Zw։+ё^q`XQbpm7ow765iO%p'8.\l+qw ^%>pyK7TjorA`Tl.3g}l⥭ lx}٫;|ܽ1\=}ӒS1g[ڲ;fN:T [5ϯ/zת߀N Uɦ\9KձQMgzu[]~uyǢ_V!~0 ^4Իa/;{0AP :!qܿ2zEm-|Pش-mB|FP֛MP)1)=zت&TJL۴d3X*MZ*:MhXwmDlY= 7P!AEm ?f\㺩B!Cr^[+ Һ+!-H}Eńf/p.[QUٜz8ӂotqp7b]X-^B=< @6xZ̄UVe(]VM4(f^yBſ>Ҳ{oyuԜ**(Vnܸ"౴ DlEI9٨]W@ r ٟWK*ÑjJ *K\ I(XrCY$P)0EQ PQW hb:$UZД+"[;>@pw3lqWcѯ !B5dL=ř)I`[M.E@8? cӶ{cK:hs<w33P^j{RM]u@@).}UJTVf6eIUN rHtLĢbSU- MMF/2@C U' ٸ{ϦFC$Kx_E./ !]FE+ |⩍.<&s-E/2 fH͚TLg"^Hz&zi?=}U7Se uix6Q2XX4J}ֶ$ɏ֬mfG+3lѧ⻴f&ZU;w:{ջq"!$( {;X:j!nLI~= e^lnԒ#k*,cwϮIy2+:3c6Orm0dƐRf' gOrtp#bhjzǢ_!V3Y}=eK5cƌi޼lB}=dzyM-E웢ݻw GيW\9rH-dB<O=IԻ^=_vt؆j@>xueddhhhٱl'88`6mT.]*[B?!]2{`ɩ#㚓t־}MkC6V?J_Dܐuhǒ@WFC`ƌK.e" ,D"ѐ!C._|u:a '~>;~@iؑ-,1"2u999egg}&N#e6$ I&PZZ*[B ͙b:9Pf7kyVL8aS';ۙ[:\HR>bADsǽ'K6 >|⎐C ]--m[HӅ׷wsCW^+\+Z|.g[8_̩SK֝uJtAw94%7wݟBsk=\d   1voXqOF^HIl&8 8m :ý>ϱcԱ;s#uF_\mrw@R(*7rO1vDt)F]̢σΗǩSI?:)'Rj;egCGaqqݻb DSFNmB}ɵ JTJLdJ:r@(9ɿ4^r@;ÎHq@  NUġHR0q aKyT ,wOZ ٍqi'ewLڎMS焉9a O#xx*0[ґj-F4aalMI|sE`w4Jzɐ) 0G{щ%4mMi{:B߬~s cccY,ڵkǍשS#G:99eee޽ߟɬnm۶6llB5T{mLPZvtJɦ㞑B$+y4*=/<^v%Q˄TqNnaR hG=44T$q8UV޽_B{|PJYXQDm?=yVԈ 3g qWŅ7@q<CJEC^ex%P4h[gB_}ֶyQ>-Z%d:4Mo;pIx>&B+ڵkW^ݬYp]]ݎ;>|xر/''R>%%},+,,̶M>… $IN:u͚5&Ms޸qԩcߛ: IDATSWmnn+[')[ 1-@#[A+QRD"P(Dާޛ4Aq5.vTZW6;{C~Imݲd0 CBH9 QկUWW7##cܹϞ=Ԕ΅"??ƌ!!!$IzyyYFYYY__\.wѢE4PPt7wυ!/ve֬YrrrnnnwZaiӦ?`xyy]VYYNUǎ{QZZszz"BZ e1{l$oߞCwp8!!! sݺul6FDD4jܼ}O6lسgϟ`0ƍݗAl1Xl!B}/5EEEe˖U{oQRRqy$La6]ZZr1cƸ]ti==`ҹs;v GB!]!ѹsiӦ)))P(tuJJJ<==ϝ;GǦMWXgH;y䈈h۶mHH˝;wѣG) =E!&_ *^f>>>iiiN2%((<<}sH>>'N#88XSSÇN>jVTT4cƌgϒ$)Gf2|>' @(1bݕwX166 j޼93fLDDM:t8~x=8ҥK> B}<Ќ /_\VV־}s!0 kk@|||NNNmj~YHdggeyyy>`@sNME'NC{mٲǏқ B_4|5tUCCCo߾,+;;TբK.[G]v/^O(رC&̙3-Z|rII?`0zB!Qh(^Yǫ&;w600044TSSYΝ۶m9a„} 6m_B1u1̬S7D۷o!B}I!<|0%%EC!!!5AjӦMvvvPPwʪ_n" ]]]S@!B ]\\455߿dɒtb7o ssÇjՊ$zu:3Lq.lܸl5B!-^ӳgɓ'ر#88811n8߽{ŋ;w?qqq)jI*=T&[B Xܲe˄Ba@@@jj*MqACCCCC5kV|I=ڴi#[B?Mh1Z:*:L/k'[vDj{Uʆ dkOBtK˳n%qA?~ѣ⩁!Ut!?C^ e[UO__͛z\ۛq>{kˢG9SWDʚ{L4f6'DS,ZS;ԉY$%#n[_P!0 ssN:;wP! j*&%l jV딒HCc.Y(NV+P <.yF6YMTbTHU2O<~P5P \tСCiӦ>xxxT?T9\4OxeP@2wTrR)aϞԂTjFg-+nj#EƗh(hA0700ϹŞԄQOÄLEָ5 4.|߳ ي;MɘT±-)쭦.h @nhCV5{F04f D)f4<]PĿ\RYLo4KE "^rfRŠiz,%W&8rsQN 76TO-@|ӔN%۲3Kw'uQL@ă4 rc* b0E7]o zᖾPt (Wܭ)BIFPd3AA#S(/_FK7KAW,^Г"dvCM1|(ih$zG9s={V ˏ;vaͿ۷o]]](֤B:BAHY{_ 1Gv<.VH D\ 1E!TWvy>5RZבgZ `3ygɵ|9ʪ΢ xAVA6 @7+yHUٗ EW˒Ei'5pS-VX҃pi%#@EqV\Xe\yBZU#ynѢ"ZEU(TYx#/̂SVrEm|<1HټdAbsiY@OU4Vfo7Qr*N/٬\}C! cE O@Y̪o9PK ]Ֆ>.]]tINN;w~uRRҤI.^ۮQRR"uQTTd0! Y y|rRRg(H9' ^8QHCbx{'oTі7.y}9jZDD:NܴTf( %ȣ@t-7J<2ˆ< a %䔲errBJY=UvL&Ŀʓ@y{J:2)S~.C' Xeŗ84 PWv*[~Vsf`Gs/\%/@m(2EP@[[F,aC@2QM|WG.e*hdd 8B!M)H6|&U[@$ ,!w_%/N}YPVhx֭3gI|||LMMfϞ:eʔdK! ccc]]]Rjb\lBd\A  4Yw=В'Mz&RH)4bѢGLP YjI>$$3 V(&FʓjB*bP*`P4]TDTT%n:7X|.P1Z5Ә2!GKΆSAt9[, )@GUaҹe BըMTo % i I Rn'$AfL8XZD뻭4GM rR(dPκjEEð0Ӿ}+WX,5,kذaQQQ>>>6muVRMe'JMB|*~*9PCU.#֠ySnWͤ@рQEL@*@0RK@T 5Etjטn|@Q>80J4!OjEYyD@Ei@E|J*T{(>U(^+2BL䈫Voh|zH3N[BDOBѯztM [[[99"n!_%Ah$j;?Z,fvdyM i)W! [)L$}Equq>3[XXz;vAlH+b{v^Qvlc%H}gc`fd|*}l{g2;SZ_X#a)&HWl^<St&SܷĘB$\_,:;IjKI $>4Ģ4CE[iy)%Lk(ˉЮ l5Z(Rʾ3%2m"PlKF8J?V=*7#JKP)tvѹlRsp _V-IB1<˿LHeL*|P]Z }!TͰ>%hو E$W@}/v7̃Y+ǹXH*b,̆ܙƵI42!q&_Mbt#MI)0! 1ԱͦZ!]DZN̟oa* (Ki[H۔>n$1 Y0{3yYLBR)XhJLZfўEy3jJQTP׿92Ȉϙ#km0Rem~ pQDgQW_| u$:GHk. y?dIxZCkuYn|;f~܂WviLDq1uLwqOiFQ.Zʳb7P"ߩSX^zRA۷oÇ666/_֫WO*uܙ=z֭...ϟ}l/^rV{D{fBl{<E) Ơ q9}ZE5v9t^k,ݽyXGR/E"H$b$G~Uz>>>7o~'O̽ȲOBPU-mI-J8HY]Yg^4tvv߿۷moBUD.HVF ]%:QW#OԋK.;|{iBExJXeTD}*V [8p5B!-Q;D"ѣuuu}!B諥eEQQQQw7Rշo_\. EQΝ+=@Æ 7l`jjٳc GͦM,--cccǎ .ɖ,YҵkײB!jjGÜymٲ%77B9**֭[[lٴiSe.R \^zojjѣ .%?sKKW^ť""<<!B0 + P*G8Q -ZBQu\\B:tѣGk֬)\,==իW߸qCpe 4WWիW'&& GEV~ڵo޼a"B}VNU'vF& cbbmFQT޽gΜٹsLSN޲eٳ{ٲZ>==c Jr#UB!T9M҆ժUkٲel5jT^ɓiiiB!@Y;w@-lllP$y{{>|8666==?! ~㦰B!뛘U|M PeUb !rrl-,!>1|K իwܹw獵 Zlya\nii)`&88˂gnn`==9s}'ɦOިQ#/_~-9R*N8A؁B!TQ/z{{o۶ӧAAAƍwį'##c͚5/_544u~ͭ[ p[9sW\$A`4D!$ϑ#G/_~ʕ|Jן4i҅ (AXYY9::1cbccU\vM1eMMMa!BChrʌ˗/@N#bر܌FOOoª*AL8QXE!BUkرcׯwrr"IG!B_d;L6rȣGB!Pf1 s?#//:dhh.JCB!ChvUV%'':u*22m͚5j.ʟY޵#dРAvvvpi*ʚ7o'JwL&[.o8B!*zѐիW/\$--(33'OٳXXY3fx왰TFFFpp0EQӦM{,}};ZZZ?~|޼yIDAAA`` o8B!*zݻk׮-..vss5kVϞ=333233]vM4IXY:::}􉌌TyoXC$I~~~OV9ȱggg77 K*zzzBR {wQ-,!ЗJhhaarJ3335FFFƍ}vhhѣG fDE|bXSSm'NT9E{t˖-?οQD"dF#'ˋv5%GfKFm ކ~ug#vE7)?H.^m|p\w?jT= cbbEvvviii\]"ԩS^JMM8Ar\XURaT 2LƱG) ,:y9VK8ˑIgzZuDƔBZbFg;yyOjڴ7usYZޮUp!3s/*Q/5uՕd"@U/Ԡ9B<#n,(+k9dPJE/U\W6&%5if&"D"i=?4ɺjk X3۹.s5LZ-uyٿ[ :'>ВS 6WOhhcctnzΝH!%&?ՑQ)յj=`An!gWu3" _ x~jȮˈ)?(|}&d3 ~asf@v?nh:q:G>O'j>_OR)g-O0w/5m{⌑Ƥ+\&4u0mVpe/"Ssn pkv?Nhs<ưYiF9Y{!;y%E/Xz/]dУMIcw1Gb_~}aA$_dv_ I4n+yW˽W\I5ļUhZ:0:U.mIJS}l*qZ􋃫@A#XhئNN*~L}ޟ45蝰a͉'5<l]v5;&lq0t6!ֶp{mzyN׮]%Ǐ7n(H$j׮~D BZ;T2NΒ+'C>5vUrIK6믫nۣAE 1/=蔳 "~X& g]H(3c/3pcZeF2ɇO<˅@X`g_ڳk1mDW߯ =kLS2q̾w"q;*XA⇐{Fٽ/]0ٷO\}o~u4JǑl4gzY5~{.얁/g36 RqE7NyuFeO'kz͚s&tjWr0GbC_:uTXX8{1c@!$p;&rxqIDAT tsrqE@47›čBP;i2 T"kyd.ҠK3-}>>!ޱF '{t DN}Fv7:᭧(724qmgtj1Ѕ_Ӥy̿Y {Ye}__sy6 @$?}&O!t?++i:IRn?<^yhԴ0N /¢LRX?x! F&V=fhh74unm[M> @&<|XȷE`Nuyj^aANc5{M Tm=k"IԴu'O Tހ0;;( ڻw󊋋|2A>ܼ` {iwWjihZ7ilOb68{c"n? &hyaa7j7ryHܩcg¯R.gUXR2nSշT1N3 xLٹn%Z.CG.;`Աӵdu8[lܠ=qS{YkqS.uΔ 9gZ̐E SR#:O3t]7 +GyTZM oVoi1wef&hhe5߇y2HIZOm-,oPTԭ[A:tرcc;񒃽 # " Oa#(JPP6^}a!B\oܴe%E"H$b(=.!UVNںuG>$b~ZZZm۶8pgȅ BkA7nb a!B}r B!&a4D!B%0"B B!P !BFCB!T!B!*!BhB!J`4D!B%0"!,!>?/6wJX/&%t_!aBѐθuroѣ߸cJ0i40h=h5D!AG>CWE.彫JtƽcڡcOo>vMBLƱڴh76Cn[oljt6k {HCAK_|~w_22^z.G1eޱo͘tȶQQ389y0-t3ƥ?xRB߿oFWI+Oτ{7{Es',_F5G#_9w0h|?'[I[+BYB.Ih ]U脳k18y}>ίL LTMjڥyvަd+ä^8uæ.25ڏޱg/vѫ&AhZ{ U.D}U? 4MQEQ ϯ5ܽ=?{5 35ݼ[j==tx={[W t^<[{wnǻS _=G=.>,Љ3_6Gv}|UtMztpukU> ֡}.~7Dg?EuԱ{ b_v:{my}&.2׽{%i碨bݕ}\6UTbaJ}]&=9ò~p|Ӧ7cs @3}1:-%01+}?Bh0R٩i V&%"LUSALwthE9snټtxqGo5=2ɼt:ʰ˺fR&'j)\i_o @ :{jH*SL;t,>8lҽ=ꋠ%VƫGl9KS&;@Sm$ /^U'?m>˚_6ff>Ń-3 :~ν(/5_g?OX9Omq 1 OʮGiM[I_0dW-M=7Knj};~޹޼ƽW0HCcHJ(=~6Xc/JMN+Y !*={q;&vL?ѷbn݌u37~?łpmRΝ}&[枞 DPp#,\uhZ$ݤog.G&>q)\qqq3X@q鑄v^).<H+A>6Z$Hwl&3sא6ao]a^\`ݐVF"5FN/#Ͼl' ^_=q1J|&߸nb^E?7i^鐠al#`(Y; Zo`2ӳCcÊ;uC Lnn>'u%C n Oo0cK§W VЅngN"S7ZTvoI[یMltHRH;zyJ1¨cO֟uJx1dFY4ܝV8{(9j ÞeDTvy#[6min.{it(goZ:+9%?D0ӅdM\֖ Y|z._sԬ+s|T1-ΣHwQA$"hf ԡ ad&,m33XJOɐhIS3&=5H LkV8.Dr-$I=]vAMj~;%::Lzj:JP!RP%n>~_xi<6 ;us u^m9'# 4\[u%?*kvNGWG̹oKC뒰cx6^&ko#:Ϥ~_1F`5+%u\DY\RA *(P2~~hݺiy aOGjѹy͵$@P_Vg}#wt,um͢vvxu#24444vg^: TMzzS&;;[0H=}ݼg*;+A<&F..BŻ7A)23hOTZTB4ka_sm_O4 ;9Vn۳ʠ˚;q[e{Q>V4U+:-[4>`GwôҪ1_XR!t~dwJ~ 9#lOAs] N"ςʑU޶ۏyR@ˍu#N:^pY}_=2)~iқM}7t[8TBeyeWװbh:tpH]t9>VDOFeGl]]Mu͘8t%ֽ[\sGǺ ]C7iZP_89G}oܬW6I"H, $I$}TΎ"ե{/VJ>#GAYf@$M+ !y)m% -J7L!TMu4$IZ))S瑒,˹8(06 eBMK `*z-Kb<hЧ$kYZS=Ӈ!B"wC,ٻw:doHQ[d._Db`cH$b5Sކ(L{ʫB!B >$Iٙ a7]}dcrPq =rE)N`4DU_iB.ѐ$I1c"эm ٴ"? V_r !B 3"gldwN\dd Bֆ!~\oYx%B |:E!BZ#xm \>m0 ß;ꂆʧ}pqOe(dEQa4DU;qdu!6d{h.zn_HзJ9qA5PȎ")" !$D2d+\[$qIxWdW2,"Qmp k'Y_g+h\C%Bf UB#RŽ}*m\/?q\?oH] BB)2(A* 8`B߶•>jPJ]lO]#{[\7LezSw*Y\ P~*BhBt?YBՙrc+\򞢏!B"N ʻ2D\3Bʆ_OWG!Jp!>s20,Jy[(G=6(0"5~<AJal>Feh*HUqFDUTW^WyuOQa4D!qx3S~(.` !NyNFV~ !B(C ?핗9B*@  Bte'*F{X>>FCzG9EP::!a"DUU^}!Ttنroy'eUFC B9* !uwy@J.IENDB`kraft-1.1/manual/images/nl/followup_2.png000066400000000000000000001546571450127457600204500ustar00rootroot00000000000000PNG  IHDR8 pHYs+ IDATx^uX ; @EnѵkX]u B@1s?2 {ݟ<<9sΙsԗKٳ!ѣE'B/B΃aa}%.aaG$AAI$ĕ2@2aa}!E!!(C4:јa((XLbaaJ(1} ғS.5SGߐmLcS1 0 JTg96Ϩ/ 3 $:N34Dªr >GEEE| xɮ0 0_ {ۖ:8XaKJMX1!}`Qc>&~=Oҷ qvR+ ! "rLL))00 0 1647cUZFF}zt?urzf{*!DGc}:N2A>FOb2QEQ΄Z'؄NN0fR1 0 ElZZPEYYzB5;7sDTl(nFO ygQSQMa[ (($fd39v3b{$=0 ðӣK. =#śoBt֟ף4e lٕ!}^ B̉4:=*4:9& h~nNl6QMnUBQTJЗW!ƌBj!a?L_Wc.^fSZz?}3&WVT@(Z4k<Ɣ ;Սv0 טlB %5p! X_mAQQ&=R15h%]ƌ2vPzm[()*>}K:-F e#;7>}ʗT rϜ|_^}_:-7D[oEƆVnJWPP=l`Ϯ22.\u}=Z6kZZVv/1#۴Ccx%/ ^ݻ 袧SXXtK| +G=x TUoXǞ;}K} p8n':u,rܺ۷mQl ,"Jzll-aPmsB"vFgez1t]ђF,ul- J _隩3|RƎDiŰre|.^s+**6167|r'*BةY99 /ɱTO?CΝ?PͿ]0lˇO!I)~Bvhz<.o͖]yzo,e f%ԼU>'U@p9&x&GEE-M8h?v%=3C:` *<^ݭ@f|>/Z-_Ҫ@ LLܡ` :;cmV/_1&VOuBEK#&V0S {}$aWV^ 9EBZ!yzAA^N758ENyekK(7>d`?fq>~ܸM&$~͛`gٹ݉3_yۧG$|Ǚ9lFy/ MMy3&Z[ ܟzɬP EEX ERԣkChk]sSޥ}Ҳn;VUU=c_u;E2W#C=N4of1}X3Sʧ޾=A!}=5oj_Pv)g,X4fNоH$](@5['gUIg.^MK;y讝m=tMs]ԋ"UUU;D?*+7zJdLg+*@f>ڭ{ =}rL\IcLuūn9۾So_zt/^x-{ANe!_]yg# $\r~&` Zl|랃7r>L4Ϟ6ԘᆄG;}Pw4ݎVwp8jKuT18n~9ԮGکZ;Ɲ7>``?F]]3dh_o?p?u/X`g3e¯NMϘi=ڬYh͖I)P·̥F֯yzJJAt|eUUM|囷z~_Z^Q9r]Qݽ'حm YGļMq wG>x$ȍ;nyP7'̟םDĹ? E=u}韜NQcOMڷq{WP@_ڲU{"cNu+dȲyff**99Qy& FzvM|bE{vLy-Et;vp%%SvmKk18]Y99~( edfx֧GW@7vO$=:L ޸gNn E"=A ;wyaFf@ LM@@]k4'7">DbOʐHcCC$Χ'7+wtuۏ\_O!޹O!EťW^:')̟ƬOHQWW0+*TUٙm[Zw|;$%f?|♚)UЁ.V|>{cӲ(*-+e[?m[;'𕿐}GO.O@{[E=U7,ObISOuP ØI5O}S&JFDQ|JoPUCR@_UqfWTPШ)ZM(ǻqda#%IHIK`Vi-Mg6ݻtG+Tu_2gr2+/]B:(+)]~Lm--j551IIKom93v8~\\ędۼ{TJGOn\<:.!>3|Se׽^!\ͧ _v?BEU%95{VGضn%lر4;y4$Wf5$* Pz8Yx#'B"B"v<:TLxmpcG3yF!@Xk}zY[6gټB( 𣙩I]I$Iy>?-=#.!qJ]BFjZ:urt@@dL~yyazսK`okӮMkߗoBv^ 012׫Ǜ@PIiiǧg&!}۳kg t 5fdf}2v0 [wS0r@ee%ü!C45I>x@UUUxT4Bu1#hk$ia!LEY!dkm I*먵#2PuL⒒fڧ0%%_}F,#+/]B5=@wxTPPPPPp8yQcG q-Yt!Ծ3:Ig&}iAaљK|cϢ1(,2Ɲ+,PVVB)WVR(JOWayݎGsdLtjȘҩ,j^+1D2^JUlTfa=*6Z! yKtH CFg?k'7E[v }<ziTJڢ93t>%oܾosM䔝TVVl $I2;'sr2½:~S 2:vC۽yݺC"u}ŢZYYKMˠ EF7oj1mʪܙWyܼKJ67g3&?z%:ۜ<^\RToܞ;} Eedeoܾ!#{$yB.]s1i|~k6 xhזҬ윗oڻ mίY;3ܾxݻxՏuo;%|_5lЂW^:XZZ(5`AzKZ2_rK܎>xg(.)pftL̜<^WGLͻ:@>=u[<>|lcex]J@ii٥kn[׭,(,z=MB¾Dڏk <ކ˥^xھՆ<=YwoX8& lBXIc<:SJKK3y~xЮ#dW9IAU KW 8 @r aW*[ԃaߧOn.zڴ]zwsrt9yk'`gom^LlߤROH@iYۈ TUUI$BA'ʱ4D6`zT[WO,Ҫ1@tAѰ@Y6*L[4,XDHՃa!a[C+Դ¢"55ՑCED1 m9oIK/m =V+--۾PZZV| =RO}2؉H*JOIGEUMEU3#`bJy0ŵj9**A!a1 vZ'~u£ݴxެV6 "*詳uϥ'=Ll޼Y},ȾIQTYYYfQͥO:3_GQTffbhm+"J(aaA8ڷZGGãb^ #+ OOr'=pe6F^&UOkA^Ng% iTa 0 0 P&b'>fOԚdЭ 70N0 0 @Qp1OvEKΨ1Mf"Nbaa߉\џI5:>[aaa~2H&+3)5I0 0 e!350QvI&zʆaa5b__gS찌=?ىaa7Y0b/ 6z  ˘ĻԨTN 0 0ј+їa?ٓZ0 0 ðƑb1I2 &]0 0 N(Q6Iϖ11 00 0 ða+z ȸGM 0aau%Qc&3eT0 0 L սG=dYaa82.z5T(.4 0 ðnXƞD T:0 0 ðFcb*#R&jV0 0 kvpU7bz@B`aa#Y1;_&``FeV 0 0dZR{Ԥ1 0 ðF ؓ?}JLI?caaDNЅGM*c;QEg̘a*@%5mWww,YZxɿ\).Zw]yA93fL30 ðȊ 4Wj@ f#r5}#T3kmo(=M68-*<#\ Tyflxx ؖ!|zs57E=2 (o5\TQJxxHO۷& 0T"( !*2!)CIN 5L{ԘP(PeV\8KDDb'[lw֏95h@jSA9< Ǟ#FR fQ}.G4g㮭홋/N==~%դe5T`){M/5fּzvs4yeW&4&I-Y wXxl$E wyJȩj4:h6|@/^q[M=:=+*uEvu [}u [rDQgZYJw߶J͜:) "=/TԱp1lo=~QJj;]w{Qy{/wi"EtlzjU[664"Ȓ3A"=+hn^xJu@[ϯzSm޾ݚWk}}KJI(sxɹPpgiHya,a\|J(~e \}d@$_SL!(O +$jRWZpT|=o:s! Tι% Yy?z>s-X33'r__N\HWkmV!K[ֈ;??wwomUWNTB)Ix޽M9i}s$UU=gVvb7а6;hό3JX{>S [BI]V{ׯ phM#:>۶t;n;,8{R+Nrq[GoR@(j CQd(%;=Shлw}b&$8= ,Q dO]Pi ]/E뫗ȑ,gˎBF JC.^~.Dr;?>OX+KIzWe{CՍscS"9nUSą_"<|!f,"um< S/wS{!gvp@_3/.Diا8_MX_1\i_ɥl2r߅j}m#C4zU{qM*D_1M89uك'L8ƈa<`.KxFxmfsH{[k+HӶm ȨHܬx| nC ) ۴"OJej4}b?* &Fje'2&`?g8]}ڀu;VE9NΰW8J $|3?NNhNz&^8fYFɯ(",Yu[]%5{dgY[T~uy9:Kd4nE%A>m.aX ;5>L-(" JlA[[#ٕ;c٧?} mm ȏTqAM͛scA'M6>TҬ]c~iou@Uɟ)h0GedR"of8M٥f1"f.#کİhgЋ܏6A#6̏8DAĻ1FoK(vףvNq‡Oy(mDTYPI<@ Nn'uG ff:J),$BɾO> TE;䢤 Qy9@I)U`̮\QJ~K d|K>#K$\Hh+o4XiFw*ª_NwmOPkniDš V{ז]^Β'DH$Aٶ2x eT0 j;ICV [kJp8d#TV7z8Ƞ.@L!d 8iP▙ÇLX}i\ DuQib@UE99EUPظg7&Mja%jnr22 JrkTPN!$ifdX}.7BtNQssS٥:dPcj^}@B\3Tvf WH QVf{]ICkk5, Q5K'X@/A[Ps@ B4I攅n陥0/"T|gp!ۡtoNV. -,T tuC@ji3@$FQ↯ _R//1k!zշba R$`7".OIBnډ<\MBQA ^{n;"J,BMckWJ(Zț|y%`j\n=H,#O:m훼mMA.;ٵ_{/|>O"RK'5eI}g@,zdoE]Q{^#ҠRWlTbS patS%"ZwY_ݻ,*rS}E8FY]IRZYՈSҋv-+KQJ4Ґ8 dT@֞+ =%EyIb5+0 !DЗ>IxExܱQ%)G붴tFRS[T%TU_ƁA@6UWP2& EJ%]-{X76եK>/R@juuqV@ں1CYud]m2Pnf:EGKc?N@*CzN]JOT c֨^q6ƜPRv_tJj~ U5yQ)ع[;yFiPsr`%T^\œ"^RF@to5 |#{owo:PԐa_گ*(3Vha* 98fH@"+kgX7"MmH@7V1꡶)@q]0=ߊPԯ {o%ֿ2m,8?/էPQw`BC N[&}XZ:*n=LbQEFz> IP-BB8N$Pp,t' -U(Bű myP>nެp6n#*z*zAA8!֚OU+"BYE š վT0 þOC+Ovj)ߎܵBY9NV: e^bRH3#JzvnMr4|0ҊFv4S|xoڍc }ɝBK'v6BY`2W1qlKM(Lzyӗ{lw~RPQ^@wDpF64ݕoK#ιd%gyFtQ'lzJ+Tv5>:Wʎ#G0|u'!.8}i![Hiܲk{2VW4MzOڼgMfmۘrul-ĵ؞mkMRǚB[K|e&vG-X9G gr7Pru[tJM%l<zԾf:*|OYeJjW?ofԲ˘U8+HoW{[S= 0 d]ĪU(BQEbaX ]K# /}XHf }:2Q:{;B]ca5Lݻ־p5D{57pAjv+V1 0 nј*"-\Z}X|jVa9Smbӡ߸㻘~aaLuϢ54Pd;YUUՏ Tc I jZt0wrTc= *1 0 ðB~ҳO}baa<aapaaaaO jaa?)aa~@Mzkz.'ghrezUWרF?Y=7J:@=Sncy73ֹ:h;tzM5?T*”}4񍔷^Q_Y]J}Z6* uL>}\z?\ERdaK|W4:}M~X D jjo+~շDK۫R=ZjPxrSx9 Ӹz7ԯO5"*ivz~ևamj٣{ݦ<87ܓMA #[ۖON\ݹzΩ=NjԆ3SWϒW>I! +cgAh >2]@w4 l{tiBp{7>ׄ.~|J`ND=}X)4л jZlUk{ >yuGrhvgԨlqI=[t컙IsޝnPHykmy8CR*yz#K2ߜ;tEn1dV['?e F*xiGf|ԚfɐJu|fsw羶#r$ ?:LvbR형f:i*T~]nFMqdvU_80P cŐgX:ƿ\&9Lq]Nw⨓&NʤN)gT(69k͊и+UR PѲ`&&wD8t;$J缍+G[7X($SPY#++:bvw#^of>ŐryΔW}S;0䡳ɱiWfH0uυeu7 @S^emM 9W"E:ź^pIs!<ƑjV]WzCgc I ڡc_劔{-;HN:!N8}i£RnA ;6fz IDATay漻 86aq̻:_m@.{ 8vRPma"IN$ޱXkNl WnӞ~ٝ_avw<ĉ'ZAU#7x}@φ P.n{>pm_/I }r;>G_#j(kϺSϟ)7>_Ur}1m6\|鶽k1ף@e[/?םSZ}.TnX-7y}dW6kQBiFV++Vv<E!xwيO?lmy{_PGީ5:g2n}*_)JO\|/Dw吷ႳOm\gN2s*sA}4[{s^6rx቉MYKkF;2-F275Po2cp! z\T@ @zt|@ɕ7cXK]+zk>xӬ9wD {O/ڴ= }-mNGR{?N[^.ʊa~vUtҟ<|G^^}e ON|h;OO^_st^e4HQSWQaNyD#D%/Ni-{Ԡyu ome9S6#sIr<ڳ;X?J$u]_3.j ԻmRY[VO4]w;cL]u>&**5-S$@,,K-(.-H*04Cgo]c;nxFGtE$kWo c'8FL3y=͔9|5#sCejEuݧLpf=j/*Ex=/1c"GALO]Y&}G4^IȁJlٵAVZXNO6Hc=FeqvndeܮJj{m;tk(VjRUxUS<{?HRwCYNu<4cj\قhfmjjld~;4!!NwN]g/(|Û .5Aj ξzSHc v?t{|,* )1EmҾ9 N>^ΌkH7Kpl[xSS%fu6ȶjmǏ {[ _\t[@S"+Zdҷ^1驅,k$m ]r{qe%yYbٳMaەYSGZluóRXbYifv"*[$GR@;9e$ 4ʊ&[P$ml@YXRH"VQ?bV"Vפ륵Jh)R.\`\A4F(wovyeO<10E<e"?4ms[@?B~V̬+cÎ+ ]Х84;6,[087IntA1[rlw'mه8[aPڊrJ^`)TVms h1s fܲeZŦM %4(Hk .ep)o[eG%/?{N=G@A^֚%sTKfs9|Ns-,lagaJh:j MaAX:6ٳاR76H_zR/[OYR4ҒOZ+A^N>k舣7lzQB3TAYUU~8W6v"g,-ՂJxyZͱ<Ω8BzSDV’9?Wk4*'Eo@Lbfh%`ToǶn~ȈA˧hss^],mb~?Jڄ|bfx؋ӗf726'8w @$gsJLֺ$|HUuiԗdf!TAi%*&N=z_}fm9Pr"E50570}g3#vakn +!U䁙enќRmyDzZ\$(|YLE-VqҦݯ{ho<KψG6 YU#cytKkANZj0(35kmŧh,'#K5K[aHlws 2uoop\F7>}<%_ʳOeZ qH)МĩңV uQK]YRՏX@vA%PA^ޮ L$J6 *հ$[fgJB叟cA(ګ>:KMk dЫ?QNE~1WNY}tSzNJQY*-k~74жm=h7#;k3mC5Y[ Uh酢4eRhƠ>l^n>*ye(m,}i6ZV.)(YvI #McӆaMl9E VqƵ\8.m޴rr@'ӵ?-6Mܵ|3&K1ۺʝ뮥`,$dYz,1wmΔa7_^T׿IaҸGߔ`_}S7,ʖrX@o<6Q? d|-AС˻1.|| M ԛ RBg XyYG^Y5P(! Vr{ӎ-[`RpJxm]pdI/M9ؾv.`isCsonmF0bUB 4<@qjB{[\ ^g/.x !Y\Κ4 h|'y, i˷h$XS%7nH5|f-n(Pٱu4oٽB:OPi`9lwg 8bc'-ӵϏC6mfS-{2!<8bʩlmzOvj7bk@['t .}cײy~WsHw.QmU){!.+ϯݠ?>4~HGŎ0` tReK# .x}/擬r 8Vͽ7j+˲53EOЦF_@O&.#GЖ7|؜ Om_~5~#p\1Ɣ!.MY)7=Y50qLmU=kH_ɺ!!>RЕo[>9܆6pi[ۣw[ڬҦ̘,ia^s5B=.:2ik{rL?9-7gUQr\{?>Sχycާ.W(ͭګfԨp}{9}r`QzB"2? *[K:>mɎmZuIֿ: Ak]P~8fMyݨ=? \#cvW'ZoU;gqbDyޣzAz^Uڥʜ┸1R޳9j1ܹp&1]kJ捸z{ejWkL|rYZuk:Iܩ?<`n)P0dl,w|lf{Vv&7Xh`YEj闣X IJx; ߷#Ϩo|>ia(bF5MEݽuRbEhʣJV"H}שݥqkw]Ic Ir u 9c mjŇķGsMj7W7(  R$P# J}m~c XpGNT@д^;̹*W  # f1" ;8 ym64%Y4 ӏn> zTr͐&6n]vwĬbƢk{d/1ؘFFr$lXzLG+V[Yv!kaw~޿JʯgL@_£JPçYP8?ySīܤӸIZ8wFyL=;e5 }"ƪN_FaRnuZH% >ܔ~ X|~ig9!7>w̞߬߈MOJ)knmĺ韗٦QWp I!3JNUTw˧h.aS3շe(.W՞Ňm̜5|/#~>F8֊7({Fw.L(+}M[_ ,[Gڟ6T&YxwҦ/]b~7͹Ϣ.DP'n]/SØ~+/AtVgO(416椀m$vׁuc{h;ϥX|tT@u 4,91&',$kD.?/:XTvM8㻅9w@<1ccQ"‚tqr>$m|Ztt&_MqV6nY綳cGK Zzh؞C_zmoƱW]6zو.A!#}Q8ؐ;147 bI2`_0a}c:FD T=+<#$bA:N(:3ݟ1`pnC<=/2O;58i&Ύl]ˆo̳nH+w?an0ugBu{d>R{k6a=ǯ*Z(Jkϲ|f%,zzpɔy~հ#t jYU:^5оaN<ȦE.5$F5;^ϊKfՃ\K޾ Z ۉOSF6ZNUg 8uTwA@2MqnI߃ʓs?@YGE陸dfm2Ϟ}`wCj)?ii;D3ͲqKoja87zLϝ>3uoRo }g]3w*r`_nO;w诎cg€R6a?1PS[ nn]Q *b9}r}7Ȥ! .=tQN7l" 5tԡ)'WscLv\78GWXQ΋>muzm O)g5/>߶8~Sv-Eد4]o;wRΝ٭τG˲>f.=ŒS=@hV'c]ZTrR;̻898Q`'w\A=݅ ; Ŗh-(6yHpg2q ^]wPMr9Q~-`,u܌OWϼjsPS#LB~`l6黎״pLm+[n IDATmҾ9 N>^ΌkH7Kpl[xSS%q'Nr%"q֥YJPPgSl[և䷆< \>}K cX3R/Zq=&wݞFŹj6]OąU)0[Z7RQFP$DεX8ocS6v6rs^>녡"v(3rFf!3qU@"92 "Jd)CaTAad1WOrRDo(z 6wt,g@`Z U+(W T$˞m 1u ˤRք>Z R=D.DCmΑ_5oMJ4ߜ}VӡK{)3)\\\,MT2/Te_z#}k5&ջR| H Aćm۠Q.*}07#,0Q(3#ߢnFގpJjϒZ LZ[i|` 5Y,҄#TW|`,mD2 ӳMXӍihM_оAE̗GW yjR5Thѿ_U[#գ,p3U+'J|}qh( tQBKa:Zk/WzWD"i # œ{$ Y$H>Ľ]A;_& [Kk h[gӣ/߰P%-iP=v¹?8G'L6yЦң"% ۯo`jwxӔ?O)%īΉD*ݿA 7[p Y}.ӻms S7,ʖrX@o<6~("־Ouo#b}lnv/o5p^οod>`j0o!cP/q3IRlETb+~x/Yr }mÏ^v VyBl0- ,lCZ<~X  ~ (A/͙KIB^)3vsH.nٶi_#T4YZA9VOO|Ncqxwn߾s~7nݢ9OvLr^%RTZTmWrj7Xyo|kZϞhJҢb9{gWNs@=bT*-){_;U~ }5޶U~ %ظ4 qmk.CVdRHw.]M%W{mм)QL k _s2]-e?^^80t>-plѤ>'A{:8sd;۹Glv:sV¥N)3=L:>+omg*LC'.Tj@X'n!#Lܰxр7cwꖺSYU=ڦu۲{UE] ~U[{_+֮Y=bĬ"Zּݬ=[U<жI.ix6ێ]ˡ^禍͎/oΓ\9jt_5p48BKe@rS54/& ˯%`bx謞s6ô*[F%I̞gf*2UmmSoR-S ؄A;PGA&$a1miV6V\ E5kKީOHhi MJ5͈#7_6a㠑OzlFů柽M6Σ#v °׏gFo$e-ƒB%qܴؼ_`s&2IrrFjrHΓ )Yڵ퇞WWύ05z OۼV&Ȟ\sF$J# >=NZz*댪f<.BUbԩ \ `dl!bG筛#G4צNi]ȍD_/zCMqk ڰG7  > R(0:0BG1CрO*xD'é7bqE;1L7  [qwudyG  7%rEVqzq^a1feyy  X4fOJ\;  $!D35qvD*ޕ(٭)BlT  3 _$ J@  +E5     R$P# J@  +M _% t >=H; ]CA@S< ; I ť_IwA@?$G* M1ƺ0#D"M% B!1fY~)_,bYJ2o @4äA|!GcҝF|Rm ` $P#>5A_ S0irB AėAL>B AėBLzԈB ABңF|Rm o-P9GF j{uT7C5NL0yoEU&kbR^F)}hȞ7}~Rm o-Py^U@sNYw3c-=Ӳ\@f(3;}ԸV[~]5~ֳ7i"*NMp!Sw18/Ù+vO+>oиalۄ Yz0p:3s^+V*hv[` w=jȂ]- G^w:ZQ²k=~?Nc.`ӷ+ ä7fuywTп sq_L\sAE!{pѭ+m|˅ MːyoUG9RԹSI 뮞UˆyQ2UpӋQ=G6gIצ9Q'S8>u%z16ѠM{Uzh.~i~5^D6m*mumF>%jwƭm.3Qqzyr)/-D{ 2.cH|֍O崅e-{5rɽE6lڤʽ7j0r\L-y3]kS{,B=v8(~{:Ϙ:URva XO^kNwzƭJwy ; 3){79S;VWm aB yALw\A=݅ ; Ŗ"lt^ƪɲKQْc.(2aC+iRȀ|_˒*m٢ zQ9)*T&HVC {θGoJ0M)YWU ejbaCFc')6C( _ZHc9|@y"+>W5 %C4YPyf&5ض5'~gUۥCQ[KS jMG L9beun֬wHѫz;ݙ=}CοEI t}[ۼCۆNו94S_CyUe޲w_+ƒ#.m˥S% |zjvkfQЀKLpG.Xɢ~l+8ekE+;Tƞzc_ _hZE ݼ,.^/kUkhxlor#YAr*7i\rmǣ|#uL:y]F%o^`,9oLx9;0̨ܤW2 ƶ% =z6RojCK0ʾͣbJ0fYv-/{%21[,A3ڵᑻr%̯ħ0.|eѣeUs Emsn PS!)Ӻͬߞ@b,K 60 ޕ~[:zw+FD. WNwFefY\{uըK֮.cU<3^9S([ v(+[ftǐچG袨;81oWmiU&>rUsHzo[ Kh^mv 2έv6&;l|W;$Dï^g3=鳘_6ǞM.6ӤO<\|ϹMG ܻigrG'.'TL%빱U]Խghdb5bwn0 M4M+_0 CQ&ij1& ^,˲la@}~?1'aڈtR]*%;T`4]4e¨{B*u} _gznhV8.'F@b5 ǜkY:8ݿ2se gjT㿙ǽM%><:_7jڿ&b(\D%}iB}᫻#0@kiW MYʇeAħ¡u+ߦbua0yz56*w<̌mnv~G7 ݀Lo HzY "_7es)o HFNYX;cXبE@2Eq$PNhךU 1V wjͨxvͰ&((("eITU.A5Ai@[`LG껿U/0ƀ&EF<Xvc I;\SI'"i& (H&c1M/- mA ԾpJB'JWIͬ@z>x7ƌqq1(!D4(_hb2A|&$P&iwttzmʟB*ѱvNxYIIj֨(`pmA ԾL/rkkOwx뗉cJJ} >+3e(q IDATZoԏ/'HHc̣fAcdd1FaYU]7д,r8j 1i25#) @ G7tlMS,U9 $A Ծa aR@x!M(c_Aj<c+[Uui;]4d~KA|$PVo 5GxZdUBA|0}4M#Vt`5ңQ|߸^>3.Iu'~6aM&d'M]RSvjU< 3 ڷRM՝&=7^Jt'|ZҸ}x&?zG \<6TkΰoЧm.ȵV'MJIAG"ڷ+{M*oͧQx}_E=}>J_{g_:a$+j5oF1\.S.{v%/[ywdzvli3gp bn>-O% މj$OZQT]uZךd)N<>oHoSw{'q{fm۲a& =yF@q~s߫i3S<\粮Ήhv|7׎̫MXռ_;sP3/톯!Qn"ґ]|7jaΕ9ৰV^-CzvyziѷE3Ov>P|oq]ծu/G5{sάڐEÂ\x׀6^ U$[00̧I36ЬS_{عGG5ILo5I'AħBԴcu<;ioyc:v]{]8W:tc&TePi#wR6\zXz0 (;'x7zmwAuMZL<|>`stv+dL̹ums76e5xK[QkU#g_ik1L~/r o-{o\Xb^oªԠv! >9}t:3[SCwieA[z3N.2ػቜmyPtX4/bxV\u5'+g?tracռkMl k֥FdPKX0>nF;z{H2cz eS5[N$68"*Wvħؿxջtny>JؗQ'^z(ûVrPQyRsKQDZ(@^N2emڍ_U jt\*q/؆@7?s=SS^u|?$A=onKFiR}h}GIF'7YZ1ϒZ=N(+3ڞ~+dLB Phebck[38{A #JPW|k+ZhX $Y~%{Y˓/)o3C2o'EPvog^cgo%Y"U#/s& $,D2GgGqNv.ekotC[X0\ <ڮ4uIST?'~KJ5AHoUTڪjɿ্;(aOS]iK$=SՁm&0YY3S"+Kcwn f[iPrɆS^ra_z~=;- fa0ROXY[uTO=TeჴB B شtP1g#Xu=f}{>Y妓e@Ѫ)3*szoJkWA{2Ԁ*( caΊũ]F+7¾sY@oeg$F^!>yWx+MMxOEXT4T[JX`o|ݦ-(sJ.d;1N(?4K)˲_`9?Op3V~Hx|ThFM}h\֋;"ES}|Y\L%ov]&vpX#.ezFy=׸ŝwcCD@N⮭4hC20n8lo ݯgƭ-'k6K5ovae;23x,1i>]&/ ^yFysh8Cf~g{wii ;[T)AħEM:9βB,jR4,n{b>92: OP+۠^O&եHUиM}}R ;?+"n)U]lʵS540VET(,b,ӄ+]'??bt3Z$QE7n޲0 E p8Z((J9B2IQ|>0ʫ0Eii?Ʃ󾘘G6Nܘ;h̶h/oC°Nq+G9$Vdz?oMĿ߬fA_AOQ94עJvc=]}6ta[+tr΂m7^fsN͍`ߏaq˧/m}*4ȯza<'g"bũimJ欉Jà $cN?ؒ$c}Wg)L+Wg3.5.lܲn;4hiУyҞCwӊkbÒΘ5V.~&lWz㡂˛ef>6ʛ}&x 㻞11{q?+$&9Odw >G ʼi89eU#pܝGOGblu4'-ruTn4vөc[go=bp؆QQ69hqjSן٣kn]V.ҏ͘xss'F OM @G(©-7`;@3h͑1G& YUu3grd)o0']- LY>qC;/[EE+/;/ijаqo|GN=o_% *+4F (M=@ 4k,({;PBNΦwzjNw3ܔ2w}W.6ޯ%E)Wq`LnE%!u]CkZp8Ε-*B6i͜c'/g5%8-]婩}z h8,S%ٻ(6 ,wF"A*{$?[4[b-j[ {î Q齳3RX;=w;gN%-kVU7 C{S;O@ C;R Chbg>YbBIwnz2<.嘌Y]:Y XsSV rzFƊFe(fv$'&11HMLiR YU.!)NgY141gdYx''']xQq7W)6Kq.K-&$#_|ՈZ>5Fܠ&$ 4oϥZ_U2yf(P KPrRSsq5XcSIDZDD|FZ&fSL,gbB ;*oiqXܪ=?6V@Ҩ5 L\5g[uaB9))5+2TltZ&:я $NfM(鑠%\.Z<εՍ[oħ?ڳR@Dyv.7(/ji]e\]{EOUb~d1'_J-}v838aˍ<YzTB`z561Jz8IN Pn F;PiT,ο1U5vs !fEzۺ'n ,3d}Ʒiِn;,-|j\xh{gVZ?@$$5d w;3խ݊,?bz9@&JE Wz*/KԆeDŽHH;sy$8] V6ć"|>.d_F&zݿer5Fkku5$kئʰT6ͿZMߔjg}xJ#"V>` 2Bځ'YԾϢFuqvrj~d9Zv]#ZsA~.M}z<,2OOi3/,33t7YrHsnέZ87k٦i΢DD9ςkתy.GDYգ!QlCP"+R7z_ND[wdXkg0{ O'/!^þsU֥+stڀewPѩoJxD*@sԾX\큫~Q%"3UFz D$G\൨LcޥknetÍɝt9`uv.=sp艻t^?k:xix_.ͽ]UFy OآASB}+٥Y^/(똉' o333U}1)((_U#"8e<)#7)ӗ%z,(mg G8] ţȸ,K%|*Tyz2ĘTik+1I7cqo`9iUpWQρ%"}}LKO_G%A'%]]G@BVfx4bre#`Rb_<~ngWp>Sb8]+KW/^J<|,l7oRT a jˊ~8${)"k;U RҳoФZLr/ 9A-lk}3Sm|« uم_qJH X-`~T#;;o@}K-zLNyM8HZ۹{9W1Zzca |lGhlQփԧ,?bXF~9f2#|jV^W~T뾋u9Òp_5o~d/IM9{73;7U X"Juű_ CM"$Q>,=R81ss5Ff6IId4_w3:]Ǐnc_\.1x^>=M +rm՘^~^캟%6{8lT7/OF. ~&6Τ핢Nzq_D$9WSv<̕ J?+}臝{ƛ2Dp'f i1<)DR..L╥=v}*HH 9cpׇ%7J2nowws؋k~y=>>oct h})ϽGӅ{ۧi?R|@!5].e,Ḡ;N垸y)rh[y3{4*qfnU}1P};xi>+P|FDyaB̾[wDٍ^v(ZL5'oo6yz١(=l4}Swma%DS'z/>p2t).rkT/(/6rʉr95dg_.;8.|m7'c:jNNcw>g!p|LUAǃ>1cʼnt߿)ɟnGY9㒔(޶ yvqnѺOK/,W۷M֬EbBzhw\)'!ޮڸ5sjN坙nEO~7n~bPO$ztwW=oVIƘVLj%ִa&QƘuTӀ%ѽiLT4O{C3okTː#׋=#g/ވ%-f;6Tcܸ/Lt)kC#{y# vϢY3[ŗ"ۡvewZ^_ \qWm3obiڱs]#X#ݜ.G??}yC[iW7*\>|>I "jMKѯ:9.1aaq:yR{uXҲl+:>bRsݰi9b +7:c{pwĮ]?~ 4fۅ lY՞kBN_mH'T`RG | IDAT{ɡWm{h֚0gqGŋKS׫PM;ߓ;vn:W=@4z'uʼnW^1+lj'*ų[ [rV=h&zZ RA7YS re jZ*=YKKLORTBjrY k􌉥zkӴY Wo/߮>io4c\2nKO "K<[ y6FDD<)ojJ0-9g'XY*V3otu2ٱrb- oآ,ٝ,g$V5N]}K"*7nYl]/X"!f)Ubbe-]-յ`\@jIbeG%"QgQȫTjѪ ׈=|NL;.Di2d,ծÿwp_.Z^;6a*T7 ? 9p߲߱J==y[4gr$%&NF59"">>:^€!9ÒN91Ʀ rqz!;=]V(^v͛b߲CȭI# ;ME=Txj8hjnݰ:["K !+))G -r2L*YfD\@& qqdj}܊WW6!+te$z&aZBbX*cm|(yaݮORx&< ָZ5wʢ/m}k)ϥ XKųKH%G6=?liaEKLZ52llS^&\I,$'&3mT֕OK C_ŷ\eA 4BD|H>ook~a˶)rܳmS]"J^ݽQ#A70z.ܙ{e $K"$u7ʽp] g,x&n oPO}b0F&LYDZ4sUtωu OcUjrW;6II~a)#KI4n_Ր%yW⊺S3{v2%uF^`od){"qԋFޱ;[S-`7O_粭vܾﵣu ($SCv\2"iLL21&&B|lJvc, =熜x._ [Wڭ zg+GpԚ9OJ Z:CN1OOTxI>{n}7vMBsEw5oa^ޝG6oWM,* dY[X_c̭N^vu&C#+\7p$ƺ팅ݹ?vp8tv6i媣 MV>wW^#w=OdHŀfoڷiW;0xtoױ{ Pȉv526XESRu2O >HDqrT̄bz$d=9;^;ۖĶ t3fHץ]2x%ظe@@=Dڸ5|g<_>~}XDeD7||̴iAPSY,噙lڬHPy^Pn)L&n9LԼn|w;w}ʞ=m͕ }=Z${t{gQ![_5~ɩ(i+"bN/$4ADv~ZOܰMnyKaW^+65c*I{y8 KĿ?pQlG4WҹkEKm2VLZl({]ғT~37cLJm\l照)RƠr>3k\윜J$8X oU6þ2̹M7V/}(q èc 1)*5RCP(' j5 4BPPj A @C!h(5 4BPX9f2B^_ /Fu;wlwx MBgVCtnMܺ:8t?JXX":c{sI4*{bS/ղWۯ+6~f[Ř;xiȨT'Pv1*.:5{^rSNKN^6ϩAer>=}]{jI!nM]<]xѮO]Hׄ.-ZuRj'Kzn CքI-<;;@ND$$ ^}қ{ɼ]8/f )*cށ}bj\ Kvgi :Ե[ rQXOW;lUVeH;Fy./Ua5mr7R= ~kp.Tnruߡ+/2Xu3[ojUuT(rUʍ[ڛk1cT=9.g,x%ɟ;ҹjz4V7o/ϊĚ6mH/:*ZU1ۻ1GYOg7/߼OwQIj>u2^IiǃJw !C423]\e98b@C me\ Dcmd9[;[DJ1cX 9!Qe *嬅9[uz{l&""A9df5hyÊ~ϩn؄Qj4}_ T_UyaݮORx&<9t\h|,}t+3DĚ[DD q/A.fV$x猱V_/w M5AuZXǧմoc+XE&fd(ͬUٸ+eacneIcyiĒa MD*DD* 93 s=laU0;xu?.]~ק0Ѱvb+qS/^znc3NtCDD]sAZb))yDŦ2A(UUN6ڣv yǂ!irtjsDD|8KKkXC3.!6A |Gǖov-P^̹U[{WX^q)AF7 ""ʣ˓=N9qGe |[Qr"-T6I^DLH׺v--Y^qSRu2O >%FD\]j]_T<+zUէz113z0*q Ivf-mfIwhoqv[r\wX\uڴL;z{dYя_3P&!AXk+2ۆz8^pIo;ls:8ZUE6̲:[n6-7vѧ9$$ںi,>p`.n>w|7ww4V~c^/ұ{>Tj%lky^@z%毦U-[ݷ=%x͹FUlτ1\[c%GdώDD8|Fwgtvo?:+'|HDCLƴmҨy’\g(iӦ r'˕%r\ǦꋁOOx#(_U; '!'m ߴnj {gkK[>%d0A"&9/ -vO\^-j_7?ޗ)H.-K(|hQƹi̬fz>f>/'g2;{yzYneQ{fiskk ؜rH5doH)9I9赵Ix1&Bru J̈^3:@ТV۳&5tR<禬z]6U^x+\KcnM ]2O <~՝@ǢM [fp"9Odpt餎'Ϭ-lÿʪF'-&`&*<=dw!6i vkCGDU"z% WGB.,э!9?z3(Jkѡ)~ U;ymw2;*ZK˒%<ֱ };<#\V61,[͐xىWBz uH1b?t࿣ܵJJ 2aA! 51TDbd0dVcaMNt~Z\ ?p#CQ/O‹wrU>/~=CA ϞgF>L[nfH.'cN:ϲ_ZyZq2 #U&M[Woxd廜\ ="X1,[hTQݩTBgRdYd!{)2YZ9%,>aX^AP+3K(TB| LTB>+}!ZZ(Cem0 `+Ç[gX ap˃5j/Sۯ>IMYeYPcF;]e(00Oiʿ,+ђ$'Z% g~ܻ  @P+KTY%'F`Fl+TxٳWv46L58HlAlSF7( 5>>ũ9ryA %PIUu@ alj; ˲ljj,y  Zy5a[AĖeX݊ݣbPp8CD+81嫒ZHu!ULQMh:+^Dz8eYUaWB[aW1{Q( Èd^%!yL7gLY݊L,S8@D (Vn'դLg^U)X0F%^/-CQD5 ڮ,W(-%*F%Q~nSh,QV0z:)ؐV.VЦVNV8҉3*rImgPxWZ9\jTmbeaʸT^jq!aJXw5P*'Vʸ pV P?j͊|J%ō*> rȬ&1E--<%mJeYd*-HX>rKMKHcEV%LO@ wz@j֬;=| WWԾ ÔpHfA U\ME)n7 zh5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4BPPj A @C!h(5 4ڗe٘XR111, ӔD)G{=R˲ڗB"4j@4'l4BPPj A @C>jPd{222G|0=]ZjH RF}}q} r.33) >Of5(ABSaТ?u>A]PʨԲdi>\g &#4>Aihy6}wgkhl?ѕe j`CIDATϊNiDUQ,##A >O>Tp*S:N IX_ttRG|fsi3Sm|2tSiJ"d5_2 n~Owfw߽ڿ'1x+`&$_Yܧ[fM.lGhl¨&= paH̱Or$'ϕ c|=@}iz:y?nɑ|lV0p*'=pa z^V|Z99eByZ]pU>&/:쯟wp/G+|գ0}ǽt;{ڣgG' g??v@m^qHH?gx2T'̋tOm=cܳuCf(Ξүl]qL}>*rt^SW\q̩}Zƭ᎔Hx?<:u؆o-^3F͆ pd'ʕb1GS~digNF ,xyu:wO2jn>_[)yL^m:6Uٛ+Ftjyb>)ɷӽ{3Cy~VSlcߺ̿"_n8|هзoV~R|"w*!-h\i-޹W+_=x΁7?|S$l;m䎍jYp?{g¶ '.>nnPLⱙ]:v_wόn[7S1? +& 4}Gx/Bޅ;{GGYa{ > $r]{;g ?eIA&x.߸23-߿>C^,H>--N[XkNL_$Æ'&u}ZVKz*mFХNe b@fZ>!U?YYcƎ{A{c u>2dgMe>z'3 ?6yօʣ  =sqO$DD-sMZr@k3NWߟ'wNYv1] !ʊqk|?ql,f)7fz8tϡu8刴Y4u]ع"Sr^9a'}_o]'NCؼb;ڱ`dߣ1u5_]];33.'l߶ueg +R쑟&:dh𺡦ǦLœvq =u7M㾘C7-pyކ~&(ضMnӲr']9l٦9DVl8qޣǏn|G'@Ne{OY❏DrDN]1%ˋ8{ 9yW7+'mW\[mW="ERϚW3Ƕ,Ų }Ǹ!k:wh38p1U.x!пԝ5(Qa:~qfU.wkީnzcf4qoݽqe)6s{B.?-P?[ڽ5} o>rdMa+~ *(ك[&ε o쫫lHZݿ\\TK[%'@J|݈:$ĿzZ߮b?f+ר?{:q],'8""NS@|tG|eU×.[6tU?$$cYo>a!ͭѫN.>$IhfEAZ3υ zhs*zvj)\8.kAN5Yְ^O^| l;ۖFzڥ]Ihb.!--jsU9je.UmMm*O1d̍|WO32ˌȄ!">.6] xgHcj305poB, 3}W5+պ""-:5,~9 Sr1 77O4qC]eX \"cmɪMr=&9 fSL 8Hlfi.~+pI IɄ̌L""͞tnB1LjH)-_2)?s *&$ʩ&GDBvzL ",̭cMDSRB"OY"32|Y'e=JM2XRXUTJsa4܅vbGQsK~Fm٭ \$%"KY2*v$/ !+=]ZVzcYC٩;b?Ʉ{Mq~Ҳ)B'k[j| ,KuQ3'1|G?9U?񜳸OМ,VO) hcƌ3g.M>ᳶJhFdQs욹RycSX!G;2DDv^~ǖ3LK*;[;ƍοʈ8fOdHK~vEQY(Z&:я $¿_ 9y+ˤiJ:OoM! ]0QgJڶ=ǖCm"b[s޿1U@yWM몬nv^c?It-,|}z=%vM,ڞ2""!3%UP6 YBB>S>59M۶W}ZlmHDDZ]3>H|{灛 qlgpjÖy '*ѰVn_?޿r}#IY+W/g{œ<=it6qX'~-%"Y×RK؝XQm1r_wFgH)/mu!^⡣g7\wA}c<.i2&Um _={Yx-{7g}d $K-im[nٲul[Oڴjzsݸ'ࠓ''Ձ.Iס[;y5ѧ;'Oc69egggg:j3ر9"?ls 8}SZP[fh"ymϝS3ɰzދZ21z[YˬtIeq5dm7G|3RA%nԲtKg=&1ws&U+ՓGa悮> Y׿]t}Ìwmm]+vS7PN-<~ZUpjX""ȭoc& qi^H"n)MZN]lv3{UiO:QmU҂Dj0>?y9m&:JWۻߘ&8+($1l6 3'F[X3 m!25 CDMaA|De=Љ& Eq=4 B[~=~w~rwغk/ h"7d-.HK=ep|&Jvɦd|6j]A -eggy,L+(57(97dWTqYE֪~]܊Akvl} ;_?wp3KG5jԎzNҖEc?r!p1xO՝-N/X|G3VTmmĠE}Nd%v<#R>(5kvp^O;sT\-zÖŅ /g,۞Xկ`mmۖuju_kX.kjkږPk+i_+Iq΂g w/1 ]?~m]mgE^|}ukс轺њ?6'?';''"?CBBZ6gzZ-( jZRً(.}60o_'Az\i~]nV~#Q.k׍;֓ҀF˾p#Ղ bɬӌI *s>곈ڙoh'ao_N]g=q~ZR L&Q\|͝4Dgbƚy%W#. `0&`|/yqiPIA׉Lsd4Nԋ A @h}t:]{{|&%:A 4* 2ffk4ZLsF1<,l64~Ԃ`㷁LQL&P(BP5"(A @j EPP(BG4L IENDB`kraft-1.1/manual/images/nl/numbercycles.png000066400000000000000000000366561450127457600210510ustar00rootroot00000000000000PNG  IHDRKk" pHYs+ IDATxw\U=L+-MQrȑLKssLGAqkns[VP>K!0BAR! a)FB#HX !$,ԓLo}/U_ų>Ǒԗ(A9(y`<[LቿompQ5b%uM jn8D1YH2壌g]*^vt-v+9a2x$,_ԓLjىɿe@@֩C}}(-czF؟6MB$ȷ^M4j-dC@t:hЪ/Ģ<2_[Rǧ)tlFDU&}[upj^4gGUiéd_ʣ}z}ZUǛq ?kGzu!߬FfOB/>~aOhMtk`r z5 $Ϝ3${=gjVyA;\vǺ>_x#>~/?{-ǫ{3yvLI U+ Y= }ۆ/̆1ti拧g=6kХ/^>[)+]w 1Y#~%"aRϰ$ZO;71a -9=gOɷ+Cٱn1` f]!77;LG'>38hg۷iN,V Y8kv/wsTZ&BQ @@ ]x>dɓzUtq=;̥7~<6Ym9N0f5B lgDz>?ibQJX=]ٝ(O[!8tMw~T5.MĚƆN2W者lٱ#ӫ'{0v-h ,8u%kdU6}&}J]d3g W]EE#~d~߄5l]*1x1W3gȂ [(s.iUP."G>WQՇTo:k{ע+C)6l ǣTSY$(;wr1c^DG t<O+u*m;M~=*ӮUMk\}>),Ѩk ~_ˮH{9Zk3o;AQFbx[}Ts\k{P>UW)LJűRԵu5n#:mhUn16,u8iIVtT𬊫YUEjSD4<\B)Kko7Ppxۃ*VxuYT/w0C7DV(J>*s-R-aX[Z`o;[KȦPӞXhw fAXD,{ do'eHA'1cԃ0^Y?Tc犫գҙ99aK[!*hkg-MW\\q֢RFR#oYKѯbcq88AuTw؉n^QIV_";G=&6ؚeE!K82@`g'q{W_g,P)HՄ)6)(<@2)P**G{Glt茩!qtt|Q* ]mnj2R+K6boSK ƨ޻}]~<lmĺu(:дGMdǨ}}j L={JWPHKtIFs(D\|49 ,'Wrez{/ǒLV"Вz:1D?ϑIf:i8cҷ7k6{qh #]_`QW9~xxzQ |*taфM+ј:8&^u hW(h3f4>gϛ:=Ye?tjivSr`i|8?_'ҲX?ظ&#~Q%}~s:8ۏ1 ٸKwXԆĿ_t3rVw/SgR 3)"#$%=xyrcaYU.ټшeZgWKS_~aOhMtkiNMϷ\ʍ/D@Gt`˟G̉e n:k5Eu~5l?Az hWOAZ}WcWӓ0C}}eY>'tmF o׏GcQtUbN,ehf4hGs fv8zMEiD'IQc8tnՔF~>4w1hZ^7lөN==F?a<޳rhڌvSM?Iۇ'Nd;ω'ӷIOO33Rqlvbؽi QL#v8Ήعs KȈx&5iDo+?'[m,ZX3G#.t)*bIvv,C㙶-Zǯ2mV/Iݣ<;3+̜LYEc;E_2aO\zR8Dxk0˷0]qު&%쌭+Ǥ'r}0CBX}',lɨ=h%κ ,̖oƲ>ϔ^XhÔիʘQjSZ mgƩK9iLg&7A iZGoXۯ,U-k.ޝI'sɧǷ`ye7iӾzVu;Q{6@S+NC |HB6焂[w)`3 x ˿;}y*03o>b 鰩qt+NC8VK*[Ώ1@􍨬j\r+e9UuynQP +6oJ04\gN޽(g*ph^-'e߹ӡǎFLtO+uRX? k/>^3l%QPlILChq$hր{G{h)A8F`aG.gl EI %b^n_^ٝ>}z3bHzf2C̩ڨ>Y,} XP/R*D1y{kXĶwu"7-dd Y$ŵq|j~^PJX0s$PIs V&}3mw/d9⵩reի~'NP;W+ĩK5DbVX\֟#KSЂ+-ɪ o)uFϠ?cc@c:m(z}ȩ}hg;{ԮMmMCtv hD>i|Mycʕ*.*:晥zU#s=Ud]ȯJSunM7H#"kFϦhRTs}59OD$_!gE KH v1"TD"J{BiHj"OsCR! pXYYr]\\\s("w>vS*WgxRnE!.] ss\+SRŝ.cͱɽڥslllrYBAR! a)FB#HX !$,Ba K!0B!R#v]j*7sI[*!xRsi-ULYfX!x&5?ex-Er7Cr,,{OwM6p<ӷ t(xZ1~-,+f7T%RLQz=z:EKI蔞˷)F1Mlӈ]חÃ98A޵|״!=V@ͩBv:3s g?J|ɜ3ѧەX7 0rQۧ2u+VT2U^8WcBWŪ ݱ`L=ņMx*v :U#|N.>,CP 3=K|(> a)Q, EIJ@fl͐jOF,w+FaFN!kF MjOLԈ;t?g; =HK2f0~<f !]^Č*]'0YwӋm1h %3qn>^B(]Tt3sѣԨ.BQjYt !$,Ba K!0BAR! a)FB#HX !$,Ba K!0B!2$1z_'ogW;\ %uLt!]"S΅~{Ӭ“j wػa!b:ըƛU{?oܟ\x6-9km40-2.-Ne_UKZ}1s5osaGϺTCl`=8BmiA:ȁy)nϤiZ x/!Lf.7H9h9k3ɬŧH V0;|^12/^ ZnX6M*¿{#Cy9 Լ#ŝfh兗|L@^0&Ϡ_X3zSn FnZ2.-^M 3u(c(i+Ѡ^='=̏2{ |ݼ7sgǔ4oMm@:ߑެNkfbGu&~]jog3rYw[-? }|ūqWmEgbOn`߄hМ[KҾ1>ӆԐsh׹rIz85M7PTxl',Ի\HV@ۗr}tWAjaMz}#k8]yGzE]a"><$hћܻCmWDeV 7Q^}!Sp&5Shc3cDž.e_A, Ύe}(<ӶŢnDZ{L];Qڢz%_ a[Xy!?C[%d C;):`![vlbjHr߸m ca =pʉ#Xs;b~{:t(X_f{'5,nFNM93|ܼmrE%;M5wg^9\vjJ#ْQH=MHhrxՄeiMƻ}[*(`DfFc+E08V ֡ƭaklZ(UGlni{ OC4)aNgMϪUi (`^65KDs΃u*ڻ:ѹ38DSU(f-;Ì5ߡXl|4"we[\DZF p<.Cg[9}7?oSn<+GI,<|JpL4qH"- , ,Ioi"_=-~oZ7ћX*Pe37iL}|Tj鶵Ol>AF,҈og}pZ)x[֥I|f H)G9,6bLp ǒ@ס KC}"f{ 75!jͤTst)zL,m5,Br(eS P q> ]%FSЧDpP)DE\:-kC*&$a+!)}͗PV§L0Y̖ )lQ ̹Vw1sk/G ҽs7v  D5u"mus~+ W-˭ˤP"Mqۍ 8~7ՃR uGVɁx^TlB׏Y+7; t `ڌ  1;mv{5a!_ a(=ZRq)cE k/>^3'=UaDhP07 Cggm0K)Cy^zm~x6sٵ0%fIQ%:Ɍ=bMכtQ݋QiףbGUzaÌG_;9e͡ ӚM~S}ZԜ[Nb{J`{@{lKbiWЬ<TWoMi'u |' Jʼwmjᦕ񪥰\H 5?ь>K<жD\|4ڦR‡R.n&J\O 7684k똻>j/KDG`^r*x36Nǟ/hS_YMSas3Q%TIDATхp|O 솟mܺA˵k*KYЈ=&ӵF>%(wU^S!ZA ғiS 3`4+yoGiLUu+84ՌpځZjfU fSsUWNJZ)z7K&ڟ3*/;x}t䇶IcN_ǎ''ץg=ɮ;/oxSPZŧ/$7ׁ.OXSҮ|i>(?5fЦHt|; &i]OjmC]pmgGTiCt[FbޜhXբc~ C~/O%2w7H;jx?ޏРYE΄փHojY>6A%> O,K<;n4׉,Y1Kߠzm8(7o#O/o;oyxx = jMuφ+1>ʯQ'}7ƥMRo< MSqv ]UϏ ͼ;=g\'ݏ^xoB/W"YvpZۊ />Yk*݂|#$@AH~SSi-{2Wrca'j &Po,c,]4v9sb7'Z d6_xO~sshנ=JGDnљSo8sG4E3+7-ݛؠU4bw(N;d`YϏgߝok*x`rOL,X_uQ JOq:}n}}~ְ=tëc\UyYhD_ fW F׼̶Oα.kgs~G!-O@Y + ^m&)Ȗ_v<֝뽦L[zR`(:@dy 3g/SgWI ; 4 t^]Ne0Qsχ+Uh%)i{ןjQ'9~8oTV[2NE_ %rq{˿&C8 Z6vϯz8i'i^WH'0o_ڃ37U/*deyzA_̇ 0sLJca\a'BQQE /dmβcIqFiZΜB'Y'l .4!-(dYF[9Q] `Biul=IEy&`ZzoW3Pwn=_1c?yʵyi95n=?H/R!S P-HT,mZ`eX `о̷Ϫ=q>hEoO5j2 M4gN@]#7o9*6>ކ v7 Sw/ G(g(Og>wpoy11AcvGޏDg瀭G{ Jz r~YNODX䣲kqes $׌! *?6ʝ Jt;آE>FB\Bּ{::ME\@#&:Pqҍ߸1%)9w\OYjWEAKJb(br50^EyxU_ `COTYk*{%|N}%\QmNFQvbw뻦o}I4UPI%_ T&??-x8ί7 nfx8+xE̱DIzme{%t$%&Dr.9>`{C|-B7fuه)M绁͘;ѵRZql˽$=kRojY?ok woh9*#qZߞGam~7̑U1\vBpbs[YjB: b̍w=%:ȞJU!.st9s2A~1G)ܒo1`c:T/>AG^V4w^5b[)1 Vnje]}֢ph!j{X;8SiM0bTD04eR aCxգEM˯?T㷩rᖁ|1Q`2r&c8;-={<6s"w8u2U@#Z0 pZ^/"uWiX-E|bY gP@\H2җŴr!i !Q$,Ba K!0BAR! a)F,_T?A|||nE+KKʗ+]A59v 5"?ν{8w"ʕ&W $>>^RJbBb̤fhs ׏,){rB#Hk$}BsIu>wbu6/aQ-Z>d߹b_1CzRUpfmEgj\ oOķY"F9Ž?a@NZ?CۊziN65q6eӧWNc3)wa|P 3@ ?g=R- Q h]F܆;ހEߺ*,75)%|1%wVyjS(VfIZg΄I8p3Ė"vb؀κ~ڜf8m4An~mr~|ŧ+d hĞ\Kw3 S7hk;A,/)%/$l8㛴 df=_Fzs?I ci`~8r+[?ѥf1k9"S©M" l28䋴~jȀ4n%[ldec|6uw0j. tG [.'u%87ݼ$Y^ Ȥ,cdEG/#d󯌬z~!,N=˯z:fJfr2CX֧(eo"򯇲@wahK0yo\c?e`~W+ym!trmFhФ*W7s%ʖ˕ Q4G.d3!f1]u ZOyǢ]ffʱ?n!q [5͌Ng]tf7cp?ћջ(<6n^H~ޛUl,'ԳZVyZ4嗉˸`#ldKz׃e)7!M +Eaj1~.q:![X=*gNaݝ| a7lX-K-rG [=8ˆhZ|F,ތNu `B2x Y* &inf3/W2$ܼEn  ֤VY {ij)(vY woyQY *(`^Ջ/אVU1(r;Q*mlPklCcSK/J[bafB0 aWլp+[EWDof@PnVَ"E} ;EbpL)lY8ihV EG ^;l`tW3A:eǑa_9-)_-\ߢq(`V5p#ox&WMܻmQ((7FMɦh1~tyey]nK|: [ԏ]ݛWh|Wp`Kh5??ao1ٺ:>՝g}Uc OΞn̨[$x+!H/Ő|Bf;G{* z lL2iYnjY?`8+ jH[hOubɂY|:7~յ!ڢ܋qwQ/>ã}JA͙>\+,ߦaco0B @>;~/ S/O4 tۢEEB@#!.敎lt :M}l~XJ1vC~=r8ޖONՈ{-)!_{O̹ՌKږTDZώ:|^:mSW~o[&2pw_6@-Slpd\v7pJNOcZ7=~ҾtK?X0+-’>?ݵW˹}{hΛ~(; ]? Gj|~J*Q~amPቻBwP xx{2Źn)9v>S>ĺR_x=8{*wq^v D+m25~+Ҹ,?oZ<\""YŚeKK!E7qO-xǿ.~`hR-9kg$VS;W+ĩKzkA 0u,NV:lmHv[)i׏q].N/gH{ۙ6|&;OMNn?kIE_Y`Utx4u6[1+"348M~] |y1>a)%=ivi MGf4tCnG=}v۹`oWz5=f:hϤi!2k1LrD96Ũhե5 'Ӕٛq0^"#%|̰EqcDG {di Zdmgcv}:Ո8|U-ptv hD>i|c}nFԾfPCCSs $i<{*^.YYک.*:WGQ]Эxxx– ݁=XUgjonl|fID{ŔVjl_N.g^! h$śéfd3]z] 'W/Pc9lN!p !s|izE{3 bkrїyr6O[]! !0@4y)#/|sH5kHR! ʒ{Ej$,_ʕ*q.^E֖ҥKannke|MRŝ.H^R5[BAR! a)FB#HX !$,Ba K!0B!۰"<,uE!rLxXVV9lUU .cBښreʠ(9Ӏ6,B<"}Ba K!0BAR! a)FB#HX !$,Ba K!0BAR! a)FB#HX !dL *2IENDB`kraft-1.1/manual/images/nl/taxes.png000066400000000000000000002143711450127457600174720ustar00rootroot00000000000000PNG  IHDR.( pHYs+ IDATx^wxU{vHHRwPQ"(QT bCDQQ  T QAHRww?vOrr2%Mpks nrDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD&"""""*t5@t;,r'ݞQ '<DDDDDD.6i^/OM1`wpm(Ծ5'k~}#_yQs|{myDDDDDDo' j}#j>`s'RZa_S|_2u׾ӸGDDDDDT^wBi=qJ/S|{|$x'enLf4Ծ`'"""""a6)Wj0 nL|o-Гe_K.P4]_噵ej׾'[<)du|_Y¬r/$Г\_mQY(01krF₧qwJ.Q0*dӺffq`֖嘵ef9FF1#$YomP4]@ "nzFJ{ fq"""""" ,  fٸhkw\o| .nQ1AmD(hmyq5WWy7.NYq@奻uܭ2UF}3I 'lۛhYQ@|M-ei`7qp763QLK5_1 FyjۨoƛPuBq&ܾc/Eۗ\a!rD_]?5fWtk۞1hBoSқ#P$򘈉~obj_󉈈_'jnj<꘎E wcbM[^ 0.ݘO=u=wc@€VWj@mEuL]W՘Rmu5橯4NDDDDDT^y0^]1uhLBWFkK(n6nݘO5_ 7!6PPPaw]n 0/vbf܍#"""""*MݍƓvܗԢXyrLnԏq9f֖RPffJ:&nln4Rm}uLWR9ʘ}y\0Z<=umW@14+.䇠^u>&" B\m<6Scy< ]_7b@1닓~Zp*;;r{Pr/d|'6G V EDDDDDDOF 0jPDEFCE4m8 ޙ]{2ykTbLL@EB̗վ45-.ܑܗrLٸ8 F稱[6e'QrD,ؿ_zBE;[D!"""""*ک:u58?VůF^^FXE !*2sW^z{\Msb9.qu] O͑+4 z m8!K$,1,,ȱ3I9 U.svANf.EQ"}z.t]g"sg^v}'X,{yICC>iռ)^~voc]Jgn[߬q#<;bޘ>1 [:Ƚeێz55W].X""Uh)xBSYܯJp!ℨ늾|E|4T|UF3:N%Gx9t/Ald"4Msnе\&H8dۯfiㆆE][(h耮#jŨ'brя{o7;/!ßEڗ`@PR<ZKDvW܎*ѻ5hެ1*ፗGp`+P ;yv?'Oihܨ>230o,_'cvVDGG#''K~[ij#!J|$b+aZq~Xݰy 9;_v;u8W_ X/|2sn~@qgPnm2m:5lؾcZhWŔOfbYFDZ'0yt$b䓏Nx螁gf BBBкE37fΝWxDDāj Ѩ:sB<714"BM԰?bChռ)zDSݯ Zl^xH!C֬q#"沢0!_&(Dk"[$&qo .\$ FmSsՇ1Qp-K߇:t$9=> X\:v8tΟéԽH=ԨUc8M %ӹ5oLlF  "|"5LDDAD`X0ⱇ̯3`Ї0uw_"<" MGǥuj㭱/bXnl6 Oyy3?¨^+Tľ?t:zW&LкE396x̘8tbbQ!"N{!#}{qlx'qg^}췠ik >OgE\l,&}[ĺ6_s hwx7](EK1YmXv=>9l6z޻>xM|, UK@Lt4|2C.>a+oLsڻߟ )"b}|!oG~ݩ\)N ((^{]:' s . tW\1wmO0ʲpaDW CHQKI8@.fU[ ka$RHPS6 sY]Gx,*6eR4+j]xc3I:EeтBnРaۮp8Xrlݱ;CU*#Lrb:a?س`8>5U}q|p)NIFzY ot쀏fs?-Ͽܗ+_};e8{taz_.p=A5ivt.SDD]Lt4ƾ0s %rn]xkT<5ЪyS<=p8̶cߒu@3T7L[;-?>"r0{A_ S dWy"&Ɲ'_p ,!p\[ bk"V7w'fW,dтB6näG_ ;~υ_:wDddtq3)/~II-gj@w80Я-xc^|\TðG\W GE|) 殺R|XSdoӥٺfqy[P_T 4j&-JPLGÁᅆ` >EיЁ ՊufZhgÎ={^ʚcO %- 'OŋF`_(@)4l ³/; 9=Ws=f3Hџ "V0Cw8q9b}F<F:/Mzixgb (|E? 51v\Lw(t]mZ!>.p刟"?77YY٨W6$'|],Dw4AKw#hXR躎ClL 32:񓧐t +R|;|bkmoл> ~WF?]{;K+.6ڈ\W;st@zgϢe&X,f1" ѢRC~eym]¢?(xs^5djv}={  ;<;7ZF]}`ސS rL Ti*g1扃p-1QW\ 4 B.AƳr]93/ nAlۉOhADtq4m? ƿ=oڂ뮹 L3)ؾs76nZ8OY_a+5N;w7gaşq}Ehr}zMU8e˶,i˶ع{/5q"BC&-c̳#&pǮ=ר|qYqü_*u/D[{s6/ᎧK~,\]j;Cڇ2mwKY\4^W\jݘWrCgrWRudeA=U9XI:QfuQF'"""""*'Z4kߩCcǎcI3jŋs7c!<W[b6*/ŤTČT ]fI1A\}\*9"鳪`ZU1Qc pU ӀFɿե>Q9żżh!lߵ#F?MÅص}jzDsސS.\E "&ϋÊW\b=3ff dB%@Xn=-/|SJ F4_ƛ' enTjn[DDDDDDt;zFڴlk_MrJlߵ֬m;#Z\myp(Z;6 ,\QՃ- bFWi zSOcb$Ǫ9vT/sIDDDDDDA@uuٺM*i_PoiyqAΓcfFXxtBOpfQ^ r\>mt儚 䩗3y+m՘:gVsyY(R…a=-ն^*~ QIx35}Ws̖jۈb IыVOV:.F'(s[1c.q5Gf eQY[.otb4A'Q9 j_Mܬ]*]pwpQ1:b)(>̪SDDDDDDDFQ"O,RPސ.\xR]NјVsZA[0ScRe/5UP_Y[K5fo(Xa\^SFjۛ~@VˆCP[хACQ0QF}:)Gn[EJr7&3:1ޜ8"*r~*^HTe$ĄN Jvdfd"$:a|""""XX7Cuwy %U wF>P4(@TL..A541 >)$5 oSo>܆Ϟ7"~oH\cDDDDDF}hh~ _cF|-}ٶԸ8fq"*%Y~/\uEBPJm4i ui؋|~>ߔ /us~DDDDPFWws]#f(P )h1" nCAllz;^|c8:W~澋%l'-bw)b)TX """"_m;4*բ|7t4qu\P5NDBw c|=m`9 f-k!?PX۬?MDDDD~a65 fqXP)+.D fcF1" 4k- - IGko8Бs>mW_7M5+uP3M0𝅸#70-.>FsV-~TLo1qq"*!>TOFm:%#qǫ ۏqu}I#g2U@llEL={9Zbv98,{("cbo8?Q@ޙ4K$*WEXY>sy("#.™cLFRz.t! !:9rϧ##'Q1Q!ć;ݎҢm<cP9GV>D z<*jFFy8"ł ¥ s8Pߗu8rRppwx?ȩxO7М4lʪ#iGv`Xl|c2 ?;Gam`CM~-{CPn#}T<,8'lEذd*suKc G;yzjMy j]DDDD%ۼL*v}oL8prjzK&qd x㍅&ɚV𿶞{+&{Yzui!"m~>x?yr,-TЊ<$vGvѨXjH@lX5Ppߩ8)TP8a1}k/uXU97b{bO#,^- ёwr&=̟*Qy|<3%]߯㟭|9?HoZ\Sݎؿ'|_@CXþ߶ozr?m=qkvxḣ]DSk4}s1emG`wݨLpRz la@Q% u@?Mí=9cϷA#\/!8yo^~Eҵ}*"m}1ޘ!nG<\P% z c:yb ~zo-؃Lǰ0pK5Tl; Hzбi`ALxŏ 8u>o@ھ8-~v 8φ&c⸻. #>s ^55~{>4k] |- i) UѨa^}^ :Ǯ6F"""bWlزR7ϓo;D`Zd\sh\Ii{.JEJi8~8 MZ!Cع|&ܳ J*Z8r#LN8g4DI7r[nכ?^?fvDIiQhףk+6RETmFl9:Z zVzuD]&hCCtV+9HODDDD_s[Ϲ"X0mH<>U?)/k5 `?_ cp WnGJr(?ſb?o9Q.E]`lա;beZѳ7zw5̾_a=hv R/bRM!kV Y¯CCĥQ$iQ%!"""`gK_ p$QY^g|Gnۑ{>oٟG=^*H0.$cVCXH|ECϏSlloYYSǃ#X3%1}{{F|QP @ʒh_'/eHoth/kN}[q+Gzk4=$AO]'fMDD *I?`M0͂-Gٸ`K!* IG㋷;#{v"F<,ϲr'z@4 w]<_rǷMtf7faLʼnw *BeqMw묭swp :t;MjDÒw'Þ-kⷵw7fi87TV :}z:6|&-ގW nFum Gw/ gΜ%x)qyDTo>7E.k"㶓bʸwȴġa{3u7>" 1g,f?ˇvWmr^b'FwyU?Û0hi:o; G+p x;t;NdFig1qdW԰=e;G~Gʨ>hX{zޕųV@-zGmph|s8aw߄0x;fyq,y!,Q -9 jäuOwǖ~qY8r6&]xEk)ʒp-nh5l̂.؇Y#- FW`)X9_)`i7Ts]]* #莓;xG.v A?_Ŋpj nh*烈HvΘThst! ?Z读ֆw7"L[ |ͬJ#{X|%7NAGƲ9XE,}--|u֌Ǥ_ҡCǙ^ň lX݇_+iX5m>]+֮^`G7*fr7([Dþ OŪUc`]f,~X+f= Vਸ>߶}?f zX LÀK? +?Ym_bҽ!ʵ{Xo3zVn<qO_`’ \l^v9-~')ښ|qLZ"iN~ThaO]E hy-}m j.-zh|j?4x(7k#}`IDQOqkBgq $ ,ԋ[vc5)w{!QU~@cMugݳ6*hmT''i&yKEZ hqXP-|6#Hv0nX v_.~SyNuZ][s~du8WnrUT:'@s'pJN-8{~t@EtQPJCZ^&ʨR/\zqхaa .$yJ1W &{jf8l{Y~܋*M!&y/vGV*R+Q9Ge[5 gБ`nD?456GBgeu -%ᵛapd`aXuBj1{&˕_qқлVh Nz!| 5XwEZcƔ?q<[`Gj֊MqؿpR[!(,p:6ʁض!>8vˀy QZ ^b=c_R10k]4iQ((xE)8u|3uDTWthphv4&wksЇW㵡,""tA[[]c:;5ġ~pG ;qױn[o:@(=]_xz кwtZxЖ2q$_ns2Q nt;.?t޻qk]oDd6t~WnAU @HS_*ikkMDDDDvQYLW7`A[`" D?b\+Oz*aB).z<"$-ng&F^m/>.vd6 Om1vW'E.uWL\ku 1X!,4ī'kg'I-"DDȮbk8x8#+׎XT-[܊vTPW'"""" 8..jԤ7QGE(hpADDDDDDDA """"""" Z,\Qbႈ DDDDDDDX """"""5@uYхW\Qbႈ DDDDDDDx ͡㗣9؜l/ GES2 D_`h\;"?FDDDDDTX h@P\ = mIjpA>imU JbsU ܢŧ QY9'  R8}G,u$f|?Nա2K =RߴG#_d \X u{(g;z7(A6z6^tEDDDx[bb"""CBXX]pxfa޽T(iXG>kJlZuBzQG!u i~9>EhѠC'4 9pzgAswQoǿ{^!^RQDĮ4,4) ATI%˥ }?ϳOvfv6̊&iq!)f[4._ 9-%Ѫ"vތGxmM`ƺDi,o{rζkkOf\Xɚ75z㥤pa͗|>g'bM\RwG/-s#z0aZ??~!H\;'eߘ,F7ʵ~Fvpd|0e6]UgemcPz>#OHÁۛ.:qkGh;Ɨ„j":ϐi Z'Hָُ᷇+&N~ݏ׮?ϲڡX̤/~fߵkcho臊tP|֝M} ByOV&K 6~+]&E3PT$ίʄ۹oR^~%ZOoEaɟ|8C8>+AGRL;+P~`sG#ӡW*˥ ]xcܫ4 T7wNp2ڀO6t+tg3'MgձۤmڏL?w#-]ɱ[8iGУBOx{T4|1F;}J)}ǖI8֤K[w [Fi^ߛ$m3vqo5_N._5eUKoag>5ߌg1(' ۈ++ua덹0+A}^z;Zor7E!Pt]G44M+Pl6mIJ& c玽ŽaǍJ4kSFڼh#[VLi5\P*JsX~kjGiANf|-c˖M>¹|:%z1eJVxJ9z;m]*Yv+[~~&8ttbMf2] W~Zؾ[6~ϫ7eԽ0oD҉1MLNywhn`wj{&>7ݴy' |e#/~Ϛ[YA].LUr͕&h&6y04tOew|97x".iLTi:v<*n/s,āic! VlaS }e2fI.K7ofwoX@cx{q|ڎgʕ4ͱim0wض~& x{ ʊMYz$K:u^­@B_$ QhuٰM?֯k61s|uĉoФIBBefI*NnC$OMOũ ݺ#bN;GHPpBh"5p*N)[YwR.Cܚ΃D[t, Mi^n\G'Ca ]J;(}.rD?Q*Рn \TP=kѨ#a(.M4-彜qrV>urt:aîmSsKiЃ~Gq(1u<xnN}[\#pajCEp@UcWnRǒhR75"Lٞ<ۼ}s.og{8ap[oQO֑ORCuC==NszS]{?u%jP|i7ݪCcGu Vy~oJw 4,rz;BS950yw*BҎ^uP yKĉX (((%Kp5t~~~xxx`g~Zy *GՇ.`fKfP^M$<*}㻱1kih.Ik=$UI3-:CĚ?3ߠUΐמeINΠk:HT:V~>]iDY gX*A!F \E(ٜOP*㦝wąo u5.EDb<;Afc6#CַɀH"kPo_o!OxD2vZF(utĸUG>xގW>Uf?j:qjL9ߗ?1D (xzYsN~;@%:Y釯}ƶ6EHU}ew~ߛcoTUAqR< !BOc!dK~cP@yYu]Ϝ-x_oF<<˶f3yqbzc-eTݜԭ{Gf0bu}5wC5gʓb遠zWk-~>qQnSFPu@TD:yz" ocK^g^HQngηNVj]=*(xxP?}o&A_\ёP HeLgr9o< ~ZRIng]*QX_"Ԡ 0x$KDG C>4$"#ѱGp=(iSK^nDD|MO'ޔqnzxt(N#W=׫(VyX!*B!G)tŨVZSPPP垞xzzȷL~~~-_߶HAO<$\oP5ޕm3q8܈).Dx4DVAnZ '7Hr&.:Q9*[fʁbP5LKfE5@K!_H*;0_̢-Ixs+ ևSY0n3[[h.B2Mix? N-"%v#w4N:W7x\tkT:szU6\έN4|BJ*~]1f0GsxOkJD&j4kd`Or6QS4%Pe(ݘ&Y1hgYt/2ޠAs0fw E)ɟn7Lٲz/aU |UcrW!B X-e۷oY"իٻPZ\ׯPȰ.!1.fKRL|&@AxkLy#4.Tuڇ{%bvh܏6Ԟzr }UxI<:C"n Ǥ1ZibǗrv2e[1AcɅF}ӟM~VOvKUlGÈt='XnSjz|7k,=wMbp煸yţOsbkZK柅Y3\-,{3B!SA#\^y|y5y޺U*mTZvܒ-6?{*/TR_$$$""<<eG1 K킚u(o Z!BEBa;oIԐFF#*U-PQiT.zC_v LāY|’u0Ԡ/ =VB!.D+ҢE ۬|myr1-vvv/MBGjN7mȓ3uOrvymZ\!BQ[6ɓҶUƵkײoQdI]9Lan+V lu "B!% QhC-ܞa-r˳ȭLUU*EB!BHBup"?UTʡDY@Fl嵼u0#G $g D!B!#Dr \ضصkPR% N-ʡYfYRB!BG.D$0PjU,Q%ײ 'B! Q(iZu5??likB!B(4Kº[mW?B!B!/ \B VsAA wTl-!y!'IԮe[$# \B-0ieY?nGZy1k-B!#c6[gRЮ*U*_yAO!B!ģA ؽ{m+VDUUΜ9c[qs[QF l!B!2fn`t憢(}[@+_!B!ģGPNWliwwwsvv&00j)͖?!B! \B- `[[+W&>>>SDs. v_B!B<$p! Ͷ{u%J*-lI!B!ģMPm E!B!ģMþB!B! Nn,.e&!t6#&!B!ă&-.D4(o>۬X"gϞ)FqY"##3*V#W;3af3i*^$΋طTR%FڵMy L>thRDrȓê7"x3[oU W3;:/DEQU)S@s̹l] &j͢oPL8?s e܊ tJ' |>˦;ݙ̠ K,.G&fD)m/K^?(N![?R\8u@glho.4·f/Р((*S<Świlu_xSiShCtQ)3j؁_ŶEs47<Юw_$Na=mQ?rQ3gHF}I&>{|'}3#a맳!hU8o䕅yϼ|I !7(]4-[򷠭1,HHH >>>LJx X-a hQ7M@aϗÙ# e\Ks?HkE:>כN04F_\1)GK;GσǏa)}ǖI8֤K[w J aY;8GM^o$m3lr v)x IDATɯf<#W!D9_@F\eGo^ _o̅Y_ hݥ4az"gV|Ŕ;9cƹHm8͊bzM3&æDҖgD2aɄO:F<M+|o6ϗ/9.yQ\BRnJ*Ӡʱ`B'jn.V SFőd'~pi2.(v]QTg~s 7Ϸܤ oܔ9EC_!HwcB`4l0smY])_<˗-6@!A -%ᇡ=X3"}P)VQfDaZ==G2n`F6OfvN^!,CzdUNj"5(}߽UU & K3܁u}BS9m)5pxfaqgڸ S^3/cS<_AcՏ^J?O%o06>֝)4{I@O?NU˭^/;=n-#ZnD͘L ޵!H͆5˦/*5OhB=x*qr/v*QbIΧT?(t?7VK,)3yc.3f,5~&K|MsN)!/B.D!40p9,- [lJrWh$aL>Ž_9;>>]K)W6o_"N7Er\5\udOMʹh p뇇%ȡ'׺9]{I ̝;fZCAA>bꊷSVRUPc]5IwO3S{^=+m@϶pjiY}Q >4 up(5RvݜxLxn$εzd'g[V׃^FMSB@{`ۺ"7+mxyS<0Çb&|f0xl͙zR,ۑe}ܨ^x$EU%đ1o<2SSc̝;?E[/8TQTq!r/! ___ uꆯ=ìeiܹꃟg ìs+?_Wo8"Z'&h*عH^}rp֣A u7'ZD Tlݑ:| RJͧ&0yLiwя1/ n"/B u+W.ꊫk&WW-$}ڵCl;r[1ɘI_T\UqS_It]#6:U(e-vr1 $_> cql(ݘ&Y1hgYt/)&D2T rCLHa(JHҮ]ѩ-3hu6̭X Ң?BZ'pw#cjڕbPK\ߋ#JɌU6!8a *M> /dQB^~ ՎRpZZ.ELW!4Fcf6{n"/BUDR^AۼfK2~mJrjРmV,bOѣǟa_j8 fJT3y;t@6|<.k ycJ1,ܝ|޽-ͽOn֊Js$w^[X<:>Fԧ8 tםW\>K;>psw&~:'"57ĄΗO/*4iK?wDD0 Icgzd5 O&IxUlIC??ǾVQuW9_F|] rjB;ҡ&͂UVOplB#lt֗zfSmCã[4uYo14fI8x>s97NB!୓s[.3狞'ն!pB! !#PCF8RHu(,މ:&sd[PFDUے@>g|ԯW}98qáӵYj7ҋO|hՈ:uҤ0Nzi;)jBwvb"3^4kؐ=xyoܖ( jTF%ړ3(.B79~ !#)vu0(ToMn(e+I@̍dzbhϿ^z,>]Фq ?'[o׍8{AVԮ7RןŽ>ǾJJaz'Zʵdt][i'@ЏʿfkS՝Z~(;:Z5D)T g-Cjd0%b롒z AN vjKn.[ T`Ȝ*1wey޼BqIB0鱪\ 󕍬Pe2ȗveLH>:>`V296JHnÙf+,͠|nƎF῰w6~U sv6eZxuPg~iW7|F|>2c:q8#)Sl-k(nߋq۞+'qK?H{+Q zq^/C(ZR|i,7r98Y."Mz:it?x]Fh9Oi;΁. !?!R}W_+fҕ6~ Ց8;;C[ zuFQ(f *XQq-8`qJDrO2UQPq϶'MŽ%q5U&5D ȳ]ࢂ}sjX!fx&TGR&:pʺ\pQܜp(h7+,?k]GT9$%lFRpqL!)9յO>Sa"YVr3cOhJ.k 9hV3k/}jmB!oV !?@iE|"Ͻ`dh/X)J?OTYU?L2wb.V)*>љG3cIAU'7k 7`gPѴ|%X\beb4Λjd*[`LUV,a|F0n 8l"%dD#Rpuں9l DToq4d(Ohk:toJA*L+L.--BoB<\ukS6pMJWu@dX$:yZ<`h7Y< tЉum(xxGEAkD_al?bd|eUU4ҫFb-)̜5wQۀLz>6Sy:?wPr}P _L s %iU*L762n$W=Qq?9f.|?uRI?Pz&fT>^N !@ uM!\vmv }7U Z5 b\MAȭ Xq&c=Uzlל\y/; y'9y1ųX#ڴ d Zǻ@k?lR0۾eoIuo_M{ 1yS ݓ?zjgOb(=X7ֲ2b3Nt EfയUVjAv0%uB!6hm,io^e^ VUU2U.c[Ҿ1S@]f PZb& 6;ӘYѴIC۬L-WEmrZ4kj}x5gk]3'zG㣦Nq&v{w6~=oE!B<$vzuf7^H14\J3&;[fgik;7da-(h^6ro@:ùz#w\#b~N9kèY=IG-:b]ӯB!q!qk+<1·݇lð77(ŨS=wA6ݕw)j# B!B[IB/Ry6o0Tf_hh6f !B!oJ(:̮lw_PݜƝ20B!BZ̮jOJ5sN*NW# 5#;cђXx !B!xI t[I5Q ؟ ޭhh)sC,f2yqeB!BO#!.Ȇ;THNTw+Xs2Z^˅n FfMdchS5]kx#?N"UqbQ#'buc#xcYtgBԧv ɖ-緮(䋫yg ى1[Nɥ|B7ahKF϶lBըdj  !tKSIh[ݍSqwRqtfj; *Sٞ^hb`.9 Ek Ks_90|?\6m yuRӻ(i҈0g-rKo^(WT5L8ubStV1M|=CF'/5%%EqbVDh \LcSl|P=A@*.ez /n}GLiǙ÷(7Ӥ5K^,r'u{\Y oL=O~9>/.WPag5'ዃLnc_8B!'@me|,;St{_ړ!7@wό'2}4kܘ698FvӂA3V2yHw6~^ _xDR8}؜ ^*ζɾҥiMgXH97K4 ewY~rOSxSS7jAAX9{GnkG1?2O9m3s+MY1}\CbLn|q*ʗ|u65FN`9)(N%iݮ.7r[ӉۻCeEpP(}굱 n^7}`:4˺. 8z IDATb?0M,}?#'PVE""ƛ@G CƤ>`B% p7sU;qwbP n (zQ4G;/k"R@bYO&r#!t|i *kg ڜ`do==ᮤngkF6ӯE3.v /œ*qau [Su?;N3~?DtP؟goH'G^~o=:`Q\t8Kwa缁Fά {ylۻ9D~AV4!_n`X*:>`V296z~C 5 g暭۳7wIK;fE}eT 6ݞ,ɾLkoncSעAk-忈˘pU+ [;Kڕ 4A W9qFJD6^HBmoKw蹇ʌ !~k[MM\AONe)K3k;xEul3)ؕ`V3Oi Sۉq-|X-(;:|2Y% yJ3p"WYޛEM])ˏy̯̔>ü.44!" C:;ǒ!vf*{vŬperq .!Ź4>Ickԋ؁}v"v $*e,BMDFD>ڜZZ*ZIat?NcŬx/j>7_mxb6ȺV =nel=I5\&hSt]#:"?0*>:1㴞 4f]HKڮFjr*.8=8WRuEfJ~6>׃?oHs}<|I׀});NjvH?!x)CIH{;uDUU!~SlDFep.՜ٹ5!q<>kۿ|7GQaAo< DEOe\ &Ǽ:Q/O"5(HOA( X41ĤX/V {&҇gi?y:Ww˨2RJ"ZbPUwMUIRfe)-P )2ʒ%pU6( C'  p17" -6?ڔ"|<{>${=ogTM_{Zsq+bbtd&bP6x#SYVgkL3/ղ'|an5LIԨC7>#OU|Uɳª7wJ5jEWr?볏+2Y2kuvd)wku*&ɪkg}uJJW`$)Y9 HQgkDJҹsoicWu)Pr!h_gx mOG)ER5T&BE|trOi.ў́UFTI$Iyj7SExsDZ'sJFvzozTJW|uY7ݳUD4uF&ɚxJkg}T6K.[WuE)KxӪ.Gqa:wRuHHR +Q'X=ѕCUX mSU~3B%)[!{RV]~K+ܹ <@W \pYe\waCs p9.\p.2~ȿ_MFkgs%jz7D-_E' ̸a\9y}J)Ź7v={\@6U|z6)5Z#TZ5hI>߯8#߈ޙQ7HkUh{-I'VgUZuxiQ%JPN[%cVޤ$-jzRuU#^E Zu~핯 g;&ߖ˚YP}B;1#__1ɷbC++dғhz6@S%K2teD]`Q6տLl7G*jnmDSiIyI_o?iP`oG H҉J(_H};lvj*yz9*ΡIyO鯽uzyJRQi.آ&.W[7PPp-56A~ݩ鯷U^o~g;6^jTaukFh uKlL^hF((Z_%Pܷ=S}5Y׭j!㰥-Z;>xM넨Fh:]3!jހgԼQ} 7n}2 XATkzoTuk2F3̦0#[^TS;sجnONmcNy1jV&j}[ImJJΪ >E=:6o! 1Χ4s ݹ*W9qp5PeSzqkz"KnȧbSd(I?٢ϫeqOTS*g]zzY]]._Y;X_)2lblż# Jpe+9 ߫u{T$|ku% a2xY,ҙ#P];Z\2g\/ZܢW?[ݛ檋kzfv5۶i1q6^$|Q_h8b缣>h-88.ZUsP}qv~OŶ;kbePʷgY|A,Ѥ#Z7,_c-huڱ (]?ڪIY@Qnv_n;r/Pmk0 vYE7ӳK5]7]^p[\*TI ;mٶIyjɄOXqTU{=~pAܮ*6KTV Yʷ5&7SW̥ԳV5ZKn2)g`mUQgu܁UrZ$wU>MёѲ>g#J(Yr >yA6%h]jڔ.SuU2yhJi,];P/!YךS 5g|.u3Ϧ1Hʫa*M2yaeuiQ:bQ*.H`|AO+<|B_SեE2&Q<#[ ]ot*{RB֣Z0g^·M*Fߵd~X%kA-DmYmli*?uZ!3甯gZ$,sn/yO,fYdfqEЌ%{tISΝaH)zBM~Llҕ6$o>pf1f3$]* ;{ 0v͙>W~R"[q%#Ðlt9g8țWަ̝WAdΫ|~7blVn\TNSfТm(f%9JGSoΣbY|RKЬ=5w 2I2eW)JLH訑ʙ,%<gH9# ]vt.XJ%]]RYVE\Fe]N# )I~zVwvr(A2s[x0R*C2UȾTܣWM];lQmf:ܕy PD~_S2.WkN6\UU"t`z #iS%񊏏WBb eS u}'Zv"QFmx>X2j~զkG句Ꮵ/d3=gK_'adlfRbۊE6uVKT/]eV犮1x)6}L&{pQnz7۴UNknEIf'ԣ6JrRbզyEwL-M:9LcQVϫ}?m$Ki{~xiXQ&*&n}B]OϽʫY:p=aL}-;@U?A a:3tTrR}z"l yX dt.-룖vS+6Tשɒs(Fᣛ o%/[wvͷ7I8kvh9Ymqoo];>Q"TD&+[mOx.\ rAK1yK/;}VsmͣiKѻ=Lٯ-{UQ/?8[TjUr()ZRJfvִܷvR5ER7b߸fvMq0trVzQ+~ܝt\2ul%*lq4 R呺7 ÐwZbsXÁ usxC$K.UQNCU~3B%)[.>CpY"zK+ܹ 튦\f\ Kׯ)qU02)h-|1H.oZK VI)5Y ݞ| .%EJq>*U*&r Wj^t~Jq*&/S;d0YBo 7:5VPPj7Qc;3Z+j^'Dj6ғ[ti,iڡ k& IR±ezMoRM=~[^Z U_}W^dCQ^У+(i~YwKEpK':JhPUWx` еiH9+[X^Ys'e_M`Ԧ맑; |hf5[/Orz XUg4dWUM=ѯ^Z< &Իw5/,K4]>j7ANUy3`=6W{mo]02&m7C?ux8VS R; @ssFl;a\7=_h %dQֽXnQdyvYo15m7{Lgfz4Oiv}4z=U RIyLI8rgktͽv+(uz{z"Ku&w)/[v|8\أHK?j3!j bIE_. Ժ$n&~-W^uFІI0dG z|7u:w5lZ>k6_U4D_ O}hJ*GPjJξ1zoIUVco(ZZ>it;GlQ7jCW%2K^Wڥ*ֶ GUtpTXo.w[yx] S|ʪ\A~ML eT}gJ5+%y},C@a=Tsve Lf #)]M62\ \KA5ullHJܫu{LΝx(EU*Tf~SM;{͇xS:;]4$Yk^ZSܴM>*㳾J?I答kiZ3~MNU!~;jq_򐡨obtvoYIGf ze\N;}EkG[ vf Z}iZԿAn&%mMCgo:2 ݼUg4UwO\$XQ\-;jŵm9jO֞CZu&7 ךUeS4exFJRܳ92f)i]()$w^S.x3V3T=SWo{kf|7xqY?zD;eS`9B 6VK $hקxW5 x_d6~"E, Ȭ!*zh~J۠źfmF:j(DZZy\S){q5^~ цW_UjMr/X m\R'HGYSB|YYX%jӢw}K)PvI ڻnZ6%dTF]ղ# IDAT[zv%4Kծt0u~,^/7( ; ϔ%j(dRڪpI/twT9e{I-geK;¨Mo=YQr,_q/Vi JM׎} (bRPիޯ5CJY3d1$yꑦϪ}:yFW`.ܖ5RΟѶ-0'A7Y6% ɽz:UX#ڿ+csKz]* ƥ {#zH9]sպߢbs\0luY|ʗ~Y~|e~c\ѡ%34cfŔsjЙ~̾ gQlL H2+XQLF?G+_p Ԇ6wg\^Ywښ)z~f@Na_B/,m3n/ KevEN%ٮ(6.vV 7%'ꓹuaW/rI2Kƥ(Eۤiŵ+uX{zL:n>;eNQcwX(ӦK,.|Ux2E=45GjE|$xDO'ӎN7^jB%oZu>-IwЛ/S݅[٩xnT]NJKIJ1{({V|}agD֬%&D dTZk{]5(m<()}3{TX$Kp*>h"%#V~XgjGIRjYzfQlv~Z9$O {JCA |L$:W6qUb (WA%}GІd{R$%^OOKb2˪+5~$8__MI:~Tú͖8Wk7ATkoj`bְ*b'HBEUlZ,)~+KYE.MSjkdv:^9L5r:̓ hW٧չK d`cRuHHR +Q[IJ3YrTݮ6$YJ Ji8P1&,TINQ`9M95i<J O})+dHqU S&uT#pFWtpumVGTWHx;f;j:DΪ KNGhԶQ7TKOտCjV^C?}f:uM~1-HazaM~ VzOϼ&,S(rjܨZ/җ'hZpoSsWô%xTPmNHi_kU;$XAj'$ҪIմnmi# d(n1\jRp'a1.pgul!ͭڶ)߬U!vf-Cd_jS:rWz/SZl)?k({x[d,vO:lQ9udZs0ZVO- I8z%+brvEW-L U˲ٮ(U5o/jf_ea&,x1,aju1JuJIk2),|~/P7Y6% EEUYKLKE_k^EUI^^Jd̾ gQlL(EFj˛~-I-o˭zCj¢x@+YS]zn48#jl5)hpE)o^]8wAҎHOfs.xYПdY6i˱7LcLA&*[Վvfp&2ofx0:)|}D PtK,:iwEo7@mǮАݐ_!(S/]9F=zPޕo0R5!JG#ԳLTVJY6C~*R,ܜW͚Ur(I|beUC"*ڥ}S=EGgdKԅÿT|y`O;SIi|oGdH XrΓʉcjդ PZtlJ34p- chS>ݑePJI8%qE6ɜK˕R^SX%E?Mn>J-[1YvP 7I2)wާVi:j9U6EVd_[VzBժsӴM|Է#޿gXby #4β,~]Mjj:;Kt>V*ܼ:-R: UI5ԵG%L5tij[0Tj`-zQAuCr)9NϔHʦʯil0UZ㽗dcP кj_-;=ۺqmooRL~fC۾%;6}{w9&vPDms.U%q^ 5)`^]… w.+ι$Iǹh-m\W~طOau8[TjUr()ZRJfvִܷvRm#fXofsl;i&̸,^MӲ\%3P?x %n'\g+KY6\N㡰[\.., ."., ."., ."., ."., ."., ."., ܜ _ ,_:\Gq\3.pGgZm7;u***:q3O̸?7\v9ÇU޼~e}G\}F597cpY̸ѣ;ovܩ3gJ *!!zsg)]d7^ .fĉ:q-R;tР7c 3zKڹkL&:vhګLGŋpb ;vL3g|Dx1ָ=3fxܵKt'1lʗ/'www|r1l>s.?yCđG`BL&M8AAA·  Ҥ e2ł:r!fCv Qù; ol6Λ xH\رs$CN=ױ}I7n x\}!;a?~[Ç,  w~!!9ނE %ݸ-Cp{Νe6pbڽ۹;]wk/e6t2Kc2 C b7` PU/ x92荁:vvڥg}N=;zȑ#G`B-Z P͐9p( www͜Ǝ/,Epbd6TN@g5t`uAsӎ;uYIR3$DOw!I)]Z# s.p.HufZYvj׭\g.DEEko;]VTTspa ܑÇJWPTTWp:57Č ಘq {e\Ep\pYe\Ep\pYe\Ep\pYe\Ep\pYe\Ep\pYe\Ep\pYe\Ep\pYe\EpL`(WU\9 CQztx905ݯh}T\=M5dfھAKesʤ$S#T襛s459zNI%IVն Cm?>V﬉.7WЫjj`~^iݦ܁UrZ$wU>MёʸELʦ"U]t8ШMo=YQr䐧dRE|TʩJ, PzNjVeU,IJYKGsT"g){2H7\ =QB9̒{05d xW)wZאtݯ5-D&]9/N#HJSfТm(f%9JGSu8bEPJg g>GWo)>93S#Uz-QՖ7k}9[l9[(>-0_f1fc: ܚ*7ǕRF6KEݔkdoj(Uzl:t8ta[iX5~7\A ذTOlW.ьŵR IસT'wi՞#:{9A)x߷HMe).'鑊$]?Z+jeNb.*[*clq:r:/q[6EYbe"eU۪dCSkoRB9,=9Yy] ĝԁ#Q\ 9f\Cj< 9qAR<]Q5|}kG=ݷiTVZ;r6+rW.pmW5QC CWUuweQ&4~wiECٲyʿrkUUn2k 1L'䖧B^+|ȝΟqm>|}$ÿfC۾%;6}{w9&vPDmd… w.+ι$Iǹh-m\W~طOau8[TjUr()ZRJfvִܷv$ámuhi5u}6c۹Nk7R."., ."., ."., Sڐ IDAT."., ."., .rs.ҹso%Ie@NGfOjZlM-4d ysSpRsqqjݶmB.[Vm(6.ι "=7j={NTB1\#G W $IgϞ1coxH\:w\L*hyj߮ڷk祇K.չsEp{ʾ$uhNmwwwuh.x,✸bb?#Mbbb$I; F ׏`6l''&`<}{g^DDDDDD*9 r6N8cIIMk|*Zxw>f̜ɀҥ0\sw?GE )3ft? d@~<>i9|03gp8xпys@Tb۰agԪYc6m]DDDDDD*]y饗_0 ~I*UdQ2,Zo @ʕy'0 fUDDDDDD*.Xv֯[׮tԣdl+w{k֮eݞ]EDDDDDPBÏ>rO|Ӎa͜鞿`DDDDDDSBڱcQQQ3]waSJqDϺh׮ڵ3  ȈHyKEĸ]m G<DDDDDDSBZ\\{ushDDDDDDSBZu[lȔ[z')TֺukÝLٲmӺU+SVDDDDDD3.l6ztvqL=Jaf!"""""" R,}qO7wGly=t޽=2""""""Rp!}U&} 0(=࣏?V͚o_S)Tb {ԩS̘9ԣ̘9{AAA""""""Rީp!6hҸ1K69sXw4m҄ˆ 1@ )63S s+MJ+WfꔧZ,"""""Ri'%͙v7%|cU|_/Yn̔)\ܼT*\Hlȥ>f4^ze 0k׭s+W3ݫGoTRѻWO3fKֱv:l6m۴aÆ @bb"Gg6n侏ˀp}ԭ[7O\DDDDDD*..ԫW/ʌX~=yEо=>p?-Z0DDDDDDSBJ]-x9>|e˗òe߰lsWh߮-}OԨQEDDDDDD*\HQ׍u#GbIJ"11XbcbZ*ŴTsbIdd$52EDDDDDD=UDDDDDDD """""""T…-.DDDDDDDop!"""""""~K [*\RBDDDDDDD """""""T…-.DDDDDDDop!"""""""~K [*\RBDDDDDDD """""""T…-.DDDDDDDop!"""""""~K )ruq,0gR<*^m7gDDDDDD 0|f]ǐYu޸HGPDDDDDD p!ʪ/#Xh!"""""".,66W'S0;bmϳ)y)ȵCyf@wwJ[f,)DЋpؕ7H>]ӟ]sW6>4;ѱdzTS1 ѕ2rp7u]tOŀi۩Ѕ<385Mob x z/IVͼW Wwj9mmm'|*bܫ[rnԥ|̟@Ә] 5RB^>5EirQKxs/v2Y[lfDXa1f".Q zՔIqUs] kӧgܼYY*_`jG08f߯K8~̦-qqc|U ]oί,XD[nu KH}U,_EkAz!X}[ܟ>CDDDDDDq!~_^pϠ##'gu,[MڧP FSt-jÎUV#k#Id/#{d۸8=Ṉ̃(ƺ*`%:(}$p4Ol/dneC5%lV7&""""""J 5Pzh>b|qOy բns w51>&J G!wTN-<T#:*+-fR 'T(h""""""tg8v0P:lj_ߎY۟/9kVbz xvI;8pҀKs>fg9y_Ph!Y۬K 'u?v'RrN '{ţtVw|qBx,x۷]ߑ<q#Շ2߽ ҁ6s%L 3:lL3PwL;_frLmw n)"""""Rz~\qiyssO^-8 pZ=<] z6iW5_xrʳhLfDbccakS!&y^p}Bbٸizt7EDDDDʅ?L6mQa()Ӽ+ǼcȍN\7O4ysX:BDDDDDDD """""""T…-.DDDDDDDop!"""""""~K [*\RBDDDDDDD """""""T…-.DDDDDDDop!"""""""~K [*\RBDDDDDDD """""""Tsj`xV K[9 "R.b;;w2DDDDDj咋/6p!̩S9vQQQ\PRкUKsXDDDDDPBʘ`_ٰq#yAAAkۖÇ1d`v%"""""rSB̚k4vmNegg_X/D:v`&"""""" .L_pc4"jԨÇ}vص{77r+7ѷ^NDDDDDD*\H‹[urر 07Ko~Ϝʼn<}EDDDDD T-X(OfW>|E E_v|-,ZSDDDDDD*\HIIM)S󷌺&O&88أw<5y22e*);H…z}v_7DDDDDD=.Tdee''MxV6ZL8ˇ_ǟ|ʽwY""""rZNN;iii攔АP5jHxx9 !1SNS'V+aaEK).T߰?vmҴIS5m҄vm۲aFXaݺv5wBl7ԮEll9%e,!!={Шa#iDB+Pj9%~"33iiX,Bϙ \=ݣ{wޭ{s""""t-D\\'Ofy˩Sgj~BBɱy,xtƅ/Ȝ 껧=-"""">2 0G\X9Ҧ…lthhGxs""""""TDJIʕ)uo4/>:9TTRQn;<2gs p^R08)qTDJEvwa?=-""""=. Ҧ3.T\Ԭk௿;Ù]65kf!""""ER¿xL )G枟tRRS=z&%5iNwϏ3)W ?j~ p!+A}cL:̝wɓ'M vIn: @ bpS/j~ _7)m*\Hl̚Q6n䚑Ǯ]k׌ 7ǡ0yl6;CR'i6NլۗK_lټd{ɝWJn)i&z~lصW^ť1iݺ*UgXl޼_}%K14is""""r&\9}#^`)sl nechEٳ'm?l4܄H?mؼ6m[t.׶DSa Jx͆Էb]%9?p!O޼?gw{/G,XQ*))ͫ/L˖-)9CσtKUطu$qW-y4}~+-:1l'XC"J WKK(Q131 0,j*3z/ R&Zjɢ_Ï>";;۝V brc0EDDD ʂ՚;Y6\W$YpK<pt{0 `Sf1 0%}[ڝdޘ[X3x/_qn>ʮf?;NH s?uA Y2Y40؉_Sg/@<݋Sh9 /]9|6sKLkFL-m#(_GmX=8F: ' KY{%gbBӘu;VsTKş' o܌}{ 3 ZHfϚMAlHEFض.:.!U nEaXl'rLmN9ߤ1VlޖM>H6;4 ,q0a)On %f4Fa' 1:ϩp!e&""G~[n/{;@(5jHΝ:dqqq5HfLJ>ɪK)77QGG>#d+,[/0͝NMr]CM+8I_5Ic Z`7&>̻fL&q څ=&L7onWL}'O^d'BF8 zOqYe 1-2sYm4)l듢sߛcyuM7CT#pkr%r sXbMcd!ր=Ft }'ݔͷˎ.;Np)[F;?#DFr8v{*GNrx|l[ ZpX2DRHa/=9 R`  M2vÍ7C^LL\(Ȍ%!NT(l8ȶ'{J6} QTwSDZNۨduQ$cD4Ja@`l 3Ns:hR6y!F|_q:?)E)),kyQz D~quȣpbͫ+}|hBK=MAǷ|ѯ3^-|/v IDAT$c?jzlW[ >_O0Z{:[-miW<5&xX*gGȰ;TҲ˒o]X*ap`YTXDe$q 1p˻DDG ;`'A\DV~x/R10ʷ.g;5IiR222OYt)۶n7wq`߿M7ŗZ\ܼ9gPR%b""""#_/t6˸85uلW=/mC#*\}_TÀL~_~(Yx04fx {g3`n 6yyFw378z34À*17pGP{fCu9I9̴30=خ!t\)e8K\8|LDtl{wVl8V+Q0c/;8倀pj6*A({V#>LL #*2aԩj˻&4MmP)5b8jcuik/iJx[~ϓ糙0s==uև˴yZ=<] z;wڕwW;,>,Cb>[Jȑ$NN\&MPF sm}Tv~W>?88s5U8Ѥ$*U -XGdDՇ@NnLӮcޞ;⚷{fM:b.x+Cg\H/yn SRīӥKwF۶mw_ ٸq?\իIIuyᥗxwzAbxeEDDDdE G<۷z ;>64>%׭FF6*;Q^w8׿RēOpnjj-/P$¨[o寿6r'yһH\J~d)xFzIIGg⃹siٲgkٲ̝.^$%[n%>>SDDDD\Td5kRT6q$> @ll,j4*=jdya&Nd%""""xjלHiRBg_|տ»{uzz"$$U?7J 9cGs3OÆ =z rq !!o Q>V __ZFV&AAHP匽lRSS>nzSw 7?aN8 /g1w9o]Ԭ;vd=攔07O``ޘhDZ9%~"8(EK).$''pb|bU, SzC.p%<4aQQQ""""祪UH /VYX,3?˱QBȧ}FVV}z . ݫ?,[Fvv6g}y+,,LrFLD3`On#Ft{O?n{dEDDDDDQB|mosM4]v^hڤ |<ꖭ[M=DDDDDDq8Lf*AAAz*UO?q8B/*\OV+]:w6V6{)N…-.DDDDDDDop!"""""""~K [*\RBDDDDDDD """""""…aj"""""""V…pcs%ANNv"==ݜsnN呓oNZZ9%e 4$FyJH'…)vE:^ݜ'$_Qn~:kgNIHHH`=4jبT ]*RnwDZqq|nc8Q*ZCqqqΊ_7u =ھTF/NU}%L8ϋdHGb> e! <Gu@{/UX|r|A/ R0ꫯjB @ ˸˱Xl*j,[P~S("bLa;ԥK̉RVv-*W]KBF}hB|l2Sm6Ѭck ?簝>Ŗ-[K3(9IIIy]_[oϿ?QoHJJ2/g R?@ϱ0ou),W.Ea;+n{?HALߜ{Df hAr{O}Ϗapt>dw3e.W} |C:tB0WyK6쉫ymܕڕ. sjd^W;]:ҮU?wҝanƞxtؕSzT. ޮA6=>2=:ӶS?ybf}G;nb{Vf\ڇWS>3H'mnC[xmD>ۿWo@_KR\,?s?_._s$'}E_:kC.}6)mNc˻:sq|F va^gI4paLz1+wK݈Ethw_c?lyJ ls<>`㞯fš_939Ev@{ nM)lX;`߱U! #3# kҴK^}Ͷ6L]k{f1-Ã}o? ZOa(}S_{aq?ވ1x"wgzD3eWs >/j0;oNƶVOU,{;ksu"kV5/WšzKZ^؏Ⱥ~h.85> nŝshsz)˿yk_7)Jvv6sӧyiu;w}tnVzI>w 3֥ytt^)e0B擕ŋfI_>Ob0۱;j~| MdRlaVBlEδH$?`A2]xgBk&vXzZqsdnau)6yʹa itsIe|w7֞j6j-7trn!R︄nBlψ^+߂ gdpl؈lۇN…} jˍ;m[8lu1jTB`^mipp"ogDDDDLe231s l|}<򹝫/$*4ztI٫_r02C|G+%axStXp!̔)L4 6cZ~u,X0O= N,>bwqեoM[ߧ|;8hzM:Ls|=c>9AO|p ȐrbCxpVxFÃߜSt_ɘg7l[|9^[[ܛg$U,\] y!<,_/?R#].04"')|HvA=דpq, =}FPt4D22mhue4's V"cyD4Ձݑsyr$'J WnlQ1Ts/n!fQv tLDDDDΔ+}ٴ ?ʕ+s`N]<Ȕ InZsGQ_gɵw>.j vXh֬)'K>4s)w.b鏗>am;wOTTWoyWXb޿;D9^bk0Ló<6\W{+yuy+臢8LKi< ~jHa9Ov缷U-FqqV##߭ԮoBЮOiw7 FtTWN[̤Wy5"8 G8OpҨGFUw,gC/GAxn Rͺ, rRmtl zѧz>T8?l pyupvΎ~Ozŭw7q;soYZF~t;830˟>#(CܝG)yIXn=}{%22Ӟj[{Rj8֔c$;9p$㸥*U,1 U{=ƧML/N[g5`n gybm۶eꔧ8i78yԯaO,,Kxd ƣKطd![r``F$efp8p760<>'΀a9zٻ0z`!wa۲SmȱT~xj nlko[s3b>+s](hySPa'sΜkz#ya-~pI<_:e-Ȟd:mC@Eӵm`Z2[mg5h۾]O yA@=sl։Z2i}nM};Ӧ}W9|+ (x!y$6s]E#1^ݮ~`ƻZKg `8Mۿ;ǎc߹랻)SYm*hGX[)͎8ҤXrcV%"?=u)=e[g5?6te<k׶S<ͣc; rY>yapn!價s Z΂5i:7jY 8R8+g""jy'/Z̒ŋYk[f_[<_h$*2˦%Kc}uy~ kż>O [GKE |?Er͛31+G̉<*m :=yLjwl3'dFÙ2o8SrOoBpӑ1}3<yd7y`W0t8=YvÇƦa <>Y[m.{c.{tV񒇂YY,ֳ_ypV 7tgOaY9mZk a3LjxEha.y)èm58WukX{~XFOEk_>СCYw曌vgq WSwCXғ XS{ ﴈ#ֽhf̂9}pψȚ5 ޷_O k8o_ȷ7jxۖW02IڷZ1/3e~}z?~=c]GBiZ?g/עƺ1-ʙ-5Y0QP?yd{xğt tQ~\KLL$66v9yO ,qHIZz5={0 O\xԨQÜr[bݺu32  p"C׿ˆ aeCz|)ʕ+iҤISdD䘚8 Ӯ`iG!U0̻ q2|Qg\6OA~ w1(iu,\.#wEwR^χ]rrjY4 """+}5'ˇ^C/7l~1\Wsyd7;#6J1^p;|ЊAy"~zyGҖ1W֟ރ)31s7{9W  o yឯB+mZ`0n3""""ep#gK*hj6 y_:W _=5o>sp#gK2]Xל+hقwJpaP.cyN,d9]Ӯ.ǯ5״/昋y…7ܹrrsg=*"""""aH҉yZ8ל[KIDAT…A+ 8yapiyWZ#.~h7su^xȟȞ6Q,9oȃwCǫ'*e=#?{ڍUױ.:}u'}iÜލGRu#>[Zk1|{خϞ8ǵspؒUIS]g^=WZ.Œspq8}C_3qͿk[uk]}+%ϿԳT+1-Gة}ץͧ-F[tg-y80V=+ >ד!UG?Fe\:UUѥXY._5q\w)k~PLUUFsNVδ":ͧsbn-'.T}q:7UwUW]l|~՘1W̗bګuO5УX=cy8jة'Aۘ9 <*湜\(<꺑|i_Ϋ_/<794y5.Wuz|)uyQ ~G과o˘xa<=O7|_Zޥ ]e(uŻh=bť燦?%yNkgLOfSGWE5u:05u9X7ܛw}Xgky?CË<:u2us9+u17ʏw{HM>S %h/POGT]th1Gzݼ.su彻<ŒǺ<D٫%5v1zS\ӕ}˽1T'wK=bև媮i_SkNuՌ3~a©.^Wk:tes?551cѼw=`hko[b~B>oHDkk{ `{(~g\TۚVkXYTC%uY׿2r䯈֧:\<5/:(Vu9Ly1jB1ksZͶb|OG5*wGU?͹:˩.OS+⏺'/4ޟrjX1;%{yuPS?yXZ>͕Ϙ_(^{ݛ}TlQuyƜw|wu1sܣnÄ<\ CyҽVwBGnփ5zl=>٨XY }AysW]FU^G{AEZW]3xAbU_{G^9ϯ]~s6xdqźS,g\Imw.2[?U]>Qsz4,tPuTԜ'%r~B(ܓ|g]sI^}d;dPAsF~(ռl.^S]i}(n6?xG ס?Y5i)QsL{̯|+\sKxc2oq˞=bxru9@S}=\OQy~!Ӝt)V_y봖]V_|:ŪxLHg^k}8?Z5'! ?'GcCqd5У(?eK/@CfY/LVƯxZF:o仦>9?4KtF\)j29<ǜwԮzzSFyXhbU/U[aLuEGFW߷((xXwa.eP!CչFu>"%p̉3XΗjGVkw5^~)庺@xlG#Z~W\6[U}@?rȿMWgźHbe/Xǜ5ϱM n k=ɃI]|)^US]jwNL6k߇bs]me-_5w+edTOd\1.l9bǶƵ^{utQ\FŻ=չX׵,G 7.j9ؖE]lit,:U_sKc}ϧ3F=9rFK9ɖz\u^.kj\5Zc9uQenp7]SkG2Rly9Z~F;k몯ݘ̯庹s֜=;K.G7K[Iw\{<]Mؽtmk޳:7\\3q纫RRnܵiG_g.ϸ}c]be-Ҟ.Ū>GdQ<]9}=to~-[ϱ}\GQ5ޟsTfhpsKM׺Ϛn3,ˍGfxt{ݼۗeXye]Gm{ZdMr]Ruu9[ܲ~G4ӹgg]aAgۓs.[r=rt&l|{KM׺@U ]L2[gwqj9XjG.Ū..G庘tu9#[wod,,t{yUTR3:Ⱥ>R]W_[]#߭ZWÁCn_b)kk5j3ࠋQ2lZˣ=ZՍڪqhF5yge-䞽i򣸌 Fs7ݨbuUjwyt3{j/3FuU&z߻!hkYMZ'Yw*re,2^cԌgkm5z{-k5k={n=瞽i뽶Udz^ճ=vk랽z&u%{ﻷ~zG5{ﳷ~{{އxv-y{[<V~5~^h?zG!S3{{=>GzxϦt}5̏z/x£{ڰ?}?t}'4:ó:ӚWXCS~?>C&@\|3pnG8RpODDDDDDp,}*m!]VKDDDDDD᭬ euw6,K1qPZŅ:NHxwODDDDDD"C_=T7T%""""""*PBW%u_Kj?%)SI'ÂcI'P}<W-KJj?!΋޷DqQDDDDDDT/@ŝx.*\_oVJj?DDDDDDWR `l~ p[g*}[u"""""pUZ`hny(ξ3D"88seo,G&^0@rTqS%"EE'_c@ljo_q_c*>:D(/VcVqXQ(8%P?18{,E_9%,E9vQVsK*K0s%""""""=\jNIQESleH VbV|GDDDDDDW1.W`,3|z.hLG DDDDDDT:-}t1]^1:Ks/^({`5}L}@EU#""""":ەjS:5}̟`_d X%uԜ`h&wyl_G1_B_$8/Sǂrt1q+EGDDDDDt(<ݸ.RsԱ`:?h 8 j~}<ԘDDDDDDT6j\ ydX}4BXf}1UU[ƃl>P9DDDDDDg, Vm<}&7(^@suyVE].`cՖYXuƭ₿q_3(goոU\*$XeV9VmU._ 4.7(\@¹j_qyq&RUBj9tE[7(͵hnyA 9}5OWLP2h[-Xj_r(EuQrjm]JI% @HP8Ϫ(j!Ŭ2q] LjE՘..&S䭚X]HNB tEw:u[A]Q9DDDDDD碢,9V5t1nE[j[$O[)鼀b> jPxLL_mYIŃQ """""* %Gq⺶V0X }VSԾ@ X((9 'ous帺?5G݇mն`5`g.QyVE:jqu+Mdr\[:W:%^`si}V7߸5_S/9ʬƬ1"""""s՘U/u"n_Wխ׶RR9P儺HWVSSr[nj[/Q8tB^S<„1Go+tswL>S/}o Z-XB|VmˬV6,e|9.lr}ukmxjLWw<`%p?_cnA}yH[P~+<&bb;HLl>&E1]@\R[3QHkLli[AV1_| JI/r}P0j\-myZtPԹ"t[5&խԘ8߂Y zuqݘ|Ņ<)tstcVŭ:}츺d\ >tq_*f׸1"""""1@h侜VΓcr[SJU[[A[[)_%_Vub^[19^I(cq9&CYo"ڪƁcbkU\䛠^uq5G7&o]ܪ5+*RŵP("վDDDDDD卿r㢯y\n[?DҘ/cj[Ԙֱ,W\Z PԸZtPc,ty"Wq"nqU\gpP ".&q](Nؤ}эbA)+.Y jAA01]sP]NLtaتz򉈈JiLK]b2320\Qt08=[xⅺv 9.㫸 (" D-DQ1*TmYZvl1]/+d A=|q7 Q$&%_S5#"""""""kIɕ:Y;:)&ء^!ȫbOTpn_L bLBQ,瀈0 ֭kZX!Dn ձ`b8xp!? V& -[AD[<&`g>? Uʱ#r{O5LDDDDDD+W ⅈ<qy,hU(/*"QPP E . dBNN&`3ecߠ^auf"4oiiغcVY[#.O[.PybLՃq/yL͗.\ʼn5&EIŸhy"f`SϺxU99HsAiE0lMkvŨV""""""OмI#uj@5йغc~ _bɆum"b+:i5nL(…ȱ'S6hᎩU.t$y987-._ȒX8߅)hEDDDDDDgMaҼI#plݱKkX]B1 ^V"2P8lO%]E>9r_15_Pst7qz0t稱!#q pt m?0^ ]n;elDFFsԱjլ8t(XEKW //OqvUzE bl,gFšÖW^鹉ϸP'&r\\ O͑+S!S A=\Qx7A\%6O[h r,1T\&v~\4f &}.+Xwu%pa&DD瘞oEk;f3̋cqq5%_ʕ0őH!s͕㺫ij/G*1qtWjըEjհbgj Y)** ==i8xvڥ3."0,/ZrТi%mD P16Qc^Z;|v rҘhӗպ/qIiO Ծh1/c kdD\0,b-60qysk2ToN/݂o~k~ϨaqM0iK.RVjըۻހz>9GGB j* -$>)Z\ 5TuF|j`~0 (~6[~%Vl߹{?8\ra[5vƤӰs?BfVvNC^n^z=lݲ9Zl֦es4o8MĆ, 7q+]Ҽic>3zVUoܗj[͑b!WZW\X=85eiq *`U-4+]2' @*ڢ>NUBtԭR`W4]p\VU3zvիh!+ ϐh< \s_ffj8~")i͆/Aff 8XV v~ˍXd:i~ oH1oL3VFu^LDnn.r4_k֭WS*o*|uiATdd~4_QQsЬI#aաi/ xq{V%ÿ/ثߢi:&Cmk7lܜS":] EDu,5n+BSUDVBPOV } ɓ(P.tL. GSvF95Lqu[ awO^n.RLfϏ?A󦍵EfSDD6L4acرk7m{^듦q~z?dխ^oCJp&i!#:^v u'TJ{oǒeeq/cPjL}k}|"={nFF 0edQxfxE6-㩁0vE:ЦesCRb"&<6lڂUkv K.ij/CVNW}wsc3p:p:lj;c8.Z| DD7unUoٻiZ2Hx(~(;457n3Y:܅O\Yss6&] yBaCRjUȓj^`0q"%Y٘T5%t3/WXph'RRKc;_:^PPP?S] rLǵw4sI4XQVOږԘ(`+.V0 " c)T20 Zs}UP ߓ,Z;~@&1豾dw\\١=7yNbӖmXo<)f|1 >}Wj>r`Ps"f3lwԭS<9v`+W xJ*g~=^ 8o}=_Sb%A[3gc܅ fJmuIcVSPk K +rBM.r1.*U #Y '+ &L89سDWbjf3׉7HO퟈,ѪE3 _̚3}&<( (BQy+"+S,\KwU\Ѝ'A>M GnGŸxTϏUC]wN;j4yܝB'""""":|>s6>y-M[a0__lTyvLrB-Z1y],b6x_q!yVƭ…J>r_=j<-N-m%.Vx%6Hݱ w_A-q嗢U\ %%nWć[e5Q(Zumy!W qUj\=r[ "JC-dsr\ Ñp 黝@Ry.( ވިv/ViuqAΓcVUTp!N?rC=M~2ucPtUCEWC L[[E䭼@AQ苶L[+BOq㺛ZcIDDDDDDTYnVEL7.\zTM}౪s"st79O%,.G'GUO>rUJ`ַr_A r*Gu1z{0wHםD5G~R‘XPWm[K sƀ xrEؾ}O(|$'}%ֶ.OH^PLg+JĭED Š|N 5(S/!"""""" gV^՘fVsuU(R…{j[u s@DDDDDDTiD_&7^dh=hUE[#um+ִrLխ:tP dXe|3DDDDDDD t+}Y qvuE{2V>.ެSDDDDDDDF]oQo"OlVP.\'RʬݘVs‰Z-T꘺UYKMi.oՖVn-c Vu+1uUہC :ur'X7Ac?߂w]:j+S!S, ҝ'Zm:U?[}fn,TXX Ez'Aڊv 7""""""p_nhUc/Sj t^@'[݊v OO[@S!:E L(uBjwխ)!Zb!S҅@N.G}-D<+Nv`Hxt97 ?֛hM>6 ؾe2JǎCjpMp N V׷Wז+ VyߦP=]"w[aE v5uͪ1(~%5LnݺWTVR[ʼnd-}w<ꀖZKo"""":ֺ֯:V(P6q=y>FDDDDDDTֶE]W_leQ(*_'jLqq""""""pcZ VqXX)t1" 5[t{e 1V1vi`CJՑ-<,# 񱈴LBEDDDD kY*<ԣ=j%[X1PF ! h W1o+Eڞ՘Zso: t[U<88NƦEa%wL*G_ kN9?sM+SX?}O:< co?aЉxSN0?.²_Hx=,UN|ia徻}|;~bw uj̞KV o܃1R@׷5e'4Q1OC_.Zl6څS[>dz/~yU-2bhދNYp(E /&r'|c^>_U0l6،G` 1y8_.Zx1k] wC1h>ÛpŔ0E'Ƕ1[)Zx1]Hc ^""""*@׳Y)N &JCb͚5;p)<܈E۟Ç-ŪU+xC܅0m1#.:?f|K,3ƢODW|i" DּNܟ`z@\UyA1qzhL]I{j8~nC َvl+g!7U70s2\}4_Zvfk?[?aCb{?aʕXx6HE&;bCr^ab,]5<u2HMI 8t}⛡E]"؏^:d@3xLCJ h4i ÀF)$"""R׳QR 9$$"*KxhxRY(ąi'-~tŃbb|+H+0p+a$UBcp"=p /O0숋b"""K… N4w&:HŻ`Tf\An/,E"GB'}I!6zT|v[xjö"]GDDDDgnM|6.ʒ|ILw?v;:^-/ =חp/\ljӭYp`X`D4U\X?M߯0uh=6 O4Ѿc Dz^\~ic/iعa`G |c\B enQǴNN-{oy]pm;n9NDDDDaA]떛uoΖC~rIu?e-7:۷ f2la҇x륨-!zB k;G9ዉp7]<ǘYؿ~9м` N[\X?FEqgS̟&:} Ch'ppf]+uղwi w ``ǧC;qwЬf÷ߍnWDH82O]ظf)-M݈gmu ul)8 u V@W^\$htqusGrws&O{M}LNJǑZ?W^bMdy7-o!IKp"7ފQ\)X9Eb-8޸H~[Ff|k}H91Q0 0Ob^yp 4a0s z7<=sø; F;t16#>pYw y B- Z':/Ż߬ڃt$aɈX83|yEXoyl iĒgO0oq^+p8">uFM;X0eL)f<Fl̛ \Hnu;F:&oĻF})z|ѥ~_Qi9@㻟A g&{w@eHAO߀ C0o'5`O:Qmc3?\'0) l6.W_ 3=bcfQT3*j+0]/oƧߍFu{a_Gت4M܅˰qddc: >Ŋ%+jӨXL$L8K:ˆ?^5b;Q涡`"\-[,0P;lR| s_Dù[Z?wxe ,*ZĎ;ǝ0}3XzӘt2r>/&|8,fk~_/E3|"L L(>Oz_,+zr)Ob 1foX;D}&[5}cũOZb' InѢ(b7WDhI͆׎Ļ/݁ 6?erhD't3zyh;#su3' d$A7ĬhZ+6$TEV>OcgBhuzBa0Ԧ>GnUj5E{)+t >_~*Mkʎ ɨ*|]|jW٪bgahθQ $Df!*6 5Uų<"""" 4+1]5Əꇾ)0s@K5 )~)ٰ : 2lW}Rӝ޾ZVpMf+}/j^ |>f؍th?ԫWӐW5b J QU"p@Zꨖz T3p"W Uw .iWH@B etєXL&&rx 2EUPU|$\Ήu~ VԾ uB,nx}9|;Qy)iU jw.Ğ ].#ذ3~3V<wA/67C;:dެ?f쯆 UX&""""*.V_t7FY DU3g8mSxv5xWpa=g-b Cےpf'Ndtǜ'qڌ lrUT:71$GQ*`s%#v2 60MWA"+٦ZB"*Jcx.N8kDDDDDDuQ1Xx=v9lgN_/܁*͛ %&!!ew WVҲ+Iڨ`9~k3սZEk阿/&rqx!iټ%Efn_ QSO"n 4N lW{Nj|2O9me_wߘ8Y{ûpl~~gt9L76abcp"Kƾ?k\,HmpiXs4&L82aN믖Cض3&L+DDDDDDd0b:SmWv}ccxwň`oqw W?lt#=DDDDDD?DDT^lܸ 7mڪCTXdggɓj8,EGGB j """"" \bkjLMo/,\P) lR y5=D}+ZYLwGaܜm8 }.8&L{$F|Exp~zF^sDEžWA:\DeQpAAQj\-^X(UVVRZ5lR;qƨZ Q~RyoB%̧p[sט<ێ>pDh"kp]{p<ˆU;+A5(sf: s.S6f*q޸iι~\7\'MKX jAC%|IHHeM7tϻQ9sǡyR]^U1y Uo0v;OaէWc!b"cd<:WԸ)9R4Hp"eF6#FM/7Jܔ&olLhE ?Ļ[X(& "":װpAA+@FFPjU?~܅D?~vvgΜDFDn`\> L.U cb:o RJ SGmxhsX.^4Ҽ jom_Q0+Lx ܟȪmx*bęMbpo6qp]&y ۖW'@x߆/'†[e^ L%O~篍:_0bíe՛^Ꞷc&&pw;s:7c=mf?Suqmxrl{&ճ=g!S8V+I&v}7}Oّ<>? XX9i(^+) 1簤sxѶ\N} Scy;}M4}?yThnZp'qq*CCU}GQlH!PJjA{^ @EHoR ( Ő B#a3)$`|߼+s);{vN]ߥMwg`P#LގndʜsocsyT~=._ê5l.i)ύ ۍSYtŰlx$_>'p seElqd-ZrMƇ$:0W>qkY0Yn<}̗fӉ+;6Q{6Jr! NXl7򫷸>ƉA1w2>{:'ͺ4?3ow1?繖{t 5F/aOwV1{\ms9h(>Ϋ9*D<]1<9"aG>_Kx^t찡rϸ^m  ;KX>w]G h{qY,зXx CF%;~Ym{#u[׾ٌ{z- 5?v(cJ1"""R$E~ U6lXy֭ݺuJdr+Iܽ/vqkw Z#Wc١2Tl 7w4|o*.oj WGmaw':blbܨ9Tzh X?p].g 7~G4Q{iW-)Ebu4 6 :bkboЃE1qmiy)3ZDa4e0RֳWkػ04؛װm˜} i3s)L۱`#ݵY-Qɿ}m@uc8,ZL[pe|-oN5,qnfRYeX=oa#@ё> ~"i~} wtj>YteO1R~s >FDDѭ"Rdy%;v[5jԈ}qXjطo_v#VJ r<3BJ [ģp7qfعYteO1(h?{R)}"$G5XG9Z.G^ à\r96MF ᶩop]U_y3x:ZR d`zf4EXD8M)e=I?=/c<=&o?IhOn'1̈́Ь]Hm#lp<' ޲~L1MhZe*+-g/7[-Fr)Le%N&15qFE"Sy:Q.,]qۜ_իV{j;wz9/op"#lifEYs1aӹ7WM{e}('7:=h`q"z>GHvAʼn'ZYsq<Y?J1"""OD bMP//\z9b!!!Zm6ad!RR$K{1d*3uV#6j8V٪? ՞wR]+ÿ~UF[aT8 ~5Чv>L0Oe[s8غm9jc/^cxb~ON##v_ie4}1;g ߿!ӡuA -{w7S Ha?9nm.l8f۱N+3ʷf LLiw2yw˽,9Gl׈*î'ɸR63o_۹ [os0ڻOV8y' cnsHRdymMh]ֲԯ_O?dKB)LREJ_,#aPGo?%{q,Zz Mn'^Z^=h0bz2vbMyk'&Nyfz\}I䇻Y yֺ zyNMz;{?I*R+&^Ӎ(y_[Yh, C3xgDѮbId{fT2O ܯsbDNw?:E`Ό7W}%6#xiJAGkRP[W(Pwӌ~7ϽЄ(<0Y]qF ?W /ѓ}'\Tc_'{AmߋڂՆK=q.;m,XT7x{}b0*Z][dz<=&'Dױ~DΝ煋J}p >F O79\|;4/v^q4'˘X_lSm.SF?LZZy{6<,t4LV8LK{3Uw;;c6)uJ\HV[Cvu _A )$֭[g Q^= SW|6mְ2J\Hy'.G7xv$UX͖缼yof@/.""""""%R$V'NÇcTTk)Q/??xeQtTdo MmHIɟ{Ӭa)fJ\HêA\Z5kZC"""""%Ÿ{YCR̔"F9b$`')ٔ"Ā5"""""""%RdSBV1|aDDDDDD(q!ERƍWv́6mڰk.c#WߦąYa$DQ[J V허,J\HQ,h +p RSSEDDJff&@^a+""""""R2(q!EWbDvn iݺ53aQ^="""rĬ!R")|~_gl>CU$?YK3YH"O۱ңuHɠ>!""Rv\ OAlll2gײiRn]֭k5Ią ԩɢy[ڸLˢ^>_|=#/;$MJ6 2˰D bMP_UN8'r+[H(>ʱCHlCvUl]oȊ0mصtjKA<6gO!ORJ(In Y>^]K&u޿Mm}Q&=cøLgW$tڛ1KS_;om\3C:Ӥa;ߧ>!""Rf)q!EVĀfU W9퓔 |Йټfؿ&sbt_5٘0'+.f/Vudg W/amV_#cX4)JLJQ qc'c_x%T}֭M*t< IJ啸I:ur r+AAA["%YH`נc\- rsHr4#iBaRS|yƞ}frd\Uݪ`fcKQ 0;[Vb`y-Xu"""eq!E_Rۼysz^<ϯ,srkժ5/ϾXIJ# 00C ZvL\3626?!""R)q!EV g0VFFF%%s[ԱN0o-?HmlGFl0sߺhk"+gYޑHmK Gu-""\Ja9BHQ{Igmloߏ6兿q Ie'LjϝYy"""eR$%%aE \~riQ 0zĵYnWBtםT]= [Aˋ"""eKa>\~1O{ڻn-䉑Ǵ {4~^uO1r^u?w#S{B2U"2lٲ-Zd←X"ދ_p{aŊt֍ X(;t`|l5dw,~;EDDDDJkyfp   $wqg˫td/;;yu̧xx׭< A#.DDDDDDDgrRRR8}4uu|vRVJJ5$""""""%rζnʱcǬ* L 9gvӧOC0ӱ;DDDDDDJ %.HoP+WСC^K#\DDDDDDJ:%.HS'O̎EGG䟌(ʺTRF )0Wȅ"""""""Ⳕą,%.DDDDDDDg)q!""""""">K YJ\RBD89n*îB&WѸeZ:mK\xx6禠v->qqPBD|J욚<1-6bk# c;,3tr6-/xɜ2K/ IDATe׳ptM6&LcIFK{xb9;~͑&ϱxzVw/⻬sB0ٞ[&|X=}x^%o"7Ǽuԣ"Z"=_[Ư&[;z&ݫcul U֌汿/ٸq)Zf$:'Y~5_aѨs.4__^X|)iE9|hU5Y3V̙#yaM*f~ETv->qQBD|QՎn bs il@ta_nn~Tn߁ĕc%NF }]Իyká+W@ nv]m7 VK AҢ%96Γ5&BʗKKA0`ԏwdw;5bVDApjns0hѱ)ȪzCU#f' zE'']99XܝWp˿rU1(d8Zڵk).T%zƅ{x}5n,QQ?0/^҆azRv;&.3?K[p}>8aǂ)< ) L%2hl< O3}޷;in;NfA lui_e9mJ˓&T"͎n5J0&NE$NFH^ KſGb5YP<[Yc/FFsxlG!'%)p_Iu;FYѽ0uq,㮬͓}y~0&~$sA F6 ;a/p@ެ\lGFl0sߺ\dh^'#<W{ϑvvR)"""DOqa/Q,ꥂs&|+RNpqh˧! /\W3g|פf_JIlݲLA|5GGp"6kc$E+ކ@ ϧ#8voñ",0G8\$}i&`#4<a_FɚNw)w89y` /\TOb&obI@@yb ǏEK?xDN: ~]]Cٮ/"y#t4*_5=Ru{]{-m"N=i5 *tk%$8JO >6B:<ʴya5z$H.$4EggTDŽ)iL|i=M"4cP}e Y0=NHf«e4G3m]rCN~b̽;Kť>q)X¼/{O{׭󿬑Ǵ {4~^uO1(gr؋Ri Dbbblc6b e4?=Ϙ(oB|ְ tdWchttQ\DDBZk7kf @2p'i{O{g ;S\eLӫnci3](l,ey'ùg&vɂ#g=vEDDDDD u2ɞ畟0 (GPd t#=xPSv,bmJ<=|uC/니oS⢌5Sbfrռx2=|=#/;f'.(_ns.&"k+YO]K.}v"""n,r5`֓19}F Ft8gC>u}vM8: ~9g}-+iS]K|jۉdLgW$tڛ1KSq -FB!$|>a]MXRo:b8xmx6LïC۶ugn YsyLobi:F|mŧą99o֞MfËxrGn{Wz9H]W#xk 6èxuY=^k4*'pW@Ǫ -غUpl٧ͯ1?NGǦՆ xٳL|hU5Y3V̙#yaM;3Ya&d+ |?'""""""e\ڱmҔ+lJ^}գ&GVe]ڭ6;m+;o>FW WmdN$մ]m 7DkY#/7AH?UAv8}%ර[ifyK{܏p;vcP[a# "|rb#IU"&̃<e}ω+)MLבIӸڥё^"Õ+-#""""""fP>cp f[7K>_y9xgV*>.,HNw1 cK3DA\ '.ӁrY1T Yãؙ/I{Vȋ{ٶBؗ/̝uPnߏ6兿q Ie',GT1`fQ .Nh si-P4,({x:WY3q_sԽ{SV pr~9~r<(㲞q10DPU^J:vr?&LIcKl'Ԁj#u~ f~JzރLN8|(NO1StN<9iGLkg׈{'>qsF7w\{6NHf«e4G3m]rCN~eDDDDDDJkbwZ%ͽ6!i ؙVqt}"+v~ôaҩm,؜=dxOrfKԏ*_T-b\˘v}Hyf_gS oؼF# ar|9OBvia }hٲ-7)4vy[z'm<=~%2V^o [өp>yw7 |^\Ur+ǝ/Sڕ 'DDD|"[xX/f̷?ۚf=pu%_:ŤSrڽc;,3tr6-/xɜ2e׳ptM6&LcIAMl&6":Vy1X|V^7_ [^d,ߔ&kؼz:OljIH/yƎn& }mmqKXx27\byɘ/x#M_7t4'DDD|"SWhOSօAvRJY{ `sŐK^]K^# (_q7-#Ï;0s?cG8j$:>[[du!""KZD"Bj1cZG{"Y,8y3?`CT<]Y/s]8:c_8Jҟ;ؾ/ ӨJIlݲLA|5Gs\^.Z[¢hɃ/܂kh&w"B ̀I| o?0Oa=30111ͳ,qO%.Dķ]νIˎYfK Y_&3˭b5s]i rQLZ;o~A (N;\w^oRBDDDDDDą\4)y!""""""3.q&b,y:w{skHDDDDDD|rQdkXDDDDDDЭ""""""""Ôą,=BD|uN *q崻f(֒ȲnU\xjsߦGDDLSB.IչzYg]ק2m5,>Ï&#հ9Rٷ]}h$ B|¥S6}>"""eQye>#bkDаA=L)R2_v{䩻kj݉#f=ͽӾ5-ধ>eݹ$JǮ6澭x?݉#COn3?ޯ("""r^xݕiڴ.0"%+CetnQ[5,~ƫ_%cbrtxF|lp{&{qY[ .gӜ"㪇;aݽWe9Xֿ1 #J%<2"*ܷ'cg1ӷԆ[]qР ߠą15$r {57tM5};߷: Vd#0;ɇ`R)k}$'JxLmp}[q>*zA~[4zES&2;!""".I.ևX"%=+d_ԿR#mp,@Zvm͑_7~ȼdэoD=x8@ Gmۊ1S]$vQK/C-;BDDtӈ Er񝹗/z<P&߻Tщk4lD|?bǐ>}_HR\xjsߦGDDdSBr)ŗ[Co֐H.qkLQ\xjsߦGDDdSBr9.gI_->/%""""""M |cű )Y\ȆfqlCDDDDDDJ%.$(m6DDDDDDdQBr9 fqlCDDDDDDJ%.$y6c""""""R(q!alCql8!""""""%xfql8!""""""%6c""""""R(q! ű؆,5 bs!XQ yiFBΌݐi#sLn6Gt+w%Hąb[cű kYf %gee}LPi;xWe)RF}BDDLSBr1_ql8a'R"N\RzF_()'DDDJ=%.$Y\|iRV\"R9Yš$ֿПN]{3fi*`rl܍6q8pS7κJFBykBҙ&o}"%H駇sJ.lz:T]mCԱ5|;x ux!OGfuX?[G=E( P;u/"""w\b.+xVI."ɑUsYW:vFNdAOdfuoÝ-P1ûnQXq!@\\\PBrQBDDDDDD|CDDDDDD|2ܯ IDAT""""""+\L.DDDDDDG(q!VJ\H.[PBr9&ktąhЋo0_ą,%.DDDDDDDg)q!"ű]yzSux854絟pZqWOjJ\3Ւ3򄎬]}NNk{\?j"HoqmL6;/':v.&RfO-q!">Ķ7f^^i&wOd;ir2_`(7zhJ m !)nўqtOf Oִl׃YOtO019>~\7oW}j=;`mډ64Iν3zovmG. ;[?&qiYFB!$|6;*6Odo6Z:y "~:|H٣ąSb#+hh3*#>eƕ|ȥ,~w'+}lD=∰Y29zOKהشi-_<ހOg V9Lh%f哘z'.Z1)_++ظ~o7qʽk> il@ta_nn~Tn߁̩ㅡηO\>!"" =1fz8ׅO]IJ]3F5K.T<}t9Ӈ*+LGs朮*Epto .W*GDoDܨZj7Y9 au2Dac{4qf/DDxywņazvn`ĕ;>q#AzS>{ L`e G :].Oq|9Ow歵Q?iٵ5GW!v::<&U.oD?iYd;Qr+!'DDD%.Dw٢geFEfLx5=;6:3oަ~+O xq 9m6>´UX2c4}j2C6"{>ABL1HZ_5^ ~07<0FG.:J Z.'=]Ocؽ~^u?@9xO{{)GH![Ϊ~ְILL$&&6fqk!PNsv~; Ɏrᑬ~=jH~\y@6^is%O:J5 )kyfp   $wqg˫tUwzMwsI:mS.-`]TVk\ ^?>o KAtܕj"""ORBDDDDDDD|jJW+ixU+.4%y;އ3;`lM=iEDDDDDQTȅllv== pgsuْՕ{?˟"""w|eT JDND@PJQϮ**rgE=E@z@PD@Q@ZHHl $L3Oٽ]32TQ[מ{Ћ |5jqW'k KЖtKNjּxQ]׽Z]Ac?#{]\?Pڏ!=Ԯ}'u0\V"rx\={ouiV]C3蘼7^[=PI{G=5k>7^]ӊ,VSc<˷;}w^mԦz=*wrj3CջsuYd(}zxHOo^qsG9DpQ"۪W{_Y2l/FZz\IRN԰i[B_^uH8޹еz㫕Z3]xcvx Ym^|q {x3#n}KV-g#cq EV\zOKV7SZWOSkrzך؍jzHKzQ=Pׄ/g+}iԣچf2,XRP>wvz$jk#4as =5o~3M?~TwU}5Myy`dW6l#koqZW~{_-ةt$ooqM"kA_H!#?`PT©낀ej*WLׇ\}עWҺC92d(/}6HЮͿ*)++%cs+9X\)y>jrjڱ}a>O^dSDGChC6MYǽI)ʝԲyucxeG#X>n֭-R~ j7pjF--ԮlsϓC59[7wR'V*7nT['QnC~c>[\k-ۺW|]ܽLNqo^u~bnfͶjxlV<7?"osj`|;Y=B}Db@g{H?R(NPjdNU\,xb?ɺM3_\egoSR&.ҾjXUa=_Ov WjW虪5w%evnDƚ NH7WI4W:/Y󺅘ʆ߹SaMnUQ]#J=_cG'[.H cnwg*U%)YR^6ހ'''l֛׍S,~es_QÈ a>s0P7j7N5@?oޤ~΃Oja5/AHmڹeʤԵm7>?u2 m)e3<@-rӎȆȍ=զE tF-H7O}=uwT\N^)xniv1y[[ߔ3$֫#SԾ`=&d2{nI͚R۞4s/PO}=:ڵ.kg8oMYs1/;+;w yʤtsu ?BjXW9Gڙ}V|C+⡗Mzr&UJhy.Ԕy]W{v*RqN'%4{GFK&:(*qe&\OWP҉6nyqf4 Sòq{x3#>&Gǩڧj=>񘗿ϝx~;79GNXR6=WMRk_^^PܠөjfE\Zټ}ԮڍT'4_V"vnbz 7lS/QHaY[[CGls( _OuNu~U ,ȩ~oeJW=JIN-U5ŮbΌtkO}L}sޝϛME9vT7CI)Ŷ52U$2]7ƿ_g(/ס&ǎPd9%TǼ<}Txs8."6UTQC:jwbSd>yx?򠆿z<ҴL韋g*:t(I]Y-hΌµsWw W?ZUsO5^^y%Oܟ%mao<\Qpݒc5ffW8T4eڛ{ձ[`0íiȣ;'æ*}܂JHf+q6,7Ҥ8>$\(Uiʳ}oR-dʛi죸Nu^ wҾViզ}*䎺)nZ^$?zJZUjټ1M GW뫉/$'ի}hCLR/]R TXd0IߩeO'YIreb (;u6YEwI6WXsu *Iq]%k^sYٰq;w2W²+ԲE s9U(x$Muoac}/{y8X68Ep,X, `Y.e\"Ep,X, `Y 82,rWw8Ty~7]sj,?sq(ן;+;@Gpb2"Kt\^1'*9zKMvhţo:}7e6I&S}4 s2pp&lvg~.[Z0yzwi]4,߆y445+6.NWRd;:T};*}'[;!`(uyx4T^X6<\OnkLMVͿY~֮VoI[Om'e||JN]1+aR{ii.q7 (-6k uV5rH5rڿ 9:)*Qsp$@Yt V:}6ov+v#Չ$j.(U*ǪZ\%'o+&:cSv(;{^kjmzI7;'c|[ hVJсDwa'+&Bqg])t "9US5՟g+*Ұ*K۾u VgPTEvo̫ۡ+_\t3h;n5mO+5M7N,ރ۴]S׊r=5!F\[y/=4r~2e|Qm^YֈoWU 8-|JN >]때~pw ~b{_X6/~u$G_{@P/vI3 \)iUD}dkihsu8"&&Z/h;+))\G^$&&*66\]`tBJt\@yɚ<6nT|NjTX|Zha>g*U%)YR^6ހ''߽'lyc^7Nm~E;#.pZbb5~Xs;V11/`ѐ8-Viwe{R7'xň ;v3gjڵڷo$Fj׶qMjPi @yDpvx,yy^|vޣݻh'j(\ ۭޣ l2x |+vةYٟ֬Ï>Ү]4cP1Jӓ&kmBbcc ƩqKrrԸ%0n} 8yy7r%bΝx,l6=;uڴ1w)צ2Y6M}vi('.P">9S^W T֭'kF^/׫f47 5kJdj9!K*P\Dyꟈ(} `Y(5jT{iQ?(ڶ$d>=KRY㬎A&MMcW- guQ\D㦛d5k'JX|u4Oen27 k2 C?:/Ëudn2D }BO@Bp3QjDz;~n&-ۭ[i;vmߣ5e]&MMMqm*1=ni4ءzަ=($)Csѐߟ{Fwx$ektU]׮_9Pzr%ЖtKNjּ|{h qT}{V,J1SJc^ޔ. ˥M7(ͦY?рWԤi3 z͚l6nF͘\.y7(ӅN7JX󥞉MS|Er$*F5/bw}[NyW;9o¤mjWZf͚] J]:QæPSsn mzqH5Z*4BЄ7|6ť4y?VRyyTټp (˥c׼9kASNNԩ!iޜ5vr:QnuyER;oVZGC5ZtT.ZtQJBjnBm<#WzjX#TR/QHaY[[Ѿy$T. utJ3_ IDAT}ΕcpRJ1/J9N!΋k¸qjJ ˡU4GfLU)Ýy=|FLQo"`Iʊ)@UXH)@ Uͯt#\%ZvdI-(JUjXYl sCUzmJ2K)5z@yJSy_L_ʫ<%oxK3ǨOKTjԊҞ?*#I9gSq J^qsw]nrbFGn8=e#.B6EtxD=|?VPf7E$HѺS5{[QUUSq J^qsCG7_^}9.DQq5@YU'w:}z`ټG}Onk(;.Pv/v9:%5ml-m,'11Q >ts$HsU5[lظQ;Raj٢TqdIyGT\{ʞr|S<˾g/:ɺq/ln+jqUX, `Y.e\"Ep,瀡9-hVx@W9S=6@y4W< i$eT.ɱ[a|f=ZJ 0ؑsUm L߯*j j-ճPq xAOu~*)$IFM@C*mzۃekվE "[MI5muAm:tUN^)O}=uwT\N^YwT$բgwK7\;$m,w'oWԲ2n~ xK"@GxQe2B5w jZxI/| *F5/bw}[NyWZdmh9^sW.ӳ"6hS4;n}*[>_o=6Pͣr''Pc-W꥚H](\6jk#4as =5o~3M?~T$Pұ|꬞I;,\꾷4Ξ5cAm վu-;${xy%8ѢWvɦ`Ru86&WadSj)o}|U]_pjgjQ"k7RHOR;nSJBimtxmO_쵯}/R]rUM '$`%q"5і/k̃i i\%oJ?ʖnSƟ Iٿkь隽7zr3ﲀvUS[ᶀv#?oߧOVS;)zX3%jpztx_5t$PrV~2 {*.x=^[\䜕uiQwy^^.ݣ'O_S[\-U/G5R>Qyv[f?ij/Tuީަ-4R+MUd>yx?򠆿z<Uu K^`U*= Z~d)ϓgkjԸlY)JɎMj(&?̜^ISpj吼ڼpv'8%w]nrbFGnCރ^ԨFny^EurdP^mޑĭ P1ҷOԘ݉:J/wGʡ4l*=9ETPX&üuŘu]7T1+~2w<CG7_^}9.DQq5LMu~;5g8/"캿I|\7ǔ6O*izB IfRQ. P\pU sHzczv1mOH9tMJTl`T2MwgklkeZAxѣVbCx@yǕ!J"NI;[no\n ʁ}W(QAsW|qn8Tu鹆 }]æ+jjR#¯JAc+!;[*ÓF!@F6=!C*#HDtA`NIjT ?ӊ #֔yX(=׫oѷ(&Į[OmRjA q4pݲ$z@@pshT7_4ژ?2|9=Q+pG mLrk1_ltL-#T?[N.P\0©'_s?SN&U+ ܛ~Vݿ"M#ʚMH{({|ciR\E|ż?5E -NvC4**7d+?ge Ή{< d\Ǚ uh\8L?]n P\]u|L&pT3hqJC+H򍲘Q̓5]OP\(L!c;ǩE5uaxG[]T(un̟".W(;.pj;T%pح&I$6ԡ.e eO!)/uTxԍEl! +GWyDoo*򨍨`C|酯ʈ (K.p**5r8cnCmԢ9S}|_;=J?E C .ܓ0g{ʹ׮Hpe Ѽ eSjه?% s_d=[Epƒ C7!𵏜`8cIٞ2$t8=JwRo߱qҀG'@Gp3H)`SkQ)gXV\y )!1WT7ҡjaSW-̡"|p(W2geAwuCZJ\u ru07D U=F]Tw`G+F ;۳$I.MC/ 3(>43,'e 7hWoEAX/T/T/$?sL=eΚא1m6.SsMK4cleΉMtLdIZG(oDĹԵF:Bvӣ,CrkeT-Npǭ"8Q X6Cj"4VA 69%I2:[+&逹(lbWPP#a~u$Tehw?\elWbɞU?*%IOdh }xy&_&gGwh`ں=]_:EK=ڸ㨞8eLQ>YS$6I3_\egoSR&.6W4GU S=Ayɚ׭psaƍ\ ˖P-LT$%7`$$o=<=e#?3y8X68*,X, `Y.e\"Ep,X,oihs`9*(uq,X, `Y.e\8vS`;@Apb/7,(׮][{zАRVVZH#׫g}Nz (@jDž s4B I р4 47Լz t=S;nM?^N.88X?^w~[t IDATAݓO>N2fo*=?hhݺ9=2rZn%L("''GϚ]P3z=nk7ZIdzfki(yyyyy=z܄ +22t׫Cr&ݮȈMPsCpb U˖j԰G5jPZ6ѣZء?Z5k(6 %СCN5@&*4,D+V27dg(Ql6M)Wss?EO ;wrf:uXo`-ǎ#U*33oGY ZBBܔg(,X[3S^݂}1 aRsaPŠr97'\X}g.*b^rfo`-\dYKG:+q/JbLj ڵkoe;me[zpv \*ܔGpbѺUŋ=$У  9.J (GsS:pX4լYS& x8],V-IY_r B k|(.P,l6ɓУh5qC>8 ,%{,^ \\wWa+33233u߰IRzt^J IF#QY,OIr$E_/ZXz1 ?X,Bq#@q8zg e rM믦'rM~Iǡ>3r8kgB9rD})+;>f1ҴcJ=?ڙҴx3h:+(Z+]ޓ5}?,rOv?Q|ŪQÆzC_ՀWR~Լy3I5g\-Ky<IRPP{f^|q%AGErԻS?T{iI9rD_%Bo^={*88ԻCk7Qll;Vj׫^ZGOVХ**m#k~H86-U;xn׶ĨN IvEVPN ʼnŮ[׮zwt:$ǣykJ+JR7$UѴ_VӦEEX.t.׿^!yF&Q \[vQk4SR|Et0`A#G|wG&$ޝGULV ".*Euߗj[U[[T[[U *j @ !!$d!3IN{N2Lz]9{g_9;3Hx-jQy-6OBȞ8֘9O _fga= CVZ@PYqd'vÓڰĴ%`mƧ_ՠ#ޭb2B:~]ZOwBl^ڼc0~`P[~]!;#͛2or oV`Gj_ߎeU{Rk0gHɽi_&XWrD{"[>=@x_2;3BNF|  F-H/jG%5.dffހK.^16mڌ}9߿ƏY3g@VYYb/g֡ ] _NyXu؛v$FNAbnlklN^Yi_)$)JW2ʒ _e[Ʋ|5v(2c/7)>/wn^  jv۵;? RPo#\cAdBdi>Ԗl6aWpe%g zR."xQP56 U^=UY虗x_z& ౰[(=+#p|r=ԩ-I=: )|MX݇N@׎l_GD*TDG%5.K/^*SDDD΍7N㟮\)C-;ۆ /@bLl6ѾqGKixzJ7$y115r,L9C ,\k8>~ԓi}; {`¿ٛ78ox ={wNNǍuF)RPb*0s*$aԙbDv 8~X0vxc8:U@bvCnr}Γ<ť(޻53SGƇA2Ō1S~s/`' =p%;47 %˰ v}tff`xE-J"+7 R w|M˂s[^/0t!sz --v۶m:m23X8j`x_ϿŀQU])6}} C62}QR懯hANF5RQr#' Ԡ_}ɭ.Rسu OB_(fmbP1`<'/~:*VI1?[8PQ7s|M{'Pnoc1زe >Y1;v`ihtxj7(FJǒ77ߌ=SO:FjM=d}y曱%(--!""8?{{M)'?CUo?*v=2}ș4{U(ڼ?V_}ꨓ1#W`H@ FϘŏoJQ )Ŷo"gq5<w.*yþrUUUK.;n,&pRRR?-C"PTcP鈎<QбۿۋJ@2Wx?ěɬD}@f:x,m~ڃ8PQ*6II H2K۝:ֲP7{t‘<)y(8ÛW o(x_,y:"+BɎBTg"k)V~StxUߋLnǞJ??rUEV\wmβX@ F nMzƘiXSx_›KbگeIJl߾۷oW ׋ ip?CnDDDg~Cה}`>6鎟v;*xͺ^? țy /OŨF 5@8\|2.@t_ޟ |V|IyG%`Y@sp; ">][o莴1wpᤊDd9'_Eu{^ݪN=7y۾GϞ=Qg/JKK1mtdefݯ ?l)݇C$8#amي5C !%]NI>$gSFT1!3;Յ%^<߄͟/Ge-MLEfA8CcuEiOB^Aؿz6lO1h[ŧkɝ:NHտ##q%DWr3eAtO]OQhZHJGͮR+ Yر; 3ipD?) Wn/c=%/ B8Vl)$tA: tH߇~7)GQAS]L>5=|Z Xm^8E *9%fWg0 xSODtyy{pAQQ/33_x!?\tQIسgC_lp'ߞkl 9aQ1M7e˖aҤI2h܄ Xb s~| qm5x_}}.]T-["'7 '''c'-9СCjM@.yFdp#7923~ O:8$z_"Ԣǒ(AueӒX|₢W{7gc„ 8v$9ע{Ͽ}+V`Yp]ZZ|O<$nzyQtX,ZvcyH/d'{Pnʰ;qWPI邡3@(+BίzK)б3$x.(*6|-~5w.D1ΙѣGi|8cqܱbժp/,zuYz 8PIDDDG|qւ'q k~q'-nKof۸i.E χ_ϝg>լE iQxfSvΜ'7~;.blܴITQ{ jmŗ^Z}]v<+^oxy^\uxgеkpIt~\|Z\gÀ+Bjs!ޛ<џYacݸPTT h…:Q}Cg.[(**E\ݻwJ"""ji_-6ŸzsK-69.\P4ovS?n]ֵ+us׮]iUO@B-\ W^/&/qk( &""""""Ņ """""""[\ """"""Ņ """""""[\ """"""Ņ """""""[\ """"""Ņ """""""[…%6""""""xvXc…~3ۛKDDDDDD햜yo{\h7ȅv7'N6ݮ,jkkqFTTT^z!==]֡\~aSyr[]QiF~ :w)rawa!߶ ={BZZLY~D7Bl޲wO1Цm"mB((pz9++>IQQQEVTPPߧSrڌą#M oRaDDDDDUj*7ϲ`Yn )fw|9uh """""(DE믋sGx1 5 6qOX=7Zljx]hH.v$DDDDDSќ yk$mF<-\ ԧ, uDDDDDB,?7ۯNw\inn4wr{AQkOE{v~.ïCmEtsՄ-~% wƉS§2kp3pjqB8g_戈șќ[6jpy]5ąz~4Ă}.L->_p ~uXvD$jO<]x1.quG_=-zN|8s,|}pʜp$sޑY yZly-{ {!"""jmeY IDATxزe o߾8SqiϸM%u,|4[ةXt1r@JL6>px\\߲>1?4 8~ d(HLwz5f˝cO+nj/4BkK.ƫ/W^~ \|1x-\}5(** eK~z2צn&N6--\8]x˼W7w2}vv5~ Fz)s1P"qX+0㸉{I8cSe0~:z[a 8~/kE'dÿgs&8秸nYPe7Oe?_u:0 ~:Twm@rky0fDw5˪j+P5tSxyŘ~x7?"|W7=_y{WMX_2_qȜY({j\u^ھ?'4/ضoIDDDSZk_ ~Q(݆8cG 'ndzP5V }xp{]*YϚ˞,i ˲0[櫯pUWaIFnN.4 {uQwF |LL}Va5kD2]pŕXÅ7M70ھ0|?>[~o~(XVUJ'[0h4E >:;+y's.>oXbx_zRmx.K, /7XEg@/+={r|: bzXx1.=w͟g}֠sŢŋPl>=U;-Xrf<䔩8a7!7vZ7i|mѱeV9x0`ԨQ֭55؉7`)0 :,{E|2,\~8eu(\ޭ@۸Ɨo-ӿ;_%{9xkϾOL\7<&~O8qøk><cv(s$f/h. 5)3]p}l)sPe7[@zV9v*GQOYue1I>/P;Z _vy]Jof2*6 P$Pq|V.;Mϗދ&͝H؄"(:p)4;^3 e0kFDDDԪ N5?(f8{UUUs"##.|e!1df!*Ci={; 3VduѼ`]cԨQp7c1gbpĿ76@]qSqI= X OO$4f6]eW`)aYG"v5\Zם3zc֬cŦpzm鱸r+;qsʵZ2䍱N8C31db =XO|??/͋߇Ҁ}(d ' c-0|6jtmXsAn}7i9r$n7> ~uѧOForزM8k:N?7/-7P ,xrypeieQwj6>gI3fङ|˃#!U{?Ϙ|| Ŧ$j$\…2;9k~%7b#pͿ8pQNcR=qR HLW-đGaW[6#GÄk|{Ga0?aqVLL/~ 8#FOIW?w[@x4~o 6~&J#ԳB<ȳpaO5bYh\pPr/ """gy&*\vu旿@^n.?>QQ\]-r5;pub^d̂iS瑛-f5T<ܳܨp;p[Ux1k j(_Eょó ♅ s'Icr0ܳ y׋jE(؏ xWח%K7;o3 &S~5To{7Uk" mmsStvqQ/(FO/=\, tv/V#Iw{Xs‰sd@aj٘l-J _X\qnz@pܸ]=R'; >Qu:oHqz 8aKޫ5kx :>,:[ """"{3f /IӦa"szUg7]SwCj.yQ 8ϧUi]݇O݈ _qng͚o=@Ȩ0qc>fY(^+8 SCb\\;S"kW$o]@xZظ6g ~)eŘ;Nwlu*4ߓ7_ߟQ 9kgD tnx!L( !;FJsXMur41..iTg㪯DEm>}_b 6/YUY92|ħ_'6n6QֶgpW@Mғp/9:aQ1M ~qQ4Xw S>ѻwotE,[ &Ma#˲h",~ҧOo:s&f: /';}xtYsP+Cn66ajaBЪi!mXߕa9Oku:9n1ng!:S {)o@pAE_(bΧDq6tcpjT[OJF\$""v 7oe\) =ztGbb͆ 8XQ!SЧoIq%"~Ij~@ bzBC ("HCTיX0`^Qq:FX*ZٷP#\IOu| Q3(//)rd8##C<׹O>sZWLuVX/\7(±p5[77}DDQ+JKKtBGMsW OIOLخU؍! 7e]Pu& (X> 7j?͉~h LC//fa:Q<V} \xv쫱2 """"""GrN+7N8o.d\½aӅc=P7[mr""""""xV#>?"z@Ø)rPz_MMQ7M}1y""""""x#ikLq},sq#O\.Y4V}loi9""""""xaMs\rN,p1c;k,\ Tc]Dy͔+UjLDDDDDDj>zNQLqSL_G4g"Z.ߴe^JCq""""""xSXX!r?[UKDžJVr]LE x,u\P[śCʧ-r>v,sipvՙzL-qc $WOxDVɸy\QH%jԦbr\^ִ9kZEsL.ODDDDD/MMyo'Tki9Ӧrz<Z0U@ՊW H Wuo>WL1]|?q!Y0Oe\Ez>_.*}-~@.lxV_6"U}SLƒ}"""""49v@jopqB_pPZ+sX1źPbzNur[DK.\Xh8Vc=n;'@ =gr*Pnp-Gz=P> S $^mΣ^'#c4v1"""""Ñg6[@5Sq=? ƒ\:-X Zku)ns\`DS^^4U#/X˘z2C C!H}TD?'S ~Nɧ+d_L扈>3q7T_.MA-2蛊 8sydLVM2tvyxr" >6,1S &~a@-Z1jc:܀E ONW׮5$=fGr&C՚bj6}: =br_=M)*n;ZUK-\X0OE0倆~t*P h9}p~4\LZsC9uP.bP̯׃XV}l7 '"""""r(y>V771}h/,qmp >&rfjz6}}SqEK>]46Și/*rC[Z_Qq}9k5pa~2.'kW?jjBB_@NP^u.)h5MzLVخbDDDDDDm>TLCٗcZ sB9V} OYI b^s;mN'ƭ.,D>/j@/N'+BB1.bZlύPLCGjbjSd2z.>D|Rϙ jA zNmF Z@h,kզeLє}.,'2.:3] u J$T_=E/E+ 0+WS!O?Wd^'R<Q[cd^ռNd^i#r4\Py7WiSy;2'NJ]`^o>[ٗ5:S,Zc‚I/ ~ƒFc‚^guEWV) qy)g)Ӝ/}Lt97nשV"c&ܦqwImT…e5z Z\'k *jE }B_0h$ZB9U#0d_Qc6V+}v6fYeh8w],BZ =zPk:5MjL18fpa!ɰ_SZX^b^S- dʫM5tvc"""""Å;ڍ-lʹbe!zLq*odbN"w텋p,'զFrP_p@͖ ')s:U|D﹀ZPqU#ǪI-Q[YXVe݂ K7 }qәb}<&ZzB8, pm#~QE X<.HX"^zZC>dN2bTN$DDDDDDmihG֪7uVT̔3YlBAߣ!cT 7nQpx/sb@ AƒZ|P5x z^ocu5L9;)FDDDDDɹ `b9-Py5 zd;LVZ 'zDsA℥9/TC?~ }S1әje_ &&9sbWM5%zLqS n#bݓzm\}[\&vDZ+l9S\L.Xlⴏd'""""":MMwSi/vLN }E⮵N,'rtzSL?[@D\?ʘ"vy;5r~'EWc*z\Ȝ3ՙbS2'zLYTLoFk/\Xh8ku2B1= qS}tr;N9)Z"""""$vNj]cƦ:q]\1M(:])b5q w݄\d\M},zMܩlM1Vg 7&""""""grn7qqΩ5藺e_ev})χO\7& y!jlGB6/΀֪s*&S=s9倆y7^gUqyczLX[M'NsvӤ^~d^bv9/[Wd,X '"""""jMe>h`jeLL}},qz^L}S."ў:)&뭩^˼F#ɩjMUL9Y'DZODDDDDD:iɻdN9yrl&N5ND{x#۵/Nyqq=e+:SSrvQkhDiSz*2ni}̛jXz8ȱܼkў9^5<h}EɼZزo7UCDDDDD/591Me_**]Nj\/l 'jlתIjy3漬TDDDDDD<.gsz)ZSL/M9i&6c6"ǣUeG9e͙}UxjL)rlb1usL75@:D_s̛jZ)gE+h%Dc2lwM}~2'[19V1ٗΔurlMb1qu{̦֙d \'R봏T'MهpԔɴn/Y/}Xc;Ѯs%_7vS4[uyQSdNp4`sDDDDDDTi2m3M10`dlu)d4MMb9u{-:iaO:Ⱦil""""""r7nJݢySLTg̵oۉv]Db9u{lu@ڦ,[0gʛb+vq""""""-ɷ+SLg7qӾvc'nkE$HTg`k:].;iξDDDDDD9pb]_gWc՘M1u@dd6GR 4w˜ήήHDZ4m""""")HETnN$F&nNuN N9)'crʼnuMe\sLq s:tzuMRHH:tlb1tvQ{tLySL5u28XG%'+2nl"k"mvNMdM1`9u}d8EZ191I1`񈈈ڻhOg˘jdLs,H|2"pGZc5Q)fbsN"'fir獴^/)fǩ)s[GDDDDDDvbT甓Lyъє}Oд }S9o9""""""j{=Aw:].8hM'*atNpQnrߜSέEEL:.qw5J$DDDDDD" W.VsӜ}"&y=Wr{,u@dR!"""""W-5َ/Or„y^""""""o" 'Q, pR|DDDDDD Iw&"""""jADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDm(]IENDB`kraft-1.1/manual/images/nl/wages.png000066400000000000000000002050121450127457600174440ustar00rootroot00000000000000PNG  IHDR.( pHYs+ IDATx^w|TPCEAE:6 E\{X^;,7WB'=?6L&lI#Z3Ϝ{'gwADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDE H^"TVm[xU~Em^VUv~2*sW~e&ǨjQ[ϕ_OM5?HUGDDDDDDUՂ=2sEm[WTf+}%VFMGDDDDDw*I67ټdTf_[j"22smh1RM/|2r'2*QgxcPqټ$ZWf1O7""""""Rn/ݭs+.qH7o,^~񠶟xRRU DIu]'3nnvmCia݇_<~/.~bAٜ[0E_ynQl<;fb[Iܸ j}{k Oo/cq츈H]hq7+.A7`57s1mcnm 'x w@qƒ-X\6qwk渂""""""[s.-^ aa"_\1a! bz'V3q̘ s̶{P-ܝk+NPv ~ňp- hnqc݇{\1{͝6CpO*""""""R*\ ws=fPZk7j Vmc{\7׍͍o/MuE2 p#-(!g b+; ZЕM5? *q]zq}5k0u):-cv];7W\V ~13mwkCP۾x2E+- :Ʀ[ """""""Ha zn铿 Qv/'l+. DfE7ǾWeѲIf|HDDDDDD$Xf-ֳʾu+f_ýαWšU ĸqaL.T$*ZDP+o="""""""Ƭ[co 5] bE8wRXAR…+.8[)8ٺo1mcyM^ʞO~m**gbyIFڕXA j+-L"xa&f{ަ*6RʰwMev]+h/E6~ebF4`#6e\Ȉ4a,3t~k+ Cn.t҉͚bJL?ƄS=hq.P ͘Yf_oK4^-jpaN/nNt1m*NmM3vϺy]7h $ ; vm[']06h.ڛGpQfg\ Pq̬aݹPjS =\Sx07]%-,ر˗ҢRZ"17NCCk;ĚQ+U=py""[ C\{/]榔h٢9wt\qj{q@}ֻnقGcO;"*S63iw?Ͼ䦈l222ϕb*ze,\ Vp蠁wn9|=ڔBqJIb/(G.NfiHOShؠq 7~OѬ]KELb6}{]W'*a.1iI27m7fylv|F|͟L>ȮכFv2mȝւ[tWʱC縣;jHICDDj#\oܨ! ׮Mk< Vξd8.cv~n*+W_ŀ~:osC]p6/=pbwͩ͘^3/%q#MncԣO1cn@ ̘7}:p١gw7=ӽk~~Ay'LbOĭwGuEJ|şXܷ׵~k_f}{_A΍} {)`U-J*]ks=x9fɅl[%zlʵY*:@FYB22ϋFfqwԐ2E [E'""5kHLb~773)mdly9+V9a :PXXw?SU6u|7P\~-5_grYr)**3ֶMk~<#??EmtSED6+ /f[<6n$#=B݆tuD~~wt4^4Hlw-ѵ \~w \~}v{I%1j=wۅ?} -X@鷈}FpܾR5U0ܓ sM߾~y!J+Tv~ 'sݲ%=p9+Vr#D";;nXDDj\~٬X{ϯpgS1clܘOf F=$,dm:pϭ7??SPX 7Ac me 9VU<< n>ϜE^=?X˅gU7ʜjLzXtO<gz"]~Mɾ;j];w⢫\u)=_~X-%Ϟ/ѴIFz#'N_~+9vU1`;s-wac^?yG~¢" 懟x(,, _GG7[Ͽкu6YX2lݮ-]p6ssXn)g0G#h1G2}FT1LjwxZ4oꆀ<Էh}7 Qz5pP31`ۦ{ۦ,\1'w~vIfL;\A4ꑳt ,hCfeEN>ͥ][ Z2K6utU@Ѭp}ㆫ/%==6bEWPBD.r B0e*h?&M-ϛ={\VZE-X< FiŹσi3fɬ_K֭:c&K-lyW-A< ]?sc^8߽-Y'L6۵}|ANپzey0e ?~Y:z6/"jܘ[s5/&-rn)3<]ZDݳ;W^T6VA :ney 5Vv%c6#&'O=pq]nu'_G$~.Q0MfFV"iиjk"IIo4OAa!+H]Ͽɘor߈9t>2) .*^s@hРMbTk+QxG9{oISs/Ůp4o֔9BpkJrhފe_aA!H;C9yؿywx0+VuW\̅gp9q;}-Į;M*y;bUk2E0qn]:ݏ}GJY9+VUn3-s@{})e֮7uapYA%[pTurehw6E;21rҤCHf!!23ܻXLxPu޽zpާ\{EL6=""y,XV1r#8rΘBҷSt܉ :kn *ΈŶo6m0q/;v:31'u ZK=oϾ}H4/-c_&*9+ؐ;oysGFK}yfyN2ܟyֹb-l6j {zpݾņTpQqf2~$n9Ӥ.4 4&Mt,~5/;n0n*_L'qd ͜DA}s~7{(V) YJ/O\}=ꡒ_F7/ggƮXxIɳ8M, s a),(`e<?;XKoq1p-7РA}֬Y~?/_IsŪuLo2 ˍd:`֬]Ǹc~{q_ ?ȣO=_6ODD*d, 5,#w˖!V(C(DF-:GH"e/QTv%d‹yꘒf>.V IDATգ;/^5[ڵKÆ ܡ֭_ϕ%9K>>zc1Rb YZcs8c$hۺF"]p{v̾~ǚlEQa36,ۚ6QTٿMfKf#_jNd[~bEDDDDD6ztckoC[ r]q˓.^[ C6{=k W[f5jo͢6,\Kw[P7O}훉&n/(G#6jLFKbt嬉AX4ΙIKNlFƌ}1cܢ1qT.\|.cҔi~+-,!bkW9…[mb”0+: .}ĺxܶ9&Fq1%o++ ~ov.,ƊSi%6ܾDDDDDD`ow>{N]iѢ999+8e~NZ6G_PXmSkͫv5YcNˍ'n1p a\Y*KEaauUM<""""""R xM&Ca]Kr ..yv,(o]0'&;m=~2p]buC $ͬ[[E쭽5PZxkmsA 8*ܢ'OqcnnʎۧȦ̺$h x…x>wsLJ;6?~ 7,__ O`U);&""""""R[ kk/s!eձpOy~'эmc>"""""""Y)vLw&%bߗ*SYNx( W}8$""""""R{4kYFC6BC1[C8]&-"XQW\O\Irͅ<^k[q7殙\w]YH p۶Ļ}Bݯs """"""RɬiLfݜhjAOvO;n~OHmm͚֎u_V dm|'o,D”`d׾۷%j׈.\;9s woA)]oqo&lpɰ_-pHwk zR춛+""""""R |چ_sx…@vݺ1{ o k5ܘuEM.0Ɂ'7cϷ!D{:9hksas5fS.wrh'nթpDDDDDDdd=36;Ujۢ=amM;Hm_ni'ucߤ@5{n'=ִyژǔS)F!Z8b^;V?6DDDDDhAXwn= 376UI1o$zb훉|ɔSܥ3m!q\||0{g?/MҥKɮӦMgIcwHDDDDDW0=w׷ׯmoMۯ~P̕LNҪpQܓ5mw?xBEѨp񥗹!cv¢%KܰT/wcݵoИ{ُ)0Z%+Hłxyov̈w ommPo̖l^mW\(7fƤ 38Cܰ$][{,^,- XPlE*dbn{M}T>}zӇnXDDDDDD&׶.`cLn6[EOfxГ)""""""R[kX{}LNE'((=&'ƃP(־~}7f]楬: H;Pv,ѓDDDDDDDjuADRɭ6]HÍ{1w\DDDDDD6u׶ɎlAqW}T.\*ރsOPPݎMu_'qq"=1~y_/ʢurn(DZtܛ{S9|W؛o\!""""u5ZOP"BU5]OV|q'c"RS3+%o(y_??g3g91\kSjaBOP(F""""R~NVthUE ٷTV4fyBݸT|=w 7Sj w@1nY™MW[HְAk^#(jdUP4b"Rżx)l(͆2۳rny2wd~+u ̎eQww/{ t2cGDDDDcIpQѓ유<jP8W\opsRJ_;#4ҙ%DYf5 hФ 2abV߬ r =קy&DKr!ޘV-."oEhؘ 24"s[5a5mJX4lޚ&zB j܀,""""K ͳ95U>$*Rf [DBֽU(+UW:A g2>O*? hy8tNҋf).+ |u1|5␑x,ˋ#xl\ ylWBr^~/~µDcw;еw_MzGVE/ןwz!Bhk_=4- Lk)C{ }c'$7GFm`;dX?\EDDDFukqH.'HMT0jCᢲ}jE0JfXJtvI^9Wgeo3'fq IG/[hAAmiEV o->yW<5Q>xQ6qsss㌽7@ߍ_aZF""""d׷jwʞd''"U(kz{F~:!n |gP$ ^>?G_o'QU-gch!2۴y B0pS>Tl@g-Byu߻kJGt ߽S(˛;wo爈H$M6/HeW)߿qTrEBgO ( n*co8^Q eȀhW e;ݞc8C9`UEk=!-f{~g>g{V~; LÎsIw&x~8?hͷ,,-Ípʭ7piV,^?~>櫢ms||y&WB9تFQx^S^z!-Pfu!CfiW\E|_~JJeݚJnUU'*%"Ґ//c9c X1S={v<|8;g|,g5G65ppw~DC+JT~C~*>t.*$GJ5~};8 -L;㸤Rsh{1>76/T>˭ö-~O2傱̏ ÏjUh('Ш@.y9=1uEw/4""""\Ժf}EIۏTDnx߳>\]]?_s=kL`ϏˌVq!+t"-^GZ%{yȊ@UH{V"oeE^ dO⼅"sGzEXhVfWgPP>v6 ^ּx^2/TZwfUu"'+"Hog#&o~_KbW`^?|6"}Gف%=rwq?gl(o4@7b7sH\at?:C,EEDDDʨT~Ņ*$لZ3oɷg]rXfD^.S/|LsǞx9^FnPq!Up4~8BMaڭ1%EY?~Nz 3חޫxZ*,ЍFi\^=DDDDĨs9udHMOç¼+gϠ_͕eq~;Av'zݛ`iޯ)0yn7(sq|g(+-=Tdԣq&4Ipj:!"""kVx "`UhBY|,+Pv >|߃b'2.VT)`oxͱoܩ/09{tItBĮȷd@DDDDl6fIx9zn>vyꗔW@#xw-:e3ސF~(:d{Ee @tlLmuim\(toP ˯,Dsٶc{;Y㧙KDDDd3٭7,vx9wݑ;Agqϗc]7R߅ }\[KM>Û'7o_W%lak"ac$]r';R]W~Se_ײ|wzrȮY%?bjR9a:'Lo^27Y|M9_S"""""֭3Tm OnzR#so?x+7m26# zQOqӡέ"5zBB!Bh./?Ģ wgw;ѣvoՔ!W/bǻUR oDl6 u>Ͱ[Ȥ٧gFAV"mg)苑v!~ӧ6d7OhC|+ECdn mQf<"]dX:` cNoĨk^Z=&,Vxw2v\D'(!ݏWmȟ'oeԻsyP:ׇp8<}fҬב\s h6Ͻq`Oq[m>lX2ߝ-I.#osgR~c?1Δpf4YUWt8"մߊac{tK8؋zWsBm9⪋vE3D'n'y@ODDDDD6-hTd{oşc_|<\w : OϞ=sFgwwh(:5w=o/ǷdGpcpkaN}n?#j}aFkzq9O9?|Ww Fl뿸滯{Z=޹9ƛG4]~8'cW`Ž1s8K '/3]W䵯~{a~2(ӗ]g-/~^Swa/溱|.yO6-:-:~MD~掜?bߓ ^qڢiICm{yi8{_elÑ/`؄$U~Sfh^bs"rs M'AFӊl:[ΪNhĞ׼'6;O`W$z+Ը+{mO>3YS|8;CAg`se~M?:'͛pKvػm!ҚJ>!V;CȤ޻ʥ%ЀO㌾miT_]8hHޜr>4,^J0>3>3'-^p,}q9E>ÿw⌋M۱]ۆ g1!Q 5gܕ$+ epŻ/Szs̿vcٸ/f}zeB6ؿguuKcxk8-m5^Fp$MбϾqxd+:s7Z?_+ѿ4F8AV۱ӁpOq~m3^4z_ /u' ލ[Qfp8Bfflյ/NƼʨzP9tʭ/d=Т!0LlOs%#x{8eu=n%'P9tp92:wp.g< z@_g>%y!%ҌpV(Y{HF=eŪ"Z]$Z-.gyϧ.0!jmɓ3YF,gf%s g6-J*cU+YӨ-mglEPlp|rV6lMvH6d{+Y2JtrV6lKwl !LJq!EV $g5\;K!hK?t2ܒV-Jc8h-pDGG#Io.\.\55n8}wGwFEK[rþFХtoHE2ݑq-܉^ܸH%pQkez,;'5rEO4/ށ|?PB>܈M",#9DײzM:W:/G o1+yعYOrqށPC6%k Q5Y5JnE+=hqE, _0h3 ۏ9D8--VlXŪ<rZвyk[CEAgKa$KoMr?x5yE|4ݻ" &MʙeEyD7de^ ڊ!8S>%k6`7 #E߾S?[NJUm$;YDbQVXMftn&|3㼥%ұ[ "(Z;W^S'I8`?=K 0~{_2<,W0kRV1?Y^̷oL,7Ck'?K6Qf.fem"Mi3Ů^@*\"^ ~{FN;?;ؗ~'Äy]"=+x1\pv+>H:x=j!{+hB<FOneu؃1Ks'q18aa E IDATAlHgד/c9c9īyA lS7j:x5܋'f#rȑ ^2adI#%xܴdF .}`Wį+"/\Ї7ʞ9q=""""""~yA1v߽nا"6lӬӊovی~VE~w﷯u.]Jvv7Tڗ_.;EDDDD4kd8ߊox s􋬾W3m/f}wH6VF?lZ*\H…Z*\H…Z*\H…Z*\H…Z*\H…Z*\H…Z*\H…Zin@D hig0|zkvL8z*\lMYJݽ[גXMXWȹ?W䎈nI wD Xz5PN&MB3WZ,XPㅋs*. h+=SN{nnXDDDyylt p!)cnV̤~nXmܸ 熪]^*ZHK]abZ-HJa&oc原 5\~(Ds~≫O2`Сr)H+.$e[1ܶ}klϧk׮4l԰$ /ȯѥӜWWko޷Ӳp.+;Ѳh Og$Sٕ&'KX=86?:Woq]oOxKܰOc|/5*Jʹ2-hC@D roL2#̝ @>[E(E3\5{D I[ҿ7W|w#'ڍV@z:k(߬8!+E;qҩ<dbؿ`؝* h;}GQ} nڦ)$PC)@CEAMISQREPDB(?Wi B IHlGa3$A z>3sϽ;3fݙ3 =0`k/49;A2ws(&ھӏ9O2}]<ʕ6"VK`EJV-n$B! 9I\G_B@;sLZ͚5z*o΍-[W,k_T)L֩9ҸEI&!I|60%%TwŽ(N2 IvS݃"dOjJ#1'>ޖy9JVfF?ƆZVg3J]# x,q/W,/Bz.)B!Da$ C-a-v,jITh4I\h=Qv=u]:⸦&.Mٟ s\,qAk.F(3B&!Fbs uSiᘳQ ТkzfB^:#F1:&hB!:9q?իWWQLu['3Kg ]yX9Ͷ(d&Ub5^>#4Є+l[?'s AſeʟiܯERϳv!RVhIoTHi=y?gċqۣ*RL˒!BgG_B@b߾}PjUt:CyĊxVhb,ycdC3VƛSax.TЃYc[lk$~0ߦaU=:RJjuyi, $giq*UG}$;geC\ϴޡUB0tB!xșxdQ: &ߺ'aO<B!0ąxd$ P?!?%o ?.WMqąB!Ŀ$.#Q'+ ~|BUPР!!Bąxd8{:@K?PdSח.]:'< !B!x6HB<fٜ[gXGaB!B'GK&(xolbLdΚ9qϊ3IpU% $C7Y21ގlȫc?g˧<_LD̷X; 3Y4Nar_좾fX,ulI3u ^NooƛTs;Y6B!BN#Qٌl-< gggs)))OͭKHH 333 [-S%+Bʏ{z/^{Q2NqG}a&ފ&MiҲÖ%p{BoAo@ă pٲNpսMii $ɞBt!׏ٟY8LDc1ƔqCZzAu(x;@\H U2cd]Xoyo}~e ݷ!n:-UFk#H&?mߏKx_:w@cEpT;Λw#B!q!u:f]o4i҄7nVJ!=rMOx!Tx!8Kw$NpcY ^u;d-㖳u{ ׯdyOo@!i,h?O|DYG;l9?+}v7WAE*lH#N>7A׃! b `'R〣}: ަB!{HBt2pKo !B-B!aMWu{\;&pjO둬ۖM8Jܬ__7#=ѢŭX3xkRn խF]|;FaD$z_O%]ٰyQ<+{*_@,sI/OkO_')y`=7 RIJ'}}AwgrՕwIӠ +PW'+:.*J%.&E9I\!BS:!uºxXB<xb21hN@7HB!# H *R=+)x tUyeB!xHB<$uH !B$q!EB! YRR@Dt$uH!B!3L/矹u:L!B!>I\LӑQHOOGIB!B!Ez(#%JƍV- V !B!xHB<*UDjjjnxy83z%KY$-{ o~"ޡ}Y򗘒xzRvfM=c;y[Th؅npy  |ya@S0}x[ڄ xam˓ ̘-|8amޞ{*$s|$&8e37 𐄨B!WVZjOƑJqkݽ4_gˆs Ӻ#3}C;I\ o>YfN}ܳbL%\U;PMLlc&1&)a}|8 \*a؇S46 <&-{xT|]u.-[,[Hv َncȡ ZX#kOow6,F{9T@,sI/OkO_'ovx `~ЀXּzaQwѕwIӠ h IDAT+PW'+:.*J%.&E9I\!B_S^NM@x1Ę~#`N3rR$qB!x{^'LD/N͚uQ56QS^ w=QC.::N Mn9eBoAo@ădaըWk&4>?S+_Э`6 ;EiИͺ0lR-;ϼʶYhHm1i= 4ίm80b,Kx,&}ɱZZc8ۡw-K:sUU_bȎCu](5ӯhtˀ%Kx#1]7x͑`$%/;"_dM\!B ~&3y{nmGaLOR:vHe!h>;"C:@GNz+\LEGKĆ>H"GtL*UqDb9Yp!BM"ƖbZйY)T­bTV4YA%uC,!A6+#.31eg<?@CJ;_|Of~A]Ims4'b;/H@nX xP86gȶTqգׁփځu)UɺG4G"ڠM\sqS<^Cb:4x7wwS:7tVBT??B<4]D4 [7o7qlv*渝L~#ߠ iF4z0aP lp}Gt ~B!LHz}=`A?f{ڔ=j"%\7n_t65qxT3kgu`a+OZ?-\t,zWjpes*`[|>mf62Ff{Y7׸͌=3-E+UӉGf|ޥ%WXiKݲC|JvǨaNLVɦ(^_jq-ngNk&Ӭ1؄[,͙'xig ",dJ(5ξ\:I1Ex -'o"> uﰐh8dz( ;7n0%}ဓ^B! B ֛fY35^'mТ{Jua}k޿+b;twȻ!=r 9w#HQ4PͬW+Szfuڞ&/J#wj-(Ej._mȫ7]Mٯ4]Ɔy.O t~ &% !yGFl”FZCփTC׮%bP@[:'$̤^Xҭں0,MˉIGɊ9S-cfFA4hw6m1W'!ȹAnNM!MɞmOꁛs 6ֹY]e^ԕfoRm(]aSyLlt!"hT>H><v?S1ۻ3kT@4y:ǐP^f,n g5:NlglZ>a"G+#PKWS'DŽqmKs%PY/~)L¤Z/BRXUgC߯O:5*y{1(z縦JU f`"rU-%#*DK>nqlWs |7tǰ1 Dhpڑ K;2A]˖9;YWQeq%یzNvCW`Tv94.9u=B!i\(hݨׁY3{SIyi̘56SIycUwZy#{WȤ掠Qh56L|ÌV}1F kоUJ_ȩU3Ț)&9KS0%䶩)hN@7ܧWB!(s~ Yeb泮tVj6Veˢ%{ЀlX[-e[~:q($N"",FI\\pMCoڳo? |}+B!τB'ȵX@`YL@ln7[M9e#c-eUYɉY&S+,euAD'gev7j7kHxB!B!-dx=9ƍ43)ߛYÚn*B!$ 7`)B!B!-dB!B! -I\!B!Вą_N!>r}WcR !B! ;I\! L~ Z} uݣeFьxڌx=WyR'7;gr0|RA0a?l;?7iШ f̘-L~54s><[md/Bx6`!B!x:$q!(Rd"*kDZ7)"3+~g;c߱/ udtt7_̦%YS4+ޝv(!vw ){f2|>+qw,"7S!⩓ąRHر2$^ԥsaܶ xE72QWޚ.nox+naf?ڇ8)!`\4~s]ZlEGRnqt$( [aNLEiИͺ0lR1G~۳'QXAL{1eл^PJ~0gN:)HXn$1]7x͑`̻q Khl׃j"yS2B!O<UQ`349M\hk6_{Wj!e'~x&+NJd%^"P ;uVZHRRl8UҬ6ud Sg/b(P}]@l0Qa&tIu73WLGfЪ-.ZN>2o{^ڍIwXH%a TR.s*ghyU }ʑ9s# +ik,AtLc]qDb9D !B} ! ӅhE s?Yq>C*x^g-[%փ;qᇵl?j>^dg%+P6(6&掖"(WDjeo5l`OTHMw !Q:t6hA\.w.M 7͛xloҐw2GSQfCvz-5z0am lp[}z48ڧސB!IBQdڍ-iВa⸰q?eu氇>JB +FuEQ,>{Ę~e./nO"=h/un/}ל7ZZ*9bNkd.`{"ϥs|^o:vL0zp]6y8U\п/ ~3;iR`0 GկqI7XNZNzB!x LQE<n7.=έ/V3~Ǝ^e`[&=DZ,r+_N"h(Rff>A ͝AQ,M[6boofV7*LRPgw'@,{vU_euD|%ܗ =i_2GNDS2ޱd$: E*TU>VI劎\M|)ɗTJgS!i30!D!{x?O%)Q+{)Մn{gNӯq &>^3RRt<f:Sz%<4Yd\oL[%v˜h(ZKs5Dr-kmNmE GۓFtTԇ1)Y Ĝz+Gwqm2̀)+Vujz`S:'$̤^XҭںbHڵD h֞adlZNdL:JV|͙ڭh)?B!Oۃoi !bJ?S$J>Q1,˿g/gߓ9T1Aem:;"&0}s4:{T$dX:xjuºxXrH!Ŀ)*ХcIZ!B !!B!$.?*ɐő+IL,ED 17z仁B!B<-2TDQ(I|߿>Uk?'J"ҠfZucO.#ܦ%iODjn_4g OOڙ-|:)}=[ ? < w0ToZӠQ;=70J9">‹ϏF-2x1<ȕɯQ4zGnT9t~kL؀{,B!;ɅhT1-'Ȱe9Jx?qjҬߏZ2#%{2{n~:O}b!Ƥ~Ӑ/fy>K]ԘolbL05q|*gN2}%[|3~d̷fmy _fΏ鈻LѬxwOcѣ߆9#Xk&g&Wb'}R9)8]!BSd޹6]dC|(j[}u)8xZ؄ƭ0}gx{;E5n@,% Qȋ [uT4%loPaA#茶}st i_?4q`m_Ŷ%9l!'k c0.5[3|(|O}Β o8t9k&eP=OMlOӕ/i6vʫSO9e,$wF?h޲=cH$[Ѥ?MZvcң?}夋u_r ֘2v]R/%TRZ]3o'h Jf,7h4(-.>!4ԝ.Lv=!6MŹj7hm`s/q Khl׃j"yS2B!O$.ݚnOREgn :PCc{!qt.LX3_<ˇuc;V18`Ž(1l%d,?>0Um%kN`9a}PPH90vq$;+7]OBqշƭ)-pȅܤKʎ!ȁ bk ,ޢM'+F̤oM=c"ؽc3[`wŮr#V _{|/MymYH0ڴ#|4pŔr\0ZxݹofE9c5TtDlS(qDdPrM4T2/T!Bw9Sd[ UVQW#LaN:, ESvkhh׍Gm IDAT~WDҾA) lLONs ;]>(EL@kt(Z9ݶs庙܍Yz 8j!UJf8tҵZNpRUœ­[\q)ɷN3 |:~A]I܊gy@1 )wӽ)l[8Zr_"km\ޯ}<:]D %/Q1M&N&>a NE!dVؔXJKu lH#N>7A׃! b `'R〣}:}7B!Modbu:UVnf /-t9cR:Z7KfŬ9xd]V{IO@S˪g^8%œ@ywI:fs$J;27(È<< sF"/c\$,5la@;7oZy;i| N8j8ꍤ]Nu:i8M!BWgB<&KBIO/u!Y h4.Atn>"MJ8l8lSuan~@[̕gP6E>i huUϫYHEXc7;wz~=nÜpxL84EQTw}hN٭8Z܊{?56. Raʁ1Yޓ_d/P!wçEOگX7yFɻGtzj#t9&U ЕwIӠ +PW'+:.*J%.&E9I\!B=[+B-ui.#pME=[N+ ;DU-J\!tܩus\}m$ןvW]|>{GINyYnzu\ܷ,T&Mln*Sen3wIԷOosǒԼY3sy(KE/ryeF{&Ur{ȩ@kVa+2a!OH:,)78%~Wݙ_ϕp>sVQKj:9 (\ZZEM0eΪ5jjZX@@p#'89Ԩ*5Xi; P+V.*xSri-U DQ07QQt"@KAp-VAp\$ @ @`(`( X RU\r U\䭫Me5-!@ = Ep,X, `Y.e\"Ep,X, `Y.e\"Ep,ࢬ0{^jpyc5Ud~FZ\_NOKv/?^E&#jڼg}1fVeǖf.^_O.wӱ b732jjc}zc^ I2Ҵusjٺ: |@/>ҧ4m6==N97MVW@}t=8W> }賏׵WvP5乙zjۺXov/0ǧz|hmQ>V".홚tunZ-:_ӷ(].󜆽FR+{{G}=յp}6kv{^2+e.^>yzξjߦZ]~'O__ޝګu^q ̔$C~GTvԺպ~L=P.8[pj竵+7)[RoQ)?jժzZp9[u[2^Ls~B;ӞkL}?H\+xX1=]=^+hRz㍹J0$סyzvDߏҼǟ׌8l>O~E+VWZjk钾c4npU h77RZރuME~Yj^`tzSW~D՟J~_YO^ߞ{\v9%ek5fS3Tzocթ:C-YB+|1Q"Y"(|VV]riH G[ܥ;'hMUVY& TŚQ7> 5V#VNujѹc+e(iZ^:ףmEޑkpuZ~`SXӍ CaͻMA;8|AմbB6$]BէSI:Tj]P-;(WF͚wܦjiuth"m7Uڹ[尜QW'Z>'>;~Qd WQdH<W#r*SQ-O$l9vn04\J@ʷԝ(2eH3FbE?%&Pt%)<2Bv{8՟f].Pʑ7g+L "l~zExL& 83a-* i_}&Nu=K=KI+G \ThP|2U1mڙ(qT{6P1d*k-GܜE?&Quo#I6LoզuGYMC5dSDg;C5ռi+u-JrG#G\W!7'z* i!jJ-~Ԟ,ȓJanQ=_\l+uL6L̇kuE[ו;eW6վ ׫c?q:8AtHWht?lvkdY=9 V:tR㏩9iƝ]7wxb?ɶMy+ڽ>^uwKmwq$9eҺեSGs3*{& xTihl@w<]F/HHHPTTcy&IR>MK.Sfߢ,-anJkVss yBaI))Tvzwם^u#ͽ޼my}nm;+.Peh4`ݜ&g|}.0nΉ2)k:I_]uNRs(ǘ˸ebnX"Ep,X, `Y.epf+=fn,JV\"Ep,X, `Y.e\"Ep,X, `Y.e\"cnN]s PX+.P(+-f{ZO?9lfNYvړkn=ɹvf@)Cp66[I.s$e,*pf.r>6UPH]$)i(%˥42r@pfI5B|Tܥ@+8TCqiN+.j(16ԠBPKs*>r>6E .*Up(צ9p(15B|oWЖC9ړC!%[(i(߮KCbFpᾧ$HUʱS2I1v&}jLp!@pqiN&pK9R|S.>(!yj00ƺ %g1.>.P"?cݏ\|.P"Rn]7tߔXŇ%}J ?]r $P2r OQ'E]u}$Iiγ'l{wSrkS] #}TW0QǦJ)\ڛ="Cpc]⣘TMsjoJ [E%0s̻E]:aFp "#Оd.ީp\଴Sxmjgn2 KsT3W _3߁V{LԮ6oaMNŊ V0J+.e\"Ep,X, `Y.e\"Ep,X, `Y.e\"Ep,X, `Y.e\"Ep,X, C?F~Æ0 K%}3@sX9>I}GRřqT5$SV#UGrIiy*gN3s~[yBl:'AavHߟ\J?[idS>~|oj14K5%J_6?FִGtO O}TۦYO㏌֏㕛m+4d nFuxDiWņT=W6)yKUJNPF7릫*4Nl RE~ԲջnWD I9/ۯ飧vϻz{Uٲ垚a~ߺNzѪkGNZ Tttg[,:PjԀzo:~V]coSHh:>6C756ߴPtXupnܥ)r:3tdm֮,[=u+&-Ԫ)$"U%!{pǝK{7+65G/ v*'ǐM%'U*/gNXmϦi[b r{s)rqGҲ_jځCtBL#5]=JMnT(ʝա[ś琯.M1|ٻl4<_SbCUӺM9ѬԮ$|Vn͓uOwTM\jq(T);U{ۻn.Ul$9{}bU/~w=Hr*u˯f+s3`9Ren3wIԷOosǒԼY3sy(KERÚ-\dBCtXRn~qJ1ս.3+;F~{y8Eq v.Ep,X, { IDAT`Y.e\"Ep,Xg֮ s >Ep,X, `Y.e\"Ep,Xm۶]T^]ĘF.f SR45{ F<=J!'.N\*^[ YgkAJIM5w.B(qcǽc%I6ԋcF1ըaCIx.R(Q6ԗOא5d`}tOx1s,JFt}}}uXʼnsDxz%''KBCCe>^n]Zժ'5j߮i@Y@p"ifCX\w =p}2.(44TkQBB;u{9N-ZYzqX4o Ejڵa:v$~zUv-=ӊVLiZիW$EEEѣuݬ?m۶)_s @ٵk{AOhѿ_?0yFNתYSwUv-}t=h͚=;u:(;\=zTw{RRS%I7 ^L_dv٣&g>i|IR@@&~ !y[v[I%+kK/n/o>x)Iy,Əʕc$I_|o=PFK\ޘ_!Izq+W4h̚3Go$|zqIaz)Ce˶۵zIRվ};ӈƔ)ύN|WҎ; Ͽ³}ۭx0ʤImϦOl _.$Uuh[<֮].Iء\r$ie?S\\$m۶lgޏ?Il6ڴi#)H= P\[޳ݦukh"ǣz?|%8gqڵky~C>PU Iܱ P\%%%yýz^PP4p@s)%:$N:r|(vXhWϹv@OǑiKNNlJ? AG IjѢZhan>TvPPWRH϶ sGy#9loy!x&(.pΪW?zJֆ?lW'@GpsִiSSb/zK…yMzΙP$IwпFЎ;%I;u0f8/ݻul'^=%c{u( .p^]T,I˯~ӈ~}WK*W֕ݻFJ; ???=M44L4I=(???@iGpkT$I,8ѴigIRuuM߾nqc/IzIZ|iTY|geƍ}Qv;PnEQÆ⋒$ө׏?duxhN$饱cըaC(@YAp"sM>gݒ,=\̜w&zu|QK0W#%uߦ\ w.Rdp.vwj3^ͽ:u.W5KAn>>JC{vTV㎉ZwR=G{vQ㎉%o(Ojۮ:|Ho8$&}ujF#,_4%{:L;W뎽tڙ7oã뻱gj* }~>p5\ ]>QI+ք&hw~?CRg-u{,~gR _7,Ѫ_n^<=; nPK~[GFikFKR~4Boꩩ WhOS58W-K5g֦k̦f7k~-:8YCY?o ӌ%+s3d/ n zwn 5Ow,үE4еwQeP]Wu*ŝ4ԵW$*ֹn~?hyt_9vzGi2r6_(.Fשo5kN:q:d ׵ҡŋ=?TWZrvɷRuп<+:=.P_ח nt+P,y@g/p阣ZR9I8v\#T.9cӍ]vQz WU;ʝTH(UߏDNѲzh#+[(#?G*seM>\X asȝ9i;Mk!iW #IՖ[u1IҎ;uwj#;<p @z=jժ{U=5ROk;h߾}r\zudM=<|X@ Pf͙sBhq3 п@h!I8Ai5kMJj^;S?'HѣuyƎe{￯ezlHӈ3{lHlBR^ @=.P,;/SfԨshSݮgFR$I_~zBp\OHPNN n+8(Hp_aunn6o٢4sJX`@ԩ}sŞK 5kz~`iѼխkQxU͵v:iڵоyXV\\($$܅uLGddM7jKmB ׮ݻTvӞ3^%'΍\BظqgSǎ^=cm4_)fP)7ysοXZXDtt222xx}|)scRsÊ ظ8v͚5zMZ5=s@`|bR9(8!(8B ^Fa:t$7 lv``WϹ{n(-ú87/_޳snJ~,^93+q,BB B+q/\xbNJ jժz{g{n( I[sQ#9(DžQ#ι)8CŏŢe ѣ#Ffy(<0p/P:PS st9EpG{\6>.uMY*n\*bѠ~}UREWp~^$J*jPi B k|(.P,l6.O}5pRRS5 >pW1tf 弊!E D33_(.P.Pl4Hj}aujt`$VZ4piXB)b yCgfH2?bb>A'aC9tD WVfV>鋡33_(.P.Pl&OzQk׭o;L# ھcx֮[')P_i$yoJwq)qR\.lq=2p\L% Pq-j-[67D#))Ij*0#E;W.׶#%r=s;72iM˖ 9mVI=5:a6>I߅+(>ܜŪ^ݺD d} :j _M6Qr$孰ذ0sN$O_]=52gCM|\$)R%SO!JwHTJf C"uI$Ov{V~_(}sR yM{$G;ɧt8Qqy$%iʒb`z)㌔}>e&&ʅFZ.!O__ſ?ĭZݡm*WF~mXZsLlUv \[5mDpb׭kW}:mx!JLԬ9s4kIRhH$)9%aȊ֔).(=8WIRN2Ց]P9]ZRjze^Bu%KT~=EGXi_ԹKsb:Vykqg[u2 ɹm42Q|Ve~;#GBАPe公R^xtɯG&$5n@vC4ڤm[Լ]WaZIڪ pH2\I lŷ@GЖ!E*"J:5פ3k~=},Ӎ7ܠ3Ln(U8-]:u,I5ᅑܤQNU~msP4@hRe{@)Y.ŨvݥəʵSŚ T7;rϭ?%-P^`9$ɕ;w| uiZߢYw.&giUTv4ʈӮm= T1*(\]2LaAduE||~sxC\Gu`HTvKrѠ*KQm̜\>ATjEȦ?%&= {WƯЇ?iV7AMM_k_j忙BzLwaw5ePt1wUˮTo юoϖjgSPa#tWJ2k:mv9vYOĽv$▿qo֖dUwnk7ҬTԪ칛57w?h݁E6ՐGCO0LoG$i?eVZ7޵K-[v.w_sd RT0+SYhcIg.LΒTXtYrJܸBBZYrɩĭisrhJHݥUmE2uhvKU|T.֎QyVTRxwXնEԿia6l!>Iٯ];pKvU]WeKZk)(eRmU NwܜG"ȼ7F2|Im%D>`H#E$  |mU;&z5RFQ}6MSTrtߴۿZ ֑۴3|U>B TzN{H6EfZ ܧ UMW)*jڪO(sCpx\wvf͙+Wj]:$IW:նm[WѦ*܏4ޡ;ԩsqQp 6ʮ #Rr)GqդY{3Zmِ*7Q}UvᨆtHCɊi\m+8KSJ=#.o}B|J;E7o˺ wk-:HP?yZ4}[+5Z5 ond s|O?&::w &wha3+s`毠JuE`۳uv=rGauY冪'eبu+b8_Gc[b>4=6!XJ襧U5E2AWi +nPUK}hԽ_VSk+yGzrhVGiKM}5\zdͪ?S^XJiR(eN?2$OO{wUu33! ,bŕگݺT۪bK_[mm[O[QVqAA@@BBȞ3'9y;w23$|ޯ<Ͻ3so9'w&8@x>;k{Œŗcӌw׵j^}L2CL6jQ]]!?@jÞDUkbo8M~g2h j" IDAT28 ijTT , UUh\_5?ņqXz}*|U&۲Kl)# ^;Xv/GXͻŚihݷ])G_:Pu9 MlZ6bh<ɈDzŏ<,CF_p i--E'%)U[=\x]FyFQ}Ɒ l8P}>H_j |-C|`|2m|;=>aeyиg=>^k!$oݷk67ai-u_τr;G{EבkI $JR\z%xo[o,Ǻ5bݚOK/D []x9s&JJe9s&|s9w ۯc !5,gHE ZZ"df0? 2 dج>" H-}}H-B^Z#-ڏ={ZP4h rSx|;`J=] ~s1pH>ҽDɐH܉f V^myHXbBk06~[ii)f͞7s]^ o,f )|kIENA}"*kъF|kͽg ςcǡ_wvױfhfEߑgsJBwKXϩ.t0bBA CgMةiD^뎭,{Guߺu ys_xвk|o, o>65cU_ݵ8 ތb+*V#5?PؿUTTUf쯮GvaR(݌Я+6!CFO>}FԸ@0 ]ؗCJ2%UjzME`@vƼb6m {\"KLd$ M)߃2:_ǙV@?i>/^/ -(Ҍ*T:gYZ+Cj٠НddDY]S@+v큧t!Eec[CQ\^K,qADDhk_^ofΚҲڒ2;soJ Ҍf 6if4#)>, Toy P-5--z M@3Z'-x`" ih#kB/\#-hnh{Rsu =HJJ0sl,=xwYg$ڄK5^ո_oͰ<X-d V{m}uh@3XhJy SqT]O*QݧE9OQ *TVr>4ox:>w,OWx*L4Ec<^{+pʋj&@׵j_5PTB /᭶`Y~,X,䧷=sN1b9;-_Ge|{8a\8C,e8ba(5;F# jl|mlR@VV|PU㇯bR BanT}PuG=jnu+/`_Z^,dZg&_(f-XζP1`(.׻+X=~ZwB1=3 ^uAj^6W%~(Bw>A 5)|WXiZb!=/]{HKk75X Vnx2 X>LdfHصpႺ]CC<%""<~ 2̜5 ׯw#e;*j#W} ڊJ4\?ICzj3,*jBcii>xґAm{ZMhB R=XiHע%[[w|WqP Qp]¯Xع3gQ Zv}Bž"yaMߊUZHN"խŞz r`ZyyHM،Mp,Aa~*Bq{ʫ_X7yvxa~@,PwSxS^ T"D &OM6EJJ }v0wnoy|P-PUg - )Eqz.TpL|YEkނʊfԤc`@*Qv1J@+"od |7"wa(JRRI 4gքny1.HpW?d=[JaT~"x"\aԝ[ !W؛R +ox.L<)HM񠹩@/X-h ^@TN!} N1:;:tp N&JqÍ7N< &NN8$sqÍ7b KQ]]-CDYm,7oAa֬<߃]z֣z|X2=bX}d, ۶bKZPc ʭby*FiZgN40͂O! 3c~Z,-vD/]4Hds mdvh"[\XH|덿{j]|---ffO* s"CC-հ <,v}P8c>&f4 |N즷Уo3$M L>yZ=g7!VT}]Qd`٨]jm(€GMXb-Z8RYA Gx{޴l#V` R}iW´1< >ܾCי}`6or+~wMC_ g@!,xU?so*ф :W/Rĉ5'qGg}|ϸƳNe}^{. \ y)n~ /ŸRQ0X8i|uqzN'vj;Ot 5[lQg/1w{ ?|H[c"SX?vǕrk_i(*æP:u ݢ\Aj +ؾ;sopD?dkXMF+YEѯ8 B8bflZj4)чf!th_z:6)GqFS]L>M}{ }jm@6N 5j\XUpU0{2LB]]{ <#6YYY(..[zQ.//]p;ӧLg>r/Po&0Eif#}_/S0fpd~@VV&y/_3fȰcM{+Vp/w bjϩoQF9^H.~ iAp>T_aо g2rs-c3ө@}hch>UV%oɾZ֑M>%x37T!iӦ30q}ECCG[o+V`MSUWW݇~8 :KD%g4쯁T/ر?9nj=םqP,Zvc(34l{OR1?G QD:^jFcc)}գ8S7'ïnK^X!>q\qe>m|O 33CƐq7+?V_,\{7ꗼzP,-r]-IAf!=?:NOsm1 `SOwoc/u [QqWRW;ƝajO-M-.\P\ ku붶 pWcIZet|>f{,f{,V>|j^'k>F%$"J"bzCౘ8X]Hyנk2Yw=d<{9͵ ߑ8F{Ez=P" 7 /j[|5ŏĴh!M< -~^}u۝^ 7j"""""" pA1j\t%mgѿ?v܅J\x%㏡Lu?Lx ?%K^6D: b׮]<]h ?k.bBQED,x"cE u!W loD`ǖ|-J$.\P<233An~If\P9""""r~4gQ/Fjtv;.ԋ!cwrU.dZ]'G[#UpI7NNȅ+;#rݜ [/|Q/0|uh9<͜wAp}q)|ЊMy>㲻p=\UIJ,3OǴo|-54c?= ̚v4&~Zw@>n×WŔcW+ë\?gŒ3.¼S1_='ƺ+杀o\Wk<\bp,<{%&v6|?^ LJ+x'cJW j|&6}ь5۟Ny/~c}ƒ~X3~^ZE>>hQ-x?ë~xo,>7Nz3V<" ~XW D̷_k݆W_^vBͲΘ_{^+Ľw/N@^kwyy,}G9W= |=;݈(f\}p]wtGV-V{9zf\W Xw|V=eZêV|6.Ȕ]Ȳ,sϢ ^ܸp!V\!xp ?ս7{6u1d;[ypm}̺z&hw,W.ybðe*TY~|+&cvS~_/<<?ߚ/ćK7W 7> `.>X -,ó. \5| >Ɂ>OcwbN xmD_Q8Q<.t.51 IDAT:m(@jl?m{68gDDDD .oMAzz{Ϳy?u"?u( 2ӑ7GyO?o|_/71?}~x4D__t1&O;-/.ć~ءs,gjxt0|~9?aMObo·N>ǝpwK&'.^ iuspS ?[Ynd;3탊P] ޹O[ǼYsӗ-;Y' e~Bw[;?7{nj)nbx+\慙Nb3q:h_hT }݄o5`98nF>}3ԯiCćFVr?^a.;ӏo- }S[6Ҋ*}yڬб5/XZ@"PKBM~(8(l݃k+sFDDDDR?wMkll}d7wߍ_Xl~pܘ4KŨY3Pa%VbZƒœ?9cƯǦMqa&MdxqayWba;lz?es2Ư//k^{ v=/y}hzɷBzsS_ a(򐟾7BG""""~8w+.)%^_} @}C#Ꮠ^/lsOn: s@z< <ȝ}B.,3~+3d>|>_yĉq g^[Æ ۿ5_Ħ=/yge|O~!|>nV?&`YD0`Y~T݇ Sq)?S|h =Ň @zJW޺ X?>~nkfj'yMcI#HN. dbWgw F's2|o6ҖހN' u46{O@bӮ#0}b1qpwfcc0muOP\vO1|u8aL97~1жL: ݘW\pTL<'^y?^nVoLjܩ0z޷0A+? W93|"v Gq&b-'c~='89L\yޥEEc"zu$V^I`IyQ0xJ[Oƞ?ވ[v̸bv)'G Ws&NnÍ oWiڡ98'xlb<=VxZ0ҽ y׋jE(؏*[<+C+ KҥxixWpmc }(/Ʃw>_^z=Ljőڮ6ֹ)x:tHXp#yX'I̋.̽+4skXwWߏ㯖 .S+ۇ#` (4nyf,y9c/|G㲻em{}[Re#m|q&n⛸=|9g#iCpmW[ZYgDDDDd/q?z=8 pܹXtۭ1N|&*:~2wᓗEOg8km Gn˸yv*/.L8 n'8ȣpii{,T.r"<%m(‚yE7Py£E~H߼8 suK8>p|L~镱aF#*6oCӀ`3/)Gह}q<S?fbY횛k` 篑vdm$&L".,[S'Tϙ2qKuŐTjG_݆>:Iyq4p ƍ۹k a[1}Ʒ'i8qgEQݾA-7 f|sѣz㡇QG[ncْ55g(F'aKl<Zm[+\k^_I˦`bDyXxW=~?D2P||\hgXk1܅)^@J@L:mh~f8+BMur41..iTg㪯o=hq9k>m+>?QT?E4/KZ3@>xu]|}1dٸƋ1@mϞ=())6hjj7![[8a lŊ5s SxM :6˗/nj3dȲ,U1S_'r J".bahb$ȋ)/XcF:cE #"""zq  Zo.Ws܀H1E`uZ@aTroBD ׋FaGQCk_Pwb[ӹZpB;-X^iz\KDDDDDjuO_o%r+2gqN.,!jdLyR y~0꫻.ODDDDD,igM &:w ;/}1`Inj\E$$dLݐBʻ6 '""""ne';G`-;m!cK^B"ڪ5No%qjDDDDDy wN\9kʘ"*.L,߁\SN~ ߝ?e%Lse^IXR΅ wWo0-HBoApQCk^wTz 6[ȕ .Gi)rdggpLFI sw(߳9._>ߕa9O1treS)=Z\Dj ULqB-EUU \jmmŚ"z#@JJwwQoUSS/܈z"ƠA渀~|~=d@Nv6 :r/PT[@hkjCXݡ&rQD.-)3MabVdʾ JJJ Ə+DDDDDy(jkke\r3ŘyFn_VS$sr+ŻL. X踏[7]7EDQ7ΎvBGsW wIwLnȱ'*uEuv'T] E *nE%""""""J6i#}Ovsb%c-O˓n/z(sW}bN[7D.\H^cywT܇(>UA|Yc]3" ЩD^usʜG!""""""J6/Ms^dcKt2:;VY#""""""Jf4Usbs;?eB0'S $ 7SNT1Q2 /bG9:}F1M1IE8ũh e^oա8QB<8?VcO5|ϸ\ v'SBK#mM n u?K\$R>!”HuS z\ ՝!^>bjd\ż.ڨcx5|,Vk.R(YD,2&'r+DP[K˙[/> SŪ4\Q}8:շD_qE+.R︐,'2}=@p¯r~>oP m/V rCժ}SLƒ}"""""49v@h ℾj[̩cǐ's*d_'NJ]Kt…i5㦾~/ZsV(bڪ ܊Q[h< S $^mG=hyO#c4mbDDDDDD#5m2oU3ŁjzNA}?h!uZP .'SԷ/pa<+]V j!ABcNB䢅z.27ӷ^e]ppaz [xl5ַ*CL?j.NC m[hOb@QeHM_@jA2>1KE uWcS~xnI.B[X' 󄶪=mZP j1h?PP^SB6}]L˾$L1"""""496%5ד}}l1"]__TP}rC[Z_Qqɜdu\>V'cnī?yuբ~gPByDcwy@A(nZc*oe_)FDDDDDԓsA4?}9[9'cշ`)/@(U^M>Su:}5]pa! ~r} T *}qBY*Tu3bc_jjLXE'""""":ȹ۾O9S܂y@->y}AϩjTN_PE ƲV_5U/c]܍i]pa9}H%""""" Ls@;VFzS1STg!=GS.ҸKu…B_"ŀAƒZ|P5x z^7wrݢ.,O'MWWރ KP5j?81b23ʾ)M%"""""NrĮVjLyK^#*,F ;/۸;vxM\cWLqU_7.Xyi.NDDDDDtl&Z$_#❍N}Eۈ \IDAT[7];.XNVC˩uN1q q)2nk;)ڼ˭e1S)e!srdNuzNm 'rrS'S_QyNT^_(&Z!.c/sNc)'ESKDDDDDԝΉS5rT'2n+iT3L&㔷~e_;ϵ[SiE398sښbS/rv})DGw\&y!jlGC>7/΀U}=TLM1;NyQo4socT2'"˱*2n6:)OMz}o6'}}E"Hy"""""*D[#Vd>Rr9=7q; riBoɱ5q7q49S[*H'"""""m4z]svu2'ٜ˼y96z\T=ɍthL/Nyqq=Vu)8tf"""""Й>)'rȸ2oQc׷>K]11d\nM1W̻i3[MΊqE&8+r/Vxgw*]Nj\I 'jlU5czT\S `s@cvN ]h5>ۚbr2ޙ2{HpsԸ]urx[WV˾DDDDDD=Y,s\@0S^n=V96Wk9 4ї5@xδ>ySVguG# """"" #oOVDLULVg:9Mk=fgLpuGg}؍CDDDDDt0dZc7ubq>r,c;s%_7vS-:`)2'H4`sDDDDDDi2m3M10`dL9SL1ɾilM%r؝[ u‚iHun}$^5DDDDDDnRݙEYΩTke4ﺨ$rn,DZ0gʛbG+vq""""""J,ɷG+SLg7qӾvc'nkE%hTg`k:].D;e_"""""dD9ҾvybX`uv5zSm]mT=Ncu28hCDDDDDԛtf>>ڱb`ח"#>ڨt$㸭Sd}cBSNgɘ+vq""""""vqcS.6ȜNGm]ud9lj>ڱNjL1]GDDDDD[tv2i?SdMcE;$QInz465ю#q[ﶎq;v[h&&0ǜ$Sz2E[191I1`Ί񈈈zxOg˘jdLs,h|2pG[cEMQ")fbsN'tD9Ǎ^/)fǩ)s[GDDDDDDvbT甓L}fqDžҙ zgQWIg!"""""}݊1b?!z9^1^q/d{>DDDDDDJvW?x=^=i2S2>'""""""JI}SP=mœ盨"Q :n {wODDDDDDdD?z^CW=j'!zd^Ow=.%Z4Ǎ Das Kraft Handbuch

Einführung

Kraft is a Qt and KDE application to organize office documents like quotes and invoices in a small business. It eases the creation of documents and helps with repeating tasks.

Using Kraft, there is no need for fiddling with a text processor any more. Documents are created by a few clicks, edited, generated and archived automatically. Kraft generates high quality PDF output for printing, mailing and archiving.

Funktionen
  • Simple creation of offers, invoices and similar documents.

  • Customer management, deeply integrated with the mature KDE KAddressbook.

  • Maintenance of document relations, ie. Partial invoices vs. invoices.

  • Vorlagen für Dokument-Kopf- und Fusstexte sowie Dokumentposten.

  • Pre calculation of item prices.

  • Materialverwaltung.

  • Konfigurierbare Dokument-Erstellung im PDF Format zum Druck und Versenden per Email.

Der Quelltext zu Kraft ist open source and wird unter der Lizenz GNU General Public License veröffentlicht.

Anmerkung
Kraft is driven by community of users, coders, artists and others by voluntary work.
Also this manual needs contributions!

Learn more on how to contribute!

Erster Start und Grundkonfiguration

When Kraft is started for the first time, it automatically enters the initial setup process.

During the initial setup you are asked to select a database to use and give the name and address of your company.

You can fill in your company address (that appears on the printed documents) in two ways: in the setup procedure use the first tab Select from Addressbook for to select your on address in KAddressBook (if you have filled your own address in KaddressBook) or use the second tab Manual entry for to fill in the information of the address from your company manually. This step is necessary for the correct generation of your documents as the address is automatically used in the document generation step.

Company adress

After the initial setup, select Preferences  Settings. That allows to prepare Kraft correctly so it can be used in a proper way.

In the Preferences dialog we have the tabs:

*Dokument Voreinstellungen
*Steuern
*Dokumenttypen
*Stundensätze
*Einheiten
*die eigene Identität

Each of the tabs allows to enter useful values for the specific use case.

Dokumenttypen

Beim ersten Start finden sich folgende Dokumenttypen:

  • Auftragsbestätigung

  • Lieferschein

  • Rechnung

  • Angebot

Document type

Übersetze diese Typen in die eigene Sprache. Du kannst ebenso neue hinzufügen und Einträge entfernen, die Du nicht benutzen wirst.

Nummernkreise

Numbercycles Each document has to have an unique identifier that identifies the document. There must not be two documents in Kraft with the same identifier.

The format of the identifier is configuratable in Kraft. For that, Kraft has a concept of so called number cycles. Number cycles are used to define the form of the document number which is printed on every document.

All documents of a certain type have identifiers taken out of one number cycle. Each document type has a number cycle assigned. Different document types can use the same number cycle to generate ids from. That way, for example the document types Invoice and Final Invoice can use numbers from the same number cycle, even thought they are different document types in Kraft. Number cycles are identified by their name. User can create new number cycles and edit them clicking on the button Edit Number Cycles…​

The format of the document numbers are defined by a template that can contain normal, fixed characters and also some variables that are replaced by the respective values when the document is created.

Each identifier needs to be unique, and thus has to contain a counter. Kraft supports two types of counter: One (variable %i) is incremented globally for every new document. The other (variable %n) is reset every day and starts at 1 again on every new day. In addition to the counter, more information can be added to the template form an useful number. Examples are a constant text or parts of the date.

The default numbercycle delivered with Kraft contains the year, the month and a serialnumber. That way you can compare offers or orders from last year with this year or the month April of last year with the month April of this year and get on this way an impression from the results of your business.

Folgende Variablen stehen zur Verfügung:

%y or %yyyy

the year of the document date.

%yy

the year of the document (two digits).

%w

the week number of the document date.

%ww

the week number of the document date with leading zero.

%d

the day number of the document date.

%dd

the day number of the document date with leading zero.

%m or %M

the month number of the document date.

%MM

the month number with leading zero.

%c

the customer id from kaddressbook

%type

the localised doc type (offer, invoice etc.)

%uid

the contact id of the client.

%i .. %iiiiii

the unique counter

%n .. %nnnnnn

the unique day counter (combine with date)

A number cycle template needs to contain either %i or %n, if not, %i is appended automatically.

Both %i and %n are numeric values. They can also be padded with with leading zeros. The length is defined by the number of i’s or n’s put into the template. For example, if a daily counter with length of three and leading zeros is desired, %nnn has to be put into the template. This works up to a length of six characters.

Anmerkung
The "design" of the numbercycles and document numbers is very important. With the flexible system of templating Kraft can not prevent invalid number cycles. It is in the responsibility of the user.

PDF Template

In the entry field Template File: the user can select a custom template for this specific document type.

If the file extension of the template file is .trml, the ReportLab based document converter is used. If the file extension is .gtmpl, Kraft automatically uses the Weasyprint based converter.

Anmerkung
The ReportLab system for PDF creation is deprecated in Kraft. Please, for new templates, always use Grantlee- and Weasyprint based templates.

PDF Postprocessing

After Kraft has created the PDF document it is possible to merge the created PDF with static, customized PDFs created by the user. With that, it is easy to add a custom stationery with a logo to the resulting PDF ("Watermark").

The static PDFs should have the same page size as the generated documents. Keep in mind to use optimized images for logos etc. to not blow up the size of the result document.

PDF Postprocessing

The watermark options are:

  1. No Watermark: No watermark is created

  2. On first page: The first page of the watermark.pdf is merged with the first page of the result document

  3. Watermark on all pages: Merges the first page of the watermark PDF to all pages of the result document

  4. alternating: For this, the watermark PDF needs to have three pages. The first page is merged to the first page of the result document, the second and third page are alternated merge to subsequent pages.

  5. different first and last page: the PDF needs to have three pages. The first page is merged to the first page of the result document, the third page to the last, and the second to all page between first and last page.

If there is another static PDF document put into the entry field "Append PDF:", it is appended to the generated PDF. With that, Kraft will automatically add for example terms and conditions documents to the final document.

Steuern

Taxes In many countries there are two kinds of VAT-taxes for sold products.

Ein hoher und ein niedriger Steuersatz.

Fill here the appropriate amounts in for the high level and the low level. If the tax-level is changing, then you add here the start date with the new tax-levels.

Wages

Wages A list of wage costs is maintained in Kraft. The items are used in templates and during calculation.

All data can be edited, customized and new items can be added in the Kraft Configuration Dialog reachable through the Settings menu.

Remember that these units are later used in the documents, it is therefor important that you translate them to your own language and to fill in the correct prices.

Units of measurement

Units of measurement A list of units of measurement is maintained in Kraft. In Kraft Configuration Dialog reachable through the Settings menu can you edit and customize items already in the list, and also can you add new items to the list.

Remember that these units are later used in the documents, it is therefor important that you translate them to your own language.

Own identity

Check here if the information that you have given during the initial setup is correct for the use in the documents.

Warnung
If you made the choice to use the information from KaddressBook then is the information from a later manual entry ignored.

After we have made some corrections to the configuration, we go back to the main window.Here we see three tabs:

  • Documents

  • Timeline

  • Catalogs

Catalogs

Kraft supports so called Catalogs in which templates for document items are kept. With the catalogs creating documents can be significantly accellerated in the day to day business. When creating new documents, the items templates from the catalogs can easily selected and moved over to the document.

Since templates are organized in chapters entire documents can be prepared in different chapters to be used as template documents.

Of course the items in the documents can be edited after they got picked from a catalog.

By default Kraft comes with two different catalogs:

Material

A catalog of material that are sold, with their purchase prices, the profit and the sell-price.

and Standard Templates

A catalog of standard recipes of work like planting trees.

Both catalogs can have chapters and sub-chapters for to organize your templates. First we are going to fill in the

Material Catalog

A catalog of material that are sold, with their purchase prices, the profit and the sell-price. First we are going to add new chapters and subchapters.

New chapters

Select with the mouse the column-name material, select now in the context-menu [Add a sub chapter]

and add an extra chapter like Trees

New sub chapters

We are going to ad sub chapters in the map Trees. Select with the mouse the name of the chapter where you like to add a subchapter, select now in the context-menu [Add a sub chapter] and ad an extra subchapters like Loaf trees and needle trees. After adding the extra chapters and subchapters for dividing the material, we are going to add the material themself.

New template

Select with the mouse the name of the sub-chapter or chapter where you like to add a material. Select the sub map Loaf trees and select now in the context-menu

Add the extra materials coconut tree, apple tree and pine-apple tree.

Fill in the price that we have paid.

Fill in the profit that we want to have on the material

And fill in how much is in a packet.

Material catalog After this we add also in the map 'Wood' a item for a 'support pole' for later use with its price.

Now we are going to:

Standard Templates

This is a catalog of standard recipes of work like:

  • planting trees

  • cutting grass

  • transport costs

  • planting grass

  • sowing grass-seed

We add here the standard work of planting a tree.

Select with the mouse the name of the chapter [Work] where you like to add the new template,

select now the context-menu [New template]

and the extra templates Plant tree and cut grass.

After we made the new template, a window opens with 4 tabs:

  • Template

  • Time calculation

  • Fixkosten

  • Material

First we go to the tab:

Template

We give here the name of the new standard template like Plant tree Standard catalog

Warnung
be careful, this name is later used in the invoice

we select that this is per piece and that the margin is 8% and that the full VAT is applicable.

Time calculation

We fill here in a number of work with the time:

Tabelle 1. Spent time

Dig hole

32 min.

worker

Place tree

12 min.

worker

Fill hole

17 min.

worker

give water

5 min.

worker

The cost for worker which we have earlier filled in is now used. Time calculation

Anmerkung
in the invoice we see later only Plant tree, we will not see the parts dig hole,place tree,fill hole,give water

Now we go to the tab

Fixed costs

and fill in:

Tabelle 2. Fixed item

Transportcost

35 euro

1 pcs.

Fixed cost

After this we go to the tab:

Material

Here we select next, after which the window [Add Material to Calculation] opens for a selection of material. We navigate to the map 'wood' where we select the 'support pole'.

Tabelle 3. Used materials

1

support pole

3,5 euro

Material

We go now back to the first tab template

On the first tab [template], we can now see the overall cost per one unit

Click on [OK] for saving the result or on [cancel] for discarding the result.

We make a second template cut grass

we fill in cut grass, as unit we choose sm (square meter), on the second tab we fill in that we need 3 min per square meter.

Click on [OK] for saving the result or on [Cancel] for discarding the result.


Kraft supports text templates also for the header- and footer-text of documents. Each document type has it’s own set of text templates. To access them, open a document of a certain document type in edit mode and use the show templates to make the templates visible. In both the header- and footer-section the stored templates become visible.

Directly under the navigation pane on the right side of the window is a list of the names of the available templates. Clicking on one of the names in the list displays the text in the pane below.

Underneath there are buttons located with the following functions from left to right:

  1. Add the template to the document: This button replaces the text of the document with the selected template.

  2. Insert the template to the document: The selected template is inserted to the current place of the cursor in the document.

  3. Create a new template: Opens a dialog to enter a complete new template for the current doc type.

  4. Edit the current template: Opens the dialog to edit the currently selected template.

  5. Delete the current template: Removes the template permanently from the list of available templates.

Anmerkung
Templates with the name Standard are the default templates for the document type. They are inserted automatically if a document of this type is created.

Macros

Both the header- and footer-templates can contain so called macros which are replaced with calculated values once the document is rendered to the final output format.

The following list of macros are supported:

  • DATE_ADD_DAYS(<amount_days>): Returns the date of the of document plus the number of days specified as parameter to the macro.

  • ITEM_COUNT_WITH_TAG(<tag>): Returns the amount of items tagged with the tag.

  • NETTO_SUM_PER_TAG(<tag>): Returns the netto sum of all items that are tagged with the named tag.

  • BRUTTO_SUM_PER_TAG(<tag>): Returns the brutto sum of all items that are tagged with the named tag.

  • VAT_SUM_PER_TAG(<tag>): Returns the pure tax of all items that are tagged with the named tag.

  • IF_ANY_HAS_TAG(<tag>) and END_HAS_TAG: Includes the text between the two macros only if there is at least one item that is tagged with the tag.

As an example, this footer text template can be used to automatically generate useful texts:

IF_ANY_HAS_TAG(Material) This invoice lists material in ITEM_COUNT_WITH_TAG(Material) items. The net value is NETTO_SUM_PER_TAG(Material), plus VAT_SUM_PER_TAG(Material) = BRUTTO_SUM_PER_TAG(Material). END_HAS_TAG ```

We are now ready for the first invoice.

[[Invoice]]
== Creating Documents

=== The first Invoice

Open the tab btn:[documents]

Click on btn:[create document]

The window document [creation wizard opens].

Select in document type `invoice`.

Fill in on the whiteboard content a short text about what the invoice is, like: `cut grass and planted tree for mister Jonson`

Click on btn:[next]

Select on the new window the name and address from the client.

(if the name and address is not there, click then on btn:[new contact] or on btn:[edit contact] if you want to edit the contact)

Click on btn:[OK].

Now opens the window document [items].

this window has 2 tabs and the 3 buttons on the top:

* btn:[Add item...],
* btn:[Add discount item],
* btn:[Show templates].

In the left tab you can see all the items that we want to place on the invoice, on the right tab we see the text from the header, the total price and the footer.

If you click on the text of the header or the footer on the right side then the window changes in such a way that you can edit the header or the footer.

Adapt the header and the footer to your situation, on the footer you can place a text: `We make your garden-dream come to reality.`.

Click on the button btn:[Show templates].

The right tab changes and show now the earlier made templates, we select in the group Work, the subgroup Plant tree and click then on the button with the to the left pointing arrow on the bottom side.

A new window [Create Item from Template] opens.

Because we have planted 2 trees, we go to the field [insert] and change this to 2 pcs.

Click on btn:[OK] for saving the result or on btn:[cancel] for discarding the result.

The window close and we go back to the main window.

We click again on btn:[Show templates] and select this time `cut grass`, we click again on the button with the arrow, in the opened window we select that the grass-field was 24 square meter.

Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding the result.

We add now manually an item by clicking on the button btn:[Add item…] and the window [create new item] opens.

Because we have delivered a special tree, we fill here in the name of the special tree `liguster`, at the field insert we fill in the number of the special trees that we have delivered and the price of them.

____
WARNING: Remind that in the catalog we can add a profit on the price of the material, in the invoice and in the offer we can not add a profit on the price of the material.
____

We have now an invoice with 3 items.

Click on btn:[OK] for saving the invoice or on btn:[Cancel] for discarding the invoice.

We click on btn:[OK] and save the result.

Your first invoice is now ready for sending.

In the window documents we see our first invoice, notice that this document has a document number which we can see on the left side.

On top of the window with all the invoices we see the button [Print Document], on which we click.

From the invoice will now a PDF be made which we can print on paper or send by email to the client.

After this we are going to create a offer for some work in a garden.

[[Offer]]
=== Creating an Offer

The client has asked to plant a tree, we will offer 3 different trees which we can plant.

Beside this, we have seen that there is a lifeless three, which we will offer to remove as extra work. image:create_new_doc.png[Numbercycles,float="right"]

For the total price we do not want to show the price of the removal of the lifeless tree and we want for the total price only to show the price of one tree and not three.

Open again the tab btn:[documents].

Click on btn:[create document]

The window _Document Creation Wizard_ opens.

select in btn:[document type] > btn:[Offer].

Fill in on the whiteboard content a short text about what the offer is, like: `plant one tree and removal of lifeless tree`

Click on btn:[next]

Select on the new window the name and address from the client.

(if the name and address is not there, click then on btn:[new contact] or on btn:[edit contact] if you want to edit the contact)

Click on btn:[OK].

Now the window [edit document] opens.

This window has 2 tabs and the 3 buttons on the top:

* btn:[Add item...],
* btn:[Add discount item],
* btn:[Show templates].

Click on the button btn:[Show templates].

The right tab changes and show now the earlier made templates, we select in the group `Work`, the subgroup `Plant tree` and click then on the button with the to the left pointing arrow on the bottom side.

A new window [Create Item from Template] opens.

Because we want to plant 1 tree, we go to the field [insert] and keep this on 1 pcs.

Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding the result.

The window close and we go back to the main window.

We click on the button btn:[Show templates] and this time we select in catalog Material

The material-catalog opens, and we can select in the chapter `trees` the subchapter `loaf trees` in which we select the `apple tree` which we made earlier.

Click on we btn:[OK] for saving the result or on btn:[cancel] for discarding the result.

The window close and we go back to the main window.

We add now manually an item by clicking on the button `Add item…`.

the window [create new item] opens.

We want that the client can make a choice from an apple, a pear tree and the liguster.

Therefor we are going to add also a pear tree manually.

We click on the button btn:[Add item…] and the window [create new item] opens.

We fill here in the name of the tree `Pear tree`, at the field insert we fill in the number of the special trees that we have delivered and the price of them.

We want add this to the material catalog for future use, therefor we select also [select this item as template for future documents] and we select in [save in chapter]`trees`.

Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding the result.

We does this again but then for the liguster.

We have now 3 items with trees in the offer.

As last item we add an item with `remove tree` with 0,5 hour for 32 euro.

On the left side of an item we can see 2 buttons:

a button with a flag and a button with what looks like a page.

We select the upper button with the page after which opens a context-menu with the items:

image:context1.png[Context menu,float="right"]

 [Item kind]->[Normal]
 [Item kind]>[Alternative]
 [Item kind]>[On demand]
 [Tax]
 [Move up]
 [Move down]
 [Lock item]
 [Unlock item]
 [Delete item]

We choose here [Item kind] and change for `pear tree` from [normal] to [alternative].

We do this also for [liguster] and for [remove tree] we change this from [normal] to [on demand].

image:context2.png[Context menu,float="right"]

Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding the result.

We want to see the result and therefor we click on the button [show document].

We see now that the prize of the pear tree, the liguster and the removal of the tree is not used for the total prize. When we are happy with the result, we can click on the button btn:[close] after which we click on the button btn:[Print Document] for making a PDF what we can print out or send to the client.

After your first invoice is now your first offer now also ready for sending.

[[Acceptance_of_order]]
=== Creating an Acceptance of Order

The document type "Acceptance of Order" is sent subsequently to an offer.

image:acceptance_o_o_context.png[Numbercycles,float="right"]

When a client has made a request, we will send an offer in wich we describe which items we will deliver. Hopefully the client will give an order for the work.

It is a good practice to respond on the order with an "Acceptance of order" in which we describe all the items we will deliver. We can make the "Acceptance of order" on the same way as we made the invoice or the offer by selecting each item and correcting the number of delivery. This takes time and we can make errors by forgetting items or filling an incorrect number.

It can be done quicker by selecting the offer in the list and selecting btn:[Create Followup Document] from either the context menu or the main menu.

We have now in documenttype the choice from:

 [Acceptance of order]
 [Invoice]
 [Partial Invoice]
 [final Invoice]
 [Progress Payment Invoice]

image:followup_1.png[Folloup document,float="right"]

We select here "Acceptance of order". We have now a copy from the offer as an Acceptance of order (do not forget to adapt Alternative Delivery items and on demand items.)

image:followup_2.png[Folloup document,float="right"]

You can do this also for the creation of the invoice as a followup for Acceptance of order. Each document type has a specific list of follow up documents. It is a good practice to describe on the invoice precisely what was delivered.

[[Customization]]
== Customization

Kraft can be customized in most of the graphical user interface and in particular in the output it generates.

=== Output Document Customization

To create PDF output documents, the document data that was edited in the Kraft app is filled into a template. The template defines how the output document looks like, ie. by font settings, placing of elements and such.

The file that is assembled from data and the template is converted to PDF using a special document creation script. All that is started automatically by Kraft if a document should be printed.

Each document type in Kraft can have it's own template that is used to create a PDF. Which one can be set in the Settings dialog for document types.

==== WeasyPrint Documents

NOTE: Kraft still ships with the old ReportLab based converter, but that will be deprecated the future. The WeasyPrint based system is the future. It is a recommended to port existing templates.

With https://weasyprint.org[WeasyPrint] Kraft uses a very powerful generator that makes it very easy to create highly customized documents with great quality.

WeasyPrint converts a html file to PDF. It is integrating a cascading stylesheet (CSS) file which has a huge impact on the PDF document's look.

The html- and CSS input file for WeasyPrint is built from the Kraft template file.

To enable the use of WeasyPrint for a document type in Kraft, simply create a weasyprint compatible template file and save it with the extension *.gtmpl*. Based on the file extension Kraft automatically uses WeasyPrint and the Grantlee templating engine for rendering.

From version 0.95 on Kraft ships with an example template in the Grantlee- and WeasyPrint format. It can be found at `/usr/share/kraft/reports/invoice.gtmpl` or https://github.com/dragotin/kraft/blob/master/reports/invoice.gtmpl[online on Github]. An example CSS file `kraft.css` (https://github.com/dragotin/kraft/blob/master/reports/kraft.css[on Github]) is shipped as a good starting point for adoption.

==== Template Variables

To generate the PDF, Kraft has to transfer data from the document you have been working on to the input file that is processed to a PDF. For that, Kraft uses a text template in which Kraft replaces variables with the actual values.

For example, the tag `{{ doc.doctype }}` is replaced with the current document type during the generating process.

The syntax is based on the Django syntax for templates described in the https://docs.djangoproject.com/en/3.1/topics/templates/[the docs].

==== EPC QR Code

With Weasyprint based PDF generation Kraft supports the https://en.wikipedia.org/wiki/EPC_QR_code[EPC QR Code] which implements a European standard for payments by computer and mobile devices.

In Germany it is also known as _Giro Code_, in Belgium as _Bancontact QR_, in the Netherlands as _iDEAL QR-code_ and in Spain it is also known as _Bizum QR-code_.

In Germany it is accepted by the _Giro Code_ and in Holland it is accepted by the official https://www.ideal.nl/consumenten/ideal-app/[_iDEAL QR-code_] app.

In Belgium and Holland it is accepted by the apps of many banks, and in Austria and Finland it is accepted by the apps of all banks.

To use the EPC QR code on the invoice printout, the bank account information has to be added to own identity settings dialog in Kraft. The giro code is current only generated for documents with the document type `Rechnung`.

To include the generated EPC QR Code into the PDF document, the Weasyprint template needs to contain a snippet like this:
{%if doc.isInvoice and epcqrcode.valid %}
<p class="epcqrcode">
  <img class="epc" src="file://{{ epcqrcode.svgfilename }}" alt="EPC QR Code" />
  Dieser QR Code ermöglicht einfaches, sicheres und schnelles Begleichen dieser Rechnung via GiroPay:
  Diesen Code mit dem Smartphone scannen und Überweisung per Banking App aufgeben.
</p>
{% endif %}
[[Menu]]
== Menus and Shortcuts

=== Main Application Menu

[[File]]
==== The File Menu

 [File]>[Quit]
 [Ctrl]+[Q]
 Quits the application.

[[Document]]
==== The Document Menu

[[Show_document]]
 [Document]>[Show Document]
 [Ctrl]+[R]
 Opens a window with the selected document for showing it.
[[Edit_document]]
 [Document]>[Edit Document]
 [Ctrl+O]
 Opens a window with the selected document for editing it.
[[Open_document]]
 [Document]>[Open Archived document]
 [Ctrl]+[A]
 Opens an archived document.
[[Create_document]]
 [Document]>[Create Document]
 Opens a window with a wizard for creating a new client-document.
[[Copy_document]]
 [Document]>[Copy Document]
 Makes a copy of the selected client-document to a new client-document
 which can belong to an other client or an other documenttype.
[[Follow_document]]
 [Document]>[Follow Document]
 Opens the selected client-document for editing.
[[Print_document]]
 [Document]>[Print document]
 Makes a PDf from the selected client-document for to be mailed or
 printed.
[[Mail_document]]
 [Document]>[Mail document]
 [Ctrl]+[M]
 Mails a document.


[[settings]]
==== The Settings menu
[[edit_template]]
 [Settings]>[Edit Tag Templates]
 [Ctrl]+[E]
 Opens a window where you add, edit or translate the tags (like work,
 material, plants or discounts).
[[redo]]
 [Settings]>[Redo initial setup]
 [Ctrl+R]
 Redoes the initial setup. After this, a restart of Kraft is required.
[[toolbars]]
 [Settings]>[Showed toolbars]
 Here you can decide if the `main toolbar` and the toolbar `Document Actions`
 are shown.
[[configure]]
 [Settings]>[Configure Kraft]
 [Ctrl]+[Shft]+[,]
 Here you can configure Kraft.

=== Document Edit Window

[[context]]
==== The context Menu

 [Context]>[Item kind]
 change the status from this item between
* Normal
* Alternative
* On demand
[[Tax]]
 [Context]>[Tax]
 Seems not working.
[[Move_up]]
 [Context]>[Move up]
 Moves this item a place up in document.
[[Move_down]]
 [Context]>[Move down]
 Moves this item a place down in document.
[[Lock_item]]
 [Context]>[Lock item]
 It is not clear what is does.
[[Unlock_item]]
 [Context]>[Unlock item]
 It is not clear what is does.
[[Delete_item]]
 [Context]>[Delete item]
 Removes this item from document.


[[AdvancedTopics]]
== Fortgeschrittene Themen

Dieses Kapitel beschreibt fortgeschrittene Themen um Kraft. Dabei wird etwas Linux-Kenntnis vorausgesetzt, und das Aufsetzen sollte von erfahreneren Linux Administratoren durchgeführt und gut testet werden.

=== Using Kraft Collaboratively

Kraft kann kollaborativ in einer verteilten Umgebung verwendet werden. Das heisst, dass mehrere Benutzer an ihren jeweiligen Arbeitsplatzrechnern mit ihrer eigenen Kraft Instanz arbeiten können und dabei die selben Daten verwenden.

Das ganze Thema ist Veränderung unterworfen, da Kraft in naher Zukunft ownCloud als private Cloud Lösung zur Datenspeicherung verwenden wird.

==== Datenbank und Dokumentpool teilen

Der einfachste Fall ist das zwei oder wenige mehr Kraft Instanzen die Datenbank gemeinsam benutzen und den Pool von PDF Dokumenten gemeinsam verwenden. Um es einfach zu halten werden hier zwei Instanzen beschrieben.

Ein typischer Anwendungsfall könnte sein: Zwei verschiedene Linux user möchten Kraft verwenden. Sie haben beide ihren eigenen Computer und arbeiten im selben Netzwerk. Dieses Beispiel beschreibt eine Situation mit einem Hauptbüro das Kraft im normalen Modus betreibt, und einem Notebook mit Kraft, das im NurLesen Modus um Dokumente anzusehen, Kataloge zu überprüfen und ähnliches.

Dafür müssen die folgenden Voraussetzungen erfüllt sein:

1. Als Datenbank-Backend wird MySQL oder MariaDB verwendet. Sqlite wird nicht unterstützt.
2. Die Datenbank ist mit dem MySQL Benutzer von beiden Rechnern aus erreichbar.
3. Das Dokument-Speicher-Verzeichnis muss geteilt werden.

____
Achtung: Es gibt keinen Schutz dagegen, dass beide Benutzer das gleiche Dokument zur gleichen Zeit bearbeiten. Weil das gefährlich ist und zu unvorhersehbaren Resultaten führen kann, ist es empfohlen, Kraft in allen ausser der Haupt-Instanz im Nur-Lese Modus zu betreiben. Der Nur-Lese Modus wird mit Krafts Kommandozeilenschalter -r eingeschaltet.
____

**Die Datenbank teilen**

Der Datenbankserver sollte auf der Haupt-Maschine installiert sein, oder es sollte ein spezialisiertes Gerät wie ein NAS verwendet werden. Die Netzwerk Geschwindigkeit beeinflusst die Benutzbarkeit natürlich erheblich.

Howtos um MySQL aufzusetzen sind im Internet zu finden.

**Den Dokument Pool teilen**

Kraft schreibt generierte PDFs in ein lokales Verzeichnis. Welches Verzeichnis das ist kann im Kraft Konfigfile eingerichtet werden. Das Konfigfile muss auf allen Instanzen angepasst werden.

Es ist in jedem Benutzer Homeverzeichnis unter dem releativen Pfad `.config/kraftrc`. Es muss den folgenden Konfigurations-Wert enthalten:

PdfOutputDir=/data/space/kraftdoc/pdf

Es gibt verschiedene Wege wie das Verzeichnis geteilt werden kann, zum Beispiel NFS und SMB Server. Es ist entscheidend, dass beide Benutzer von beiden Maschinen die Dateien auflisten und zugreifen können. Der Hauptbenutzer braucht Schreib- und Leserecht., Nur-Lese Bentuzer brauchen nur Lesezugriff auf die Dateien.

Ein empfohlenes Setup benutzt ein NFS Share über autofs, das auf der Hauptmaschine aufgesetzt werden muss. Um Dateizugriff zu verwalten, sollte eine Gruppe aufgesetzt werden.

**Kraft im Nur-Lesen Modus**

Um Kraft im Nur-Lese Modus zu starten, muss das Programm mit dem Kommandozeilenschalter `-r` gestartet werden.

=== XRechnung Support

Kraft supports the XRechnung standard. That is a digital format for electronic invoicing, and it passed as law in Germany and follows a EU directive. The XRechnung is a XML file format designed for that purpose.

To use the XRechnung Export productivly, a little manual work is still needed in Kraft. Kraft creates the XML file based on a template, very similar to the normal PDF documents. That means that it loads a template that contains static elements (ie. the company address) that do not change between different invoices. The dynamic elements (customer data, items etc.) are filled into the template during the generation step.

In order to generate correct XRechnung files for the specific company, the user has to adopt the template file manually to the companies needs. Note that this has only to be done once and should be easy for a person with a bit computer experience (Basic knowledge about XML appreciated!).

To adapt the file to the needs of the company, it is best to start with the https://raw.githubusercontent.com/dragotin/kraft/master/reports/xrechnung.xrtmpl[example XRechnung file]. It has to be downloaded and saved into a location that the user can edit. Open it in a normal text editor, such as https://kate-editor.org/[Kate].

Read carefully through the file without being scared off by the XML format. All user strings (ie. company name, address and such) are user specific and should be replaced accordingly. Find https://www.xoev.de/xrechnung-16828[details about the format] here to better understand the meaning of the fields.

Make sure to not disturb the proper XML format and do not change places where the template format `{{ template_name }}` is used.

Once the file is adopted to the needs, open the Settings dialog of Kraft and insert the filename into the entry field for the XRechnung Template File on the Document Defaults page.

After that step, the btn:[Export XRechung] menu item will open a dialog to pick a filename where to save the XRechnung invoice to.

This file can now be transfered to the receiver of the invoice.

NOTE: There are validators for invoices in XRechnung format out there in the internet. It is useful to verify the format of the Kraft exported XRechnung.

=== Changing the Locale

If it is needed that Kraft runs under a different locale than the actual desktop environment, this can be achieved by setting the desired locale in the start file of Kraft.

On the linux desktop, apps are usually started through a so called https://specifications.freedesktop.org/desktop-entry-spec/latest/[desktop file]. It contains the information how the Kraft binary is started if user clicks on the icon on the desktop or in the start menu.

The desktop file can usually be found in `/usr/share/applications/de.volle-kraft-voraus.kraft.desktop`.

It contains the line ``` Exec=kraft %u ``` which starts the application with the default locale.

Changing it to ``` Exec=env LANG=de_DE.UTF-8 kraft %u ``` would change that to run in the German locale for example, independent from the desktop environment location.


[[Credits]]
== Credits und Lizenz

Program and documentation copyright 2004–2023 Klaas Freitag

Documentation copyright 2020-2023 Ronald Stroethoff
kraft-1.1/manual/kraft-en.html000066400000000000000000002773151450127457600163660ustar00rootroot00000000000000 The Kraft Handbook

Introduction

Kraft is a Qt and KDE application to organize office documents like quotes and invoices in a small business. It eases the creation of documents and helps with repeating tasks.

Using Kraft, there is no need for fiddling with a text processor any more. Documents are created by a few clicks, edited, generated and archived automatically. Kraft generates high quality PDF output for printing, mailing and archiving.

Feature Overview
  • Simple creation of offers, invoices and similar documents.

  • Customer management, deeply integrated with the mature KDE KAddressbook.

  • Maintenance of document relations, ie. Partial invoices vs. invoices.

  • Templates for document header- and footertexts and for document items.

  • Pre calculation of item prices.

  • Material management.

  • Configurable document creation in PDF format for print and email.

The code of Kraft is open source and is released under the GNU General Public License.

Note
Kraft is driven by community of users, coders, artists and others by voluntary work.
Also this manual needs contributions!

Learn more on how to contribute!

First Use and Basic Configuration

When Kraft is started for the first time, it automatically enters the initial setup process.

During the initial setup you are asked to select a database to use and give the name and address of your company.

You can fill in your company address (that appears on the printed documents) in two ways: in the setup procedure use the first tab Select from Addressbook for to select your on address in KAddressBook (if you have filled your own address in KaddressBook) or use the second tab Manual entry for to fill in the information of the address from your company manually. This step is necessary for the correct generation of your documents as the address is automatically used in the document generation step.

Company adress

After the initial setup, select Preferences  Settings. That allows to prepare Kraft correctly so it can be used in a proper way.

In the Preferences dialog we have the tabs:

*Document Defaults
*Taxes
*Documunt Types
*Wages
*Units
*Own identity

Each of the tabs allows to enter useful values for the specific use case.

Document Types

At the first use you find a list of different document types, such as:

  • Acceptance of order

  • Delivery receipt

  • Invoice

  • Offer

Document type

Translate this types to your own language. You can also add new ones and remove document types you wont use.

Numbercycles

Numbercycles Each document has to have an unique identifier that identifies the document. There must not be two documents in Kraft with the same identifier.

The format of the identifier is configuratable in Kraft. For that, Kraft has a concept of so called number cycles. Number cycles are used to define the form of the document number which is printed on every document.

All documents of a certain type have identifiers taken out of one number cycle. Each document type has a number cycle assigned. Different document types can use the same number cycle to generate ids from. That way, for example the document types Invoice and Final Invoice can use numbers from the same number cycle, even thought they are different document types in Kraft. Number cycles are identified by their name. User can create new number cycles and edit them clicking on the button Edit Number Cycles…​

The format of the document numbers are defined by a template that can contain normal, fixed characters and also some variables that are replaced by the respective values when the document is created.

Each identifier needs to be unique, and thus has to contain a counter. Kraft supports two types of counter: One (variable %i) is incremented globally for every new document. The other (variable %n) is reset every day and starts at 1 again on every new day. In addition to the counter, more information can be added to the template form an useful number. Examples are a constant text or parts of the date.

The default numbercycle delivered with Kraft contains the year, the month and a serialnumber. That way you can compare offers or orders from last year with this year or the month April of last year with the month April of this year and get on this way an impression from the results of your business.

See the following table for available variables which can be used:

%y or %yyyy

the year of the document date.

%yy

the year of the document (two digits).

%w

the week number of the document date.

%ww

the week number of the document date with leading zero.

%d

the day number of the document date.

%dd

the day number of the document date with leading zero.

%m or %M

the month number of the document date.

%MM

the month number with leading zero.

%c

the customer id from kaddressbook

%type

the localised doc type (offer, invoice etc.)

%uid

the contact id of the client.

%i .. %iiiiii

the unique counter

%n .. %nnnnnn

the unique day counter (combine with date)

A number cycle template needs to contain either %i or %n, if not, %i is appended automatically.

Both %i and %n are numeric values. They can also be padded with with leading zeros. The length is defined by the number of i’s or n’s put into the template. For example, if a daily counter with length of three and leading zeros is desired, %nnn has to be put into the template. This works up to a length of six characters.

NOTE: The "design" of the numbercycles and document numbers is very important. With the flexible system of templating Kraft can not prevent invalid number cycles. It is in the responsibility of the user.

PDF Template

In the entry field Template File: the user can select a custom template for this specific document type.

If the file extension of the template file is .trml, the ReportLab based document converter is used. If the file extension is .gtmpl, Kraft automatically uses the Weasyprint based converter.

NOTE: The ReportLab system for PDF creation is deprecated in Kraft. Please, for new templates, always use Grantlee- and Weasyprint based templates.

PDF Postprocessing

After Kraft has created the PDF document it is possible to merge the created PDF with static, customized PDFs created by the user. With that, it is easy to add a custom stationery with a logo to the resulting PDF ("Watermark").

The static PDFs should have the same page size as the generated documents. Keep in mind to use optimized images for logos etc. to not blow up the size of the result document.

PDF Postprocessing

The watermark options are:

  1. No Watermark: No watermark is created

  2. On first page: The first page of the watermark.pdf is merged with the first page of the result document

  3. Watermark on all pages: Merges the first page of the watermark PDF to all pages of the result document

  4. alternating: For this, the watermark PDF needs to have three pages. The first page is merged to the first page of the result document, the second and third page are alternated merge to subsequent pages.

  5. different first and last page: the PDF needs to have three pages. The first page is merged to the first page of the result document, the third page to the last, and the second to all page between first and last page.

If there is another static PDF document put into the entry field "Append PDF:", it is appended to the generated PDF. With that, Kraft will automatically add for example terms and conditions documents to the final document.

Taxes

Taxes In many countries there are two kinds of VAT-taxes for sold products.

A high level and a low level.

Fill here the appropriate amounts in for the high level and the low level. If the tax-level is changing, then you add here the start date with the new tax-levels.

Wages

Wages A list of wage costs is maintained in Kraft. The items are used in templates and during calculation.

All data can be edited, customized and new items can be added in the Kraft Configuration Dialog reachable through the Settings menu.

Remember that these units are later used in the documents, it is therefor important that you translate them to your own language and to fill in the correct prices.

Units of measurement

Units of measurement A list of units of measurement is maintained in Kraft. In Kraft Configuration Dialog reachable through the Settings menu can you edit and customize items already in the list, and also can you add new items to the list.

Remember that these units are later used in the documents, it is therefor important that you translate them to your own language.

Own identity

Check here if the information that you have given during the initial setup is correct for the use in the documents.

WARNING: If you made the choice to use the information from KaddressBook then is the information from a later manual entry ignored.

After we have made some corrections to the configuration, we go back to the main window.Here we see three tabs:

  • Documents

  • Timeline

  • Catalogs

Catalogs

Kraft supports so called Catalogs in which templates for document items are kept. With the catalogs creating documents can be significantly accellerated in the day to day business. When creating new documents, the items templates from the catalogs can easily selected and moved over to the document.

Since templates are organized in chapters entire documents can be prepared in different chapters to be used as template documents.

Of course the items in the documents can be edited after they got picked from a catalog.

By default Kraft comes with two different catalogs:

Material

A catalog of material that are sold, with their purchase prices, the profit and the sell-price.

and Standard Templates

A catalog of standard recipes of work like planting trees.

Both catalogs can have chapters and sub-chapters for to organize your templates. First we are going to fill in the

Material Catalog

A catalog of material that are sold, with their purchase prices, the profit and the sell-price. First we are going to add new chapters and subchapters.

New chapters

Select with the mouse the column-name material, select now in the context-menu [Add a sub chapter]

and add an extra chapter like Trees

New sub chapters

We are going to ad sub chapters in the map Trees. Select with the mouse the name of the chapter where you like to add a subchapter, select now in the context-menu [Add a sub chapter] and ad an extra subchapters like Loaf trees and needle trees. After adding the extra chapters and subchapters for dividing the material, we are going to add the material themself.

New template

Select with the mouse the name of the sub-chapter or chapter where you like to add a material. Select the sub map Loaf trees and select now in the context-menu

Add the extra materials coconut tree, apple tree and pine-apple tree.

Fill in the price that we have paid.

Fill in the profit that we want to have on the material

And fill in how much is in a packet.

Material catalog After this we add also in the map 'Wood' a item for a 'support pole' for later use with its price.

Now we are going to:

Standard Templates

This is a catalog of standard recipes of work like:

  • planting trees

  • cutting grass

  • transport costs

  • planting grass

  • sowing grass-seed

We add here the standard work of planting a tree.

Select with the mouse the name of the chapter [Work] where you like to add the new template,

select now the context-menu [New template]

and the extra templates Plant tree and cut grass.

After we made the new template, a window opens with 4 tabs:

  • Template

  • Time calculation

  • Fix costs

  • Material

First we go to the tab:

Template

We give here the name of the new standard template like Plant tree Standard catalog

WARNING: be careful, this name is later used in the invoice

we select that this is per piece and that the margin is 8% and that the full VAT is applicable.

Time calculation

We fill here in a number of work with the time:

Table 1. Spent time

Dig hole

32 min.

worker

Place tree

12 min.

worker

Fill hole

17 min.

worker

give water

5 min.

worker

The cost for worker which we have earlier filled in is now used. Time calculation

NOTE: in the invoice we see later only Plant tree, we will not see the parts dig hole,place tree,fill hole,give water

Now we go to the tab

Fixed costs

and fill in:

Table 2. Fixed item

Transportcost

35 euro

1 pcs.

Fixed cost

After this we go to the tab:

Material

Here we select next, after which the window [Add Material to Calculation] opens for a selection of material. We navigate to the map 'wood' where we select the 'support pole'.

Table 3. Used materials

1

support pole

3,5 euro

Material

We go now back to the first tab template

On the first tab [template], we can now see the overall cost per one unit

Click on [OK] for saving the result or on [cancel] for discarding the result.

We make a second template cut grass

we fill in cut grass, as unit we choose sm (square meter), on the second tab we fill in that we need 3 min per square meter.

Click on [OK] for saving the result or on [Cancel] for discarding the result.


Kraft supports text templates also for the header- and footer-text of documents. Each document type has it’s own set of text templates. To access them, open a document of a certain document type in edit mode and use the show templates to make the templates visible. In both the header- and footer-section the stored templates become visible.

Directly under the navigation pane on the right side of the window is a list of the names of the available templates. Clicking on one of the names in the list displays the text in the pane below.

Underneath there are buttons located with the following functions from left to right:

  1. Add the template to the document: This button replaces the text of the document with the selected template.

  2. Insert the template to the document: The selected template is inserted to the current place of the cursor in the document.

  3. Create a new template: Opens a dialog to enter a complete new template for the current doc type.

  4. Edit the current template: Opens the dialog to edit the currently selected template.

  5. Delete the current template: Removes the template permanently from the list of available templates.

Note
Templates with the name Standard are the default templates for the document type. They are inserted automatically if a document of this type is created.

Macros

Both the header- and footer-templates can contain so called macros which are replaced with calculated values once the document is rendered to the final output format.

The following list of macros are supported:

  • DATE_ADD_DAYS(<amount_days>): Returns the date of the of document plus the number of days specified as parameter to the macro.

  • ITEM_COUNT_WITH_TAG(<tag>): Returns the amount of items tagged with the tag.

  • NETTO_SUM_PER_TAG(<tag>): Returns the netto sum of all items that are tagged with the named tag.

  • BRUTTO_SUM_PER_TAG(<tag>): Returns the brutto sum of all items that are tagged with the named tag.

  • VAT_SUM_PER_TAG(<tag>): Returns the pure tax of all items that are tagged with the named tag.

  • IF_ANY_HAS_TAG(<tag>) and END_HAS_TAG: Includes the text between the two macros only if there is at least one item that is tagged with the tag.

As an example, this footer text template can be used to automatically generate useful texts:

Please pay this invoice until three weeks after the date of the document, which is the DATE_ADD_DAYS(21).

IF_ANY_HAS_TAG(Material)
This invoice lists material in ITEM_COUNT_WITH_TAG(Material) items. The net value is NETTO_SUM_PER_TAG(Material),
plus VAT_SUM_PER_TAG(Material) = BRUTTO_SUM_PER_TAG(Material).
END_HAS_TAG

We are now ready for the first invoice.

Creating Documents

The first Invoice

Open the tab documents

Click on create document

The window document [creation wizard opens].

Select in document type invoice.

Fill in on the whiteboard content a short text about what the invoice is, like: cut grass and planted tree for mister Jonson

Click on next

Select on the new window the name and address from the client.

(if the name and address is not there, click then on new contact or on edit contact if you want to edit the contact)

Click on OK.

Now opens the window document [items].

this window has 2 tabs and the 3 buttons on the top:

  • Add item…​,

  • Add discount item,

  • Show templates.

In the left tab you can see all the items that we want to place on the invoice, on the right tab we see the text from the header, the total price and the footer.

If you click on the text of the header or the footer on the right side then the window changes in such a way that you can edit the header or the footer.

Adapt the header and the footer to your situation, on the footer you can place a text: We make your garden-dream come to reality..

Click on the button Show templates.

The right tab changes and show now the earlier made templates, we select in the group Work, the subgroup Plant tree and click then on the button with the to the left pointing arrow on the bottom side.

A new window [Create Item from Template] opens.

Because we have planted 2 trees, we go to the field [insert] and change this to 2 pcs.

Click on OK for saving the result or on cancel for discarding the result.

The window close and we go back to the main window.

We click again on Show templates and select this time cut grass, we click again on the button with the arrow, in the opened window we select that the grass-field was 24 square meter.

Click on OK for saving the result or on Cancel for discarding the result.

We add now manually an item by clicking on the button Add item… and the window [create new item] opens.

Because we have delivered a special tree, we fill here in the name of the special tree liguster, at the field insert we fill in the number of the special trees that we have delivered and the price of them.

WARNING: Remind that in the catalog we can add a profit on the price of the material, in the invoice and in the offer we can not add a profit on the price of the material.

We have now an invoice with 3 items.

Click on OK for saving the invoice or on Cancel for discarding the invoice.

We click on OK and save the result.

Your first invoice is now ready for sending.

In the window documents we see our first invoice, notice that this document has a document number which we can see on the left side.

On top of the window with all the invoices we see the button [Print Document], on which we click.

From the invoice will now a PDF be made which we can print on paper or send by email to the client.

After this we are going to create a offer for some work in a garden.

Creating an Offer

The client has asked to plant a tree, we will offer 3 different trees which we can plant.

Beside this, we have seen that there is a lifeless three, which we will offer to remove as extra work. Numbercycles

For the total price we do not want to show the price of the removal of the lifeless tree and we want for the total price only to show the price of one tree and not three.

Open again the tab documents.

Click on create document

The window Document Creation Wizard opens.

select in document type > Offer.

Fill in on the whiteboard content a short text about what the offer is, like: plant one tree and removal of lifeless tree

Click on next

Select on the new window the name and address from the client.

(if the name and address is not there, click then on new contact or on edit contact if you want to edit the contact)

Click on OK.

Now the window [edit document] opens.

This window has 2 tabs and the 3 buttons on the top:

  • Add item…​,

  • Add discount item,

  • Show templates.

Click on the button Show templates.

The right tab changes and show now the earlier made templates, we select in the group Work, the subgroup Plant tree and click then on the button with the to the left pointing arrow on the bottom side.

A new window [Create Item from Template] opens.

Because we want to plant 1 tree, we go to the field [insert] and keep this on 1 pcs.

Click on OK for saving the result or on Cancel for discarding the result.

The window close and we go back to the main window.

We click on the button Show templates and this time we select in catalog Material

The material-catalog opens, and we can select in the chapter trees the subchapter loaf trees in which we select the apple tree which we made earlier.

Click on we OK for saving the result or on cancel for discarding the result.

The window close and we go back to the main window.

We add now manually an item by clicking on the button Add item….

the window [create new item] opens.

We want that the client can make a choice from an apple, a pear tree and the liguster.

Therefor we are going to add also a pear tree manually.

We click on the button Add item… and the window [create new item] opens.

We fill here in the name of the tree Pear tree, at the field insert we fill in the number of the special trees that we have delivered and the price of them.

We want add this to the material catalog for future use, therefor we select also [select this item as template for future documents] and we select in trees.

Click on OK for saving the result or on Cancel for discarding the result.

We does this again but then for the liguster.

We have now 3 items with trees in the offer.

As last item we add an item with remove tree with 0,5 hour for 32 euro.

On the left side of an item we can see 2 buttons:

a button with a flag and a button with what looks like a page.

We select the upper button with the page after which opens a context-menu with the items:

Context menu

[Item kind]->[Normal]
[Item kind]>[Alternative]
[Item kind]>[On demand]
[Tax]
[Move up]
[Move down]
[Lock item]
[Unlock item]
[Delete item]

We choose here [Item kind] and change for pear tree from [normal] to [alternative].

We do this also for [liguster] and for [remove tree] we change this from [normal] to [on demand].

Context menu

Click on OK for saving the result or on Cancel for discarding the result.

We want to see the result and therefor we click on the button [show document].

We see now that the prize of the pear tree, the liguster and the removal of the tree is not used for the total prize. When we are happy with the result, we can click on the button close after which we click on the button Print Document for making a PDF what we can print out or send to the client.

After your first invoice is now your first offer now also ready for sending.

Creating an Acceptance of Order

The document type "Acceptance of Order" is sent subsequently to an offer.

Numbercycles

When a client has made a request, we will send an offer in wich we describe which items we will deliver. Hopefully the client will give an order for the work.

It is a good practice to respond on the order with an "Acceptance of order" in which we describe all the items we will deliver. We can make the "Acceptance of order" on the same way as we made the invoice or the offer by selecting each item and correcting the number of delivery. This takes time and we can make errors by forgetting items or filling an incorrect number.

It can be done quicker by selecting the offer in the list and selecting Create Followup Document from either the context menu or the main menu.

We have now in documenttype the choice from:

[Acceptance of order]
[Invoice]
[Partial Invoice]
[final Invoice]
[Progress Payment Invoice]

Folloup document

We select here "Acceptance of order". We have now a copy from the offer as an Acceptance of order (do not forget to adapt Alternative Delivery items and on demand items.)

Folloup document

You can do this also for the creation of the invoice as a followup for Acceptance of order. Each document type has a specific list of follow up documents. It is a good practice to describe on the invoice precisely what was delivered.

Customization

Kraft can be customized in most of the graphical user interface and in particular in the output it generates.

Output Document Customization

To create PDF output documents, the document data that was edited in the Kraft app is filled into a template. The template defines how the output document looks like, ie. by font settings, placing of elements and such.

The file that is assembled from data and the template is converted to PDF using a special document creation script. All that is started automatically by Kraft if a document should be printed.

Each document type in Kraft can have it’s own template that is used to create a PDF. Which one can be set in the Settings dialog for document types.

WeasyPrint Documents

Note
Kraft still ships with the old ReportLab based converter, but that will be deprecated the future. The WeasyPrint based system is the future. It is a recommended to port existing templates.

With WeasyPrint Kraft uses a very powerful generator that makes it very easy to create highly customized documents with great quality.

WeasyPrint converts a html file to PDF. It is integrating a cascading stylesheet (CSS) file which has a huge impact on the PDF document’s look.

The html- and CSS input file for WeasyPrint is built from the Kraft template file.

To enable the use of WeasyPrint for a document type in Kraft, simply create a weasyprint compatible template file and save it with the extension .gtmpl. Based on the file extension Kraft automatically uses WeasyPrint and the Grantlee templating engine for rendering.

From version 0.95 on Kraft ships with an example template in the Grantlee- and WeasyPrint format. It can be found at /usr/share/kraft/reports/invoice.gtmpl or online on Github. An example CSS file kraft.css (on Github) is shipped as a good starting point for adoption.

Template Variables

To generate the PDF, Kraft has to transfer data from the document you have been working on to the input file that is processed to a PDF. For that, Kraft uses a text template in which Kraft replaces variables with the actual values.

For example, the tag {{ doc.doctype }} is replaced with the current document type during the generating process.

The syntax is based on the Django syntax for templates described in the the docs.

EPC QR Code

With Weasyprint based PDF generation Kraft supports the EPC QR Code which implements a European standard for payments by computer and mobile devices.

In Germany it is also known as Giro Code, in Belgium as Bancontact QR, in the Netherlands as iDEAL QR-code and in Spain it is also known as Bizum QR-code.

In Germany it is accepted by the Giro Code and in Holland it is accepted by the official iDEAL QR-code app.

In Belgium and Holland it is accepted by the apps of many banks, and in Austria and Finland it is accepted by the apps of all banks.

To use the EPC QR code on the invoice printout, the bank account information has to be added to own identity settings dialog in Kraft. The giro code is current only generated for documents with the document type Rechnung.

To include the generated EPC QR Code into the PDF document, the Weasyprint template needs to contain a snippet like this:

    {%if doc.isInvoice and epcqrcode.valid %}
    <p class="epcqrcode">
      <img class="epc" src="file://{{ epcqrcode.svgfilename }}" alt="EPC QR Code" />
      Dieser QR Code ermöglicht einfaches, sicheres und schnelles Begleichen dieser Rechnung via GiroPay:
      Diesen Code mit dem Smartphone scannen und Überweisung per Banking App aufgeben.
    </p>
    {% endif %}

Main Application Menu

The File Menu

[File]>[Quit]
[Ctrl]+[Q]
Quits the application.

The Document Menu

[Document]>[Show Document]
[Ctrl]+[R]
Opens a window with the selected document for showing it.
[Document]>[Edit Document]
[Ctrl+O]
Opens a window with the selected document for editing it.
[Document]>[Open Archived document]
[Ctrl]+[A]
Opens an archived document.
[Document]>[Create Document]
Opens a window with a wizard for creating a new client-document.
[Document]>[Copy Document]
Makes a copy of the selected client-document to a new client-document
which can belong to an other client or an other documenttype.
[Document]>[Follow Document]
Opens the selected client-document for editing.
[Document]>[Mail document]
[Ctrl]+[M]
Mails a document.

The Settings menu

[Settings]>[Edit Tag Templates]
[Ctrl]+[E]
Opens a window where you add, edit or translate the tags (like work,
material, plants or discounts).
[Settings]>[Redo initial setup]
[Ctrl+R]
Redoes the initial setup. After this, a restart of Kraft is required.
[Settings]>[Showed toolbars]
Here you can decide if the `main toolbar` and the toolbar `Document Actions`
are shown.
[Settings]>[Configure Kraft]
[Ctrl]+[Shft]+[,]
Here you can configure Kraft.

Document Edit Window

The context Menu

 [Context]>[Item kind]
 change the status from this item between
* Normal
* Alternative
* On demand
[Context]>[Tax]
Seems not working.
[Context]>[Move up]
Moves this item a place up in document.
[Context]>[Move down]
Moves this item a place down in document.
[Context]>[Lock item]
It is not clear what is does.
[Context]>[Unlock item]
It is not clear what is does.
[Context]>[Delete item]
Removes this item from document.

Advanced Topics

This chapter describes advanced topics around Kraft. Some Linux knowledge is required, and setups should be done by experienced Linux administrators and should be tested carefully.

Using Kraft Collaboratively

Kraft can be used collaborative in a distributed environment. That means that multiple users work on their desktops with their own Kraft instance on the same data.

This whole topic is a subject to change, as Kraft will evolve to use ownCloud as a private cloud solution to store the data.

Sharing Database and Document Pool

The simplest case is that two or more Kraft instances use a database together and access the same pool of PDF documents on the harddisk. For simplicity this describes only two Kraft instances.

A typical use case would be: Two different Linux users want to use Kraft. They both have their own computer but only work in the same network. For example this would describe a situation with one main office machine that runs Kraft in normal mode, plus a notebook with Kraft in read only mode to view documents, check catalogs and such.

For that, the following prerequisites have to be met:

  1. MySQL or MariaDB is used as database backend. Sqlite is not supported.

  2. The database is accessible with a mysql user and from each machine for both users.

  3. The document store directory has to be shared.

WARNING: There is no protection against having both users editing the same document. Because that is dangerous and can lead to unpredictable results, it is recommended to run all instances of Kraft except the main one in read only mode. This is done by starting Kraft with the -r command line switch.

Sharing the Database

The database server should be installed on the main machine or a dedicated device like a NAS. Networking speed influences the comfort to use obviously.

Find howtos on the internet how to setup MySQL accordingly.

Sharing the Document Pool Directory

Kraft writes generated PDF documents into a local directory. Where that is can be configured in the Kraft Config file. The config file has to be adopted on all instances.

That is located in each users home directory, in the path .config/kraftrc. It has to contain the following config value:

[reporting]
PdfOutputDir=/data/space/kraftdoc/pdf

There are different ways how share that directory, ie. NFS or SMB storages. It is important that both users from both machines can list and access the files. The main user needs read and write access, read only users only need read access to the files.

A recommended setup is a NFS share with autofs which is set up on the main machine. To manage file access a certain group should be set up on the machines with which access can be managed.

Starting Kraft in read-only mode

To start Kraft in read-only mode, start the binary with the -r command line switch.

XRechnung Support

Kraft supports the XRechnung standard. That is a digital format for electronic invoicing, and it passed as law in Germany and follows a EU directive. The XRechnung is a XML file format designed for that purpose.

To use the XRechnung Export productivly, a little manual work is still needed in Kraft. Kraft creates the XML file based on a template, very similar to the normal PDF documents. That means that it loads a template that contains static elements (ie. the company address) that do not change between different invoices. The dynamic elements (customer data, items etc.) are filled into the template during the generation step.

In order to generate correct XRechnung files for the specific company, the user has to adopt the template file manually to the companies needs. Note that this has only to be done once and should be easy for a person with a bit computer experience (Basic knowledge about XML appreciated!).

To adapt the file to the needs of the company, it is best to start with the example XRechnung file. It has to be downloaded and saved into a location that the user can edit. Open it in a normal text editor, such as Kate.

Read carefully through the file without being scared off by the XML format. All user strings (ie. company name, address and such) are user specific and should be replaced accordingly. Find details about the format here to better understand the meaning of the fields.

Make sure to not disturb the proper XML format and do not change places where the template format {{ template_name }} is used.

Once the file is adopted to the needs, open the Settings dialog of Kraft and insert the filename into the entry field for the XRechnung Template File on the Document Defaults page.

After that step, the Export XRechung menu item will open a dialog to pick a filename where to save the XRechnung invoice to.

This file can now be transfered to the receiver of the invoice.

Note
There are validators for invoices in XRechnung format out there in the internet. It is useful to verify the format of the Kraft exported XRechnung.

Changing the Locale

If it is needed that Kraft runs under a different locale than the actual desktop environment, this can be achieved by setting the desired locale in the start file of Kraft.

On the linux desktop, apps are usually started through a so called desktop file. It contains the information how the Kraft binary is started if user clicks on the icon on the desktop or in the start menu.

The desktop file can usually be found in /usr/share/applications/de.volle-kraft-voraus.kraft.desktop.

It contains the line

Exec=kraft %u

which starts the application with the default locale.

Changing it to

Exec=env LANG=de_DE.UTF-8 kraft %u

would change that to run in the German locale for example, independent from the desktop environment location.

Credits and License

Program and documentation copyright 2004–2023 Klaas Freitag

Documentation copyright 2020-2023 Ronald Stroethoff

kraft-1.1/manual/kraft-nl.html000066400000000000000000002614421450127457600163670ustar00rootroot00000000000000 Het handboek van Kraft

Inleiding

Kraft is een Qt- en KDE-Programma voor het organiseren van kantoor documenten zoals offertes en rekeningen in een klein bedrijf. Het vergemakkelijkt de creatie van documenten en helpt bij vaak voorkomende taken.

Met gebruik van Kraft is geen tekstverwerker meer nodig. Rekeningen en offertes stelt u met slechts een paar muisklikken samen en worden automatisch gearchiveerd. Kraft genereert kwalitatief goede PDF-documenten geschikt om uit te printen, voor email en voor archivering.

Overzicht van de mogelijkheden
  • De eenvoudige creatie van offertes, rekeningen en vergelijkbare documenten.

  • Beheer van klanten, door het gebruik van KAddressbook in de KDE-infrastructuur geïntegreerd.

  • Beheer van relaties tussen documenten, bv. Partial invoices (Gedeeltelijke factuur) ten opzichte van invoices (rekening).

  • Sjablonen voor kop- en voetteksten maar ook voor document-items.

  • De voorcalculatie van prijzen.

  • Materiaalgebruik

  • Instelbare aanmaak van documenten in PDF Formaat voor uitprinten en verzenden per Email.

De broncode van Kraft is open source en wordt onder de licentie GNU General Public License vrij gegeven.

Noot
Kraft wordt door een gemeenschap van gebruikers, programmeurs artiesten en anderen vrijwilligers gedragen.
Ook dit gebruikershandboek heeft uw hulp nodig om verbeterd te worden.

Lees hier hierover hoe u kan bijdragen

Eerste gebruik en basisconfiguratie

Als Kraft voor de eerste keer wordt opgestart, dan komt het automatisch in een initiële proces voor het maken van instellingen terecht.

Tijdens de basisconfiguratie wordt u gevraagd om een database-type te selecteren en wordt naar de naam en adres van uw firma gevraagd.

Het adres van uw eigen bedrijf, die automatisch op het uitgeprinte document verschijnt, kan op twee manieren opgegeven worden: Bij het eerste gebruik: gebruik in de basisconfiguratie de eerste tab 'Uit adresboek' om in KAdressbook uw eigen adres te selecteren (als u in KAdressbook uw eigen adres heeft ingevuld) of u gebruikt de tweede tab 'Handmatige adres' om handmatig de informatie van uw bedrijf in te vullen. Deze stap is noodzakelijk voor de correcte aanmaak van uw documenten, omdat het automatisch wordt gebruikt in het proces voor de generatie van het document.

Company adress

Na de basisconfiguratie, selecteert u Voorkeuren  Instellingen. Hier kunt u Kraft correct voorbereiden zodat het op de juiste manier gebruikt kan worden.

In het dialoogvenster voor de instellingen hebben we de tabs:

*Standaarddocument
*Belastingen
*Dokumenttypes
*Salarissen
*Eenheden
*Uw eigen identiteit

In elke tab is het mogelijk om voor uw specifieke geval realistische waarden in te voeren.

Document typen

Bij het eerste gebruik vindt u een lijst met verschillende documenttypes, zoals:

  • Acceptance of order (opdrachtbevestiging)

  • Delivery receipt (afleverbon)

  • Invoice (rekening)

  • Offer (offerte)

Document type

Vertaal deze typen naar uw eigen taal. U kan ook nieuwe documenten toevoegen en documenten verwijderen waarvan u denkt dat u die niet zal gebruiken.

Uniek documentnummer

Numbercycles Elk document moet een uniek identificatie hebben die het document identificeert. Er mogen in Kraft geen twee documenten aanwezig zijn met dezelfde identificatie.

De opbouw van het identificatie is in Kraft instelbaar. Hiervoor heeft Kraft het concept van zogeheten volgnummers. Volgnummers worden gebruikt om de opbouw van het documentnummer te definiëren dat op elk document wordt geprint.

Alle documenten van een bepaald type hebben een identificatie die uit een één volgnummersysteem komen. Aan elk documenttype is een volgnummersysteem gekoppeld. Verschillende documenttypes kunnen hetzelfde volgnummersysteem gebruiken om hun identificatie uit te generen. Op die manier kunnen bijvoorbeeld de documenttypes Invoice (rekening) en Final Invoice (eindafrekening) nummers uit dezelfde volgnummersysteem gebruiken, terwijl ze in Kraft verschillende documenttypes zijn. Volgnummersystemen worden geïdentificeerd door hun naam. Gebruikers kunnen nieuwe volgnummersystemen creëren en deze bewerken door op de knop Volgnummersysteem bewerken…​ te klikken

De opbouw van de documentnummers worden gedefinieerd in een sjabloon waarin normale, vaste karakters maar ook enkele variabelen aanwezig kunnen zijn die worden vervangen door hun respectievelijke waarden bij de creatie van het document.

Elk documentnummer moet uniek zijn, en moet dus een teller hebben. Kraft kan twee soorten tellers gebruiken: Een type (variabele %i) wordt bij elk nieuw document verhoogt. De andere (variabele %n) wordt elke dag teruggezet en begint dus weer bij 1 op elke nieuwe dag. Behalve de teller kan extra informatie toegevoegd worden om een bruikbaar documentnummer te krijgen, zoals een constante tekst of gedeeltes van de datum.

Het standaard volgnummersysteem dat met Kraft wordt geleverd bevat het jaar, de maand en een serienummer. Op deze manier kunt u offertes of opdrachten van het vorige jaar vergelijken met die van dit jaar of van de maand April van het vorige jaar met de maand April van dit jaar en op die manier een indruk krijgen van de resultaten van uw bedrijf.

Zie de volgende tabel voor de beschikbare variabelen die gebruikt kunnen worden:

%y of %yyyy

het jaar van de documentdatum.

%yy

het jaar van de documentdatum (twee cijfers).

%w

het weeknummer van de documentdatum.

%ww

het weeknummer van het documentdatum met een nul (twee cijfers).

%d

de dag van de week als getal van de documentdatum.

%dd

de dag van de week als getal van het documentdatum met een nul (wee cijfers).

%m of %M

de maand van het documentdatum als getal.

%MM

de maand van het documentdatum als getal met een nul (twee cijfers).

%c

de ID van de klant in het kaddressbook

%type

het vertaalde doc type (offerte, rekening enz.)

%uid

het contact id van de klant.

%i .. %iiiiii

de unieke teller (verplicht)

%n .. %nnnnnn

de unieke dagteller (te combineren met de datum)

In een volgnummersysteem-sjabloon moet naar keuze %i of %n aanwezig zijn, als dat niet het geval is dan wordt automatisch %i eraan toegevoegd.

Zowel %i als %n hebben numerieke waarden. Ze kunnen ook worden voorafgegaan door extra nullen. De length is afhankelijk van het aantal i’s of n’s die in het sjabloon voorkomen. Bijvoorbeeld, als u een dagelijkse teller met een lengte van drie cijfers en voorloop nullen wenst, dan moet u %nnn in de sjabloon plaatsen. Dit werkt tot een lengte van zes karakters.

Opmerking: het "ontwerp" van het volgnummersysteem en documentnummers is erg belangrijk. Door het flexibele systeem van sjablonen in Kraft kan niet ongeldige volgnummersystemen voorkomen. Dit is de verantwoordelijkheid van de gebruiker.

PDF Template

In the entry field Template File: the user can select a custom template for this specific document type.

If the file extension of the template file is .trml, the ReportLab based document converter is used. If the file extension is .gtmpl, Kraft automatically uses the Weasyprint based converter.

Noot
The ReportLab system for PDF creation is deprecated in Kraft. Please, for new templates, always use Grantlee- and Weasyprint based templates.

PDF Postprocessing

After Kraft has created the PDF document it is possible to merge the created PDF with static, customized PDFs created by the user. With that, it is easy to add a custom stationery with a logo to the resulting PDF ("Watermark").

The static PDFs should have the same page size as the generated documents. Keep in mind to use optimized images for logos etc. to not blow up the size of the result document.

PDF Postprocessing

The watermark options are:

  1. No Watermark: No watermark is created

  2. On first page: The first page of the watermark.pdf is merged with the first page of the result document

  3. Watermark on all pages: Merges the first page of the watermark PDF to all pages of the result document

  4. alternating: For this, the watermark PDF needs to have three pages. The first page is merged to the first page of the result document, the second and third page are alternated merge to subsequent pages.

  5. different first and last page: the PDF needs to have three pages. The first page is merged to the first page of the result document, the third page to the last, and the second to all page between first and last page.

If there is another static PDF document put into the entry field "Append PDF:", it is appended to the generated PDF. With that, Kraft will automatically add for example terms and conditions documents to the final document.

Belastingen

Taxes In veel landen zijn er twee BTW-tarieven voor verkochte producten.

Een hoog tarief en een laag tarief.

Geef hier de toepasselijke waarden op voor het hoge tarief en voor het lage tarief. Als het belastingtarief wijzigt, dan kunt u hier de startdatum met de nieuwe belastingtarieven toevoegen.

Salarissen

Wages In Kraft is een lijst met salariskosten aanwezig. De items daarin worden in de sjablonen en in de berekeningen gebruikt.

Alle data kan bewerkt en aangepast worden in een configuratiedialoog dat u kunt bereiken via het menu-item 'voorkeuren', waar u ook nieuwe items kunt toevoegen .

Vergeet niet dat deze items later worden gebruikt in de documenten, het is daarom belangrijk dat u ze vertaalt naar uw eigen taal en dat u de correcte bedragen invult.

Eenheden

Units of measurement In Kraft is een verzameling eenheden aanwezig. In het configuratiedialoog die u kunt bereiken via het menu-item 'Voorkeuren' kunt u de items die al aanwezig zijn bewerken, maar u kunt ook nieuwe items toevoegen.

Vergeet niet dat deze eenheden later worden gebruikt in de documenten, het is daarom belangrijk dat u ze vertaalt naar uw eigen taal.

Uw eigen identiteit

Controleer hier of de informatie die u heeft opgegeven tijdens de basisconfiguratie correct is voor het gebruik in de documenten.

Pas op: Als u de keuze heeft gemaakt om de informatie in Kaddressbook te gebruiken dan wordt de informatie die u handmatig toevoegt genegeerd.

Nadat we indien nodig de gewenste correcties in de configuratie hebben aangebracht, gaan we terug naar het hoofdvenster. Hier zien we drie tabs:

  • Documenten

  • Tijdlijn

  • Catalogi

Catalogi

Kraft gebruikt zogeheten Catalogi waarin sjablonen voor document items worden bewaard. Door de catalogi te gebruiken kan in het dagelijks gebruik het creëren van documenten significant worden versneld. Tijdens de creatie van nieuwe documenten, kunt u in de catalogi de items-sjablonen eenvoudig selecteren en naar het document verplaatsen.

Omdat sjablonen worden georganiseerd in mappen, kunnen hele documenten worden voorbereid en opgeborgen in verschillende mappen om later als documentsjabloon te worden gebruikt.

Uiteraard kunnen de items in de documenten worden bewerkt nadat ze in een catalogus zijn geselecteerd.

Kraft komt standaard met twee verschillende catalogi:

Material

Een catalogus met materialen die worden verkocht, met hun inkoopprijs, de winst en hun verkoopprijs.

en Standard Templates

Een catalogus met standaard recepten voor werkzaamheden zoals het planten van bomen.

Beide catalogussen kunnen mappen en submappen hebben om daar uw sjablonen in op te bergen . Eerst gaan we gegevens toevoegen aan de

Materiaalcatalogus

Een catalogus met materialen die worden verkocht, met hun inkoopprijs, de winst en hun verkoopprijs. Eerst gaan we nieuwe mappen en submappen toevoegen.

Nieuwe mappen

Selecteer met de muis de kolomnaam material, selecteer vervolgens in het contextmenu [Submap toevoegen]

en voeg een extra map zoals Bomen toe

Nieuwe submappen

We gaan nu submappen toevoegen aan de map Bomen. Selecteer met de muis de naam van de map waaraan u een submap wilt toevoegen, selecteer nu in het contextmenu [Submap toevoegen] en voeg extra submappen zoals Bladbomen en Naaldbomen toe. Nadat we extra mappen en submappen hebben toegevoegd om het materiaal onder te verdelen, gaan we het materiaal zelf toevoegen.

Nieuw sjabloon

Selecteer met de muis de naam van de submap of map waarin u materiaal wilt toevoegen. Selecteer de submap bladbomen en selecteer nu in het contextmenu nieuw sjabloon.

Voeg de nieuwe bomen kokosnoot-boom, appelboom en ananasboom toe.

Vul de prijs in die we hebben betaald.

Vul de winst in die we willen hebben op het materiaal.

En vul in per hoeveel ze verpakt zijn.

Material catalog Hierna voegen we ook in de map 'Wood' een item toe voor 'boompaal' met zijn prijs voor later gebruik.

Nu gaan we naar:

Standard Templates

Dit is een catalogus met standaard recepten voor werkzaamheden zoals:

  • Bomen planten

  • Gras maaien

  • Transportkosten

  • Graszoden leggen

  • Graszaad zaaien

We gaan hier de standaard werkzaamheden voor het planten van een boom toevoegen.

Selecteer met de muis de naam van de map [Work] waar u de nieuwe sjabloon aan wilt toevoegen,

selecteer nu in het contextmenu Nieuw sjabloon

en voeg de extra sjablonen Boom planten en Gras maaien toe.

Nadat we de nieuwe sjabloon hebben aangemaakt, opent een venster met 4 tabs:

  • Sjabloon

  • Post arbeid

  • Vaste kosten

  • Materiaal

Eerst gaan we naar de tab:

Sjabloon

We geven hier de naam op van de nieuwe standaard sjabloon zoals Boom planten Standard catalog

Pas op: wees voorzichtig, dit is de naam die later op de rekening komt.

we stellen hier in dat het per stuk is en dat de winst 8% is en dat het hoge BTW-tarief van toepassing is.

Post arbeid

We vullen hier een aantal werkzaamheden met hun tijd in:

Tabel 1. Gebruikte tijd

Gat graven

32 min.

worker

Boom plaatsen

12 min.

worker

Gat opvullen

17 min.

worker

Water geven

5 min.

worker

De kosten voor een werknemer die we eerder hebben ingevuld worden nu gebruikt.Time calculation

Opmerking: op de rekening zien we later alleen Boom planten, we zullen dan niet de onderdelen Gat graven, boom plaatsen, Gat opvullen, Water geven zien.

We gaan nu naar de tab:

Vaste kosten

en we vullen in:

Tabel 2. Vast item

Transportkosten

35 euro

1 pcs.

Fixed cost

Hierna gaan we naar de tab:

Materiaal

Hier kiezen we volgende, waarna het venster [Materiaal toevoegen aan Berekening] opent voor de selectie van materiaal. We gaan dan naar de map 'wood' waar we de 'boompaal' selecteren.

Tabel 3. Gebruikte materialen

1

boompaal

3,5 euro

Material

We gaan nu terug naar de eerste tab 'Sjabloon'

In de eerste tab [Sjabloon], kunnen we nu de totale kosten per eenheid zien.

Klik op OK om het resultaat op te slaan of op Annuleren om het resultaat te verwijderen.

We maken een tweede sjabloon 'Gras maaien'.

we vullen in Gras maaien, als eenheid kiezen we sm (square meter in het Engels) of m² (in het Nederlands), in de tweede tab vullen we in dat 3 min nodig hebben per vierkante meter.

Klik op OK om het resultaat op te slaan of op Annuleren om het resultaat te verwijderen.


Kraft supports text templates also for the header- and footer-text of documents. Each document type has it’s own set of text templates. To access them, open a document of a certain document type in edit mode and use the show templates to make the templates visible. In both the header- and footer-section the stored templates become visible.

Directly under the navigation pane on the right side of the window is a list of the names of the available templates. Clicking on one of the names in the list displays the text in the pane below.

Underneath there are buttons located with the following functions from left to right:

  1. Add the template to the document: This button replaces the text of the document with the selected template.

  2. Insert the template to the document: The selected template is inserted to the current place of the cursor in the document.

  3. Create a new template: Opens a dialog to enter a complete new template for the current doc type.

  4. Edit the current template: Opens the dialog to edit the currently selected template.

  5. Delete the current template: Removes the template permanently from the list of available templates.

Noot
Templates with the name Standard are the default templates for the document type. They are inserted automatically if a document of this type is created.

Macros

Both the header- and footer-templates can contain so called macros which are replaced with calculated values once the document is rendered to the final output format.

The following list of macros are supported:

  • DATE_ADD_DAYS(<amount_days>): Returns the date of the of document plus the number of days specified as parameter to the macro.

  • ITEM_COUNT_WITH_TAG(<tag>): Returns the amount of items tagged with the tag.

  • NETTO_SUM_PER_TAG(<tag>): Returns the netto sum of all items that are tagged with the named tag.

  • BRUTTO_SUM_PER_TAG(<tag>): Returns the brutto sum of all items that are tagged with the named tag.

  • VAT_SUM_PER_TAG(<tag>): Returns the pure tax of all items that are tagged with the named tag.

  • IF_ANY_HAS_TAG(<tag>) and END_HAS_TAG: Includes the text between the two macros only if there is at least one item that is tagged with the tag.

As an example, this footer text template can be used to automatically generate useful texts:

IF_ANY_HAS_TAG(Material) This invoice lists material in ITEM_COUNT_WITH_TAG(Material) items. The net value is NETTO_SUM_PER_TAG(Material), plus VAT_SUM_PER_TAG(Material) = BRUTTO_SUM_PER_TAG(Material). END_HAS_TAG ```

We zijn nu klaar voor de eerste rekening.

[[Invoice]]
== De creatie van documenten

=== De eerste rekening

Open de tab btn:[Documenten]

Klik op btn:[Nieuw document]

Het document-venster [creation wizard] opent.

Selecteer in document type `invoice` (rekening).

Vul op het whiteboard een korte tekst over wat de rekening is, zoals: `gras maaien en boom planten voor de heer Jansen` .

Klik op btn:[Volgende]

Selecteer in het volgende venster de naam en adres van de klant.

(Als de naam en adres niet aanwezig zijn, klik dan op btn:[nieuw contactpersoon] of op btn:[contactpersoon bewerken] als u het contact wilt bewerken)

Klik op btn:[OK].

Nu opent het venster document-items.

Dit venster heeft bovenaan 2 tabs en 3 knoppen:

* btn:[Item toevoegen...],
* btn:[Korting geven],
* btn:[Document tonen].

Aan de linkerkant kunt u alle items zien die we op de rekening willen plaatsen, aan de rechterkant zien we de tekst van de koptekst, de totale prijs en de voettekst.

Als u op de tekst van de koptekst of van de voettekst aan de rechterkant klikt dan verandert het venster zodanig dat u de koptekst of de voettekst kan bewerken.

Pas de koptekst en de voettekst aan naar uw situatie, in de voettekst kan u bijvoorbeeld een tekst plaatsen als: Wij maken uw tuindroom werkelijkheid.

Klik op de knop btn:[Document tonen].

De rechter tab verandert en toont nu de eerder gemaakte sjablonen, we selecteren in de map 'Work', de submap 'Boom planten' en klikken op de knop met de naar links wijzende pijl aan de onderkant.

Een nieuw venster [Item van sjabloon creëren] opent.

Omdat we 2 bomen hebben geplant, gaan we naar het veld [invoegen] en veranderen dit naar 2 pcs (in het Nederlands stk).

Klik op btn:[OK] om het resultaat op te slaan of op btn:[Annuleren] om het resultaat te verwijderen.

Het venster sluit en we gaan terug naar het hoofdvenster.

We klikken opnieuw op btn:[Document tonen] en selecteren deze keer `gras maaien`, we klikken opnieuw op de knop met de pijl, in het geopende venster stellen we in dat het grasveld 24 vierkante meter was.

Klik op btn:[OK] om het resultaat op te slaan of op btn:[Annuleren] om het resultaat te verwijderen.

We voegen nu handmatig een item toe door te klikken op de knop btn:[Item toevoegen…] waarna het venster [Item creëren] opent.

Omdat we een speciale boom hebben geleverd, vullen we hier de naam van de speciale boom `liguster` in, in het veld invoegen vullen we het aantal van de speciale boom die we geleverd hebben in en de prijs daarvan.

____
Pas op: verlies niet uit het oog dat we in de catalogus een winst op de prijs van het materiaal kunnen toevoegen, in de rekening en in de offerte kunnen we geen winst aan de prijs van het materiaal toevoegen.
____

We hebben nu een rekening met 3 items.

Klik op btn:[OK] om de rekening op te slaan of op btn:[Annuleren] om de rekening te verwijderen.

We klikken op btn:[OK] en slaan het resultaat op.

Uw eerste rekening is nu klaar voor verzending.

In het venster met documenten zien we onze eerste rekening, merk op dat dit document een documentnummer heeft die we aan de linkerkant zien.

Bovenaan het venster met alle rekeningen zien we de knop btn: [Print Document], waar we op klikken.

Van de rekening zal nu een PDF worden gemaakt die we op papier kunnen uitprinten of per email naar de klant kunnen versturen.

Hierna gaan we een offerte maken voor wat werk in een tuin.

[[Offer]]
=== Een offerte creëren

De klant heeft gevraagd of we een boom kunnen planten, we bieden 3 verschillende bomen aan die we kunnen planten.

Daarnaast hebben we gezien dat er een dode boom is, waarvoor we een aanbod doen om deze als extra werk te verwijderen. image:create_new_doc.png[Numbercycles,float="right"]

De totale prijs willen we exclusief de prijs voor de verwijdering van de dode boom en alleen de prijs van een boom en niet van drie bomen.

Open opnieuw de tab btn:[Documenten].

Klik op btn:[Nieuw document]

Het document-venster [creation wizard] opent.

Selecteer in btn: [document type]>btn:[offer].

Vul op het whiteboard een korte tekst over waarover de offerte gaat, zoals: `een boom planten en verwijding van dode boom` .

Klik op btn:[Volgende]

Selecteer in het volgende venster de naam en adres van de klant.

(Als de naam en adres niet aanwezig zijn, klik dan op btn:[nieuw contactpersoon] of op btn:[contactpersoon bewerken] als u het contact wilt bewerken)

Klik op btn:[OK].

Nu opent het venster [Document bewerken].

Dit venster heeft bovenaan 2 tabs en 3 knoppen:

* btn:[Item toevoegen...],
* btn:[Korting geven],
* btn:[Document tonen].

Klik op de knop btn:[Document tonen].

De rechter tab verandert en toont nu de eerder gemaakte sjablonen, we selecteren in de map 'Work', de submap 'Boom planten' en klikken op de knop met de naar links wijzende pijl aan de onderkant.

Een nieuw venster [Item van sjabloon creëren] opent.

Omdat we 1 boom willen planten, gaan we naar het veld [invoegen] en houden dit op 1 pcs (in het Nederlands stk).

Klik op btn:[OK] om het resultaat op te slaan of op btn:[Annuleren] om het resultaat te verwijderen.

Het venster sluit en we gaan terug naar het hoofdvenster.

We klikken op de knop btn:[Document tonen] en selecteren deze keer de catalogus Material.

De material-catalogus opent, en we kunnen in de map `Bomen` de submap `Bladbomen` selecteren waar we de `appelboom` selecteren die we eerder hebben gemaakt.

Klik op btn:[OK] om het resultaat op te slaan of op btn:[Annuleren] om het resultaat te verwijderen.

Het venster sluit en we gaan terug naar het hoofdvenster.

We voegen nu handmatig een item toe door te klikken op de knop `Item toevoegen...'.

Het venster [Nieuw item aanmaken] opent.

We willen dat de klant een keuze kan maken tussen een appelboom, een perenboom en de liguster.

Daarom gaan we een perenboom handmatig toevoegen.

We klikken op de knop btn:[Item toevoegen…] waarna het venster [Item creëren] opent.

We vullen hier de naam van de boom `Perenboom` in, en in veld invoegen vullen we het aantal van de speciale bomen in die we kunnen leveren en de prijs daarvan.

We willen dit aan de materiaalcatalogus toevoegen voor toekomstig gebruik, daarom selecteren we ook [Dit item als sjabloon bewaren voor latere documenten] en selecteren we in btn:[opslaan in map] 'bomen'.

Klik op btn:[OK] om het resultaat op te slaan of op btn:[Annuleren] om het resultaat te verwijderen.

We doen dit ook voor de liguster.

We hebben nu 3 items met bomen in de offerte.

En tenslotte voegen we een item toe met 'boom verwijderen' met 0,5 uur voor 32 euro.

Links van het item zien we 2 knoppen:

Een knop met een vlag en een knop met wat lijkt op een pagina.

We selecteren de bovenste knop met de pagina waarna een contextmenu opent met de items:

image:context1.png[Context menu,float="right"]

 [ Soort item]->[Normaal]
 [Soort item]>[Alternatief]
 [Soort item]>[Op verzoek]
 [Belasting]
 [Omhoog verplaatsen]
 [Omlaag verplaatsen]
 [Item vastzetten]
 [Item ontgrendelen]
 [Verwijder item]

We selecteren hier [Soort item] en veranderen dit voor `perenboom` van [normaal] naar [alternatief].

We doen dit ook voor [liguster] en voor [Boom verwijderen] veranderen we dit van [normaal] naar [Op verzoek].

image:context2.png[Context menu,float="right"]

Klik op btn:[OK] om het resultaat op te slaan of op btn:[Annuleren] om het resultaat te verwijderen.

We willen het resultaat bekijken en daarom klikken we op de knop btn:[Document tonen].

We zien nu dat de prijs voor de perenboom, de liguster en het verwijderen van de boom niet is gebruikt voor de totale prijs. Als we tevreden zijn met het resultaat, dan klikken we op de knop btn:[OK] waarna we klikken op de knop btn:[Document afdrukken] voor het maken van een PDF die we kunnen uitprinten of naar de klant kunnen sturen.

Na uw eerste rekening is nu ook uw eerste offerte klaar voor verzending.

[[Acceptance_of_order]]
=== Een Acceptance of order (opdrachtbevestiging) aanmaken

Het documenttype "Acceptance of Order" (opdrachtbevestiging) wordt verstuurd als vervolg op een offerte.

image:acceptance_o_o_context.png[Numbercycles,float="right"]

Als een klant een verzoek heeft gemaakt, dan zullen we een offer (offerte) sturen waarin we beschrijven welke items we zullen gaan leveren. Hopelijk zal de klant een order geven voor het werk.

Het is een goede gewoonte om op de order te reageren met een "Acceptance of order" (opdrachtbevestiging) waarin we alle items beschrijven die we zullen gaan leveren. We kunnen de "Acceptance of order" op dezelfde manier maken als waarmee we de invoice (rekening) of de offer (offerte)hebben gemaakt door elk item te selecteren en het aantal te leveren aan te passen. Dit kost tijd en we kunnen fouten maken door items te vergeten of een incorrect aantal in te vullen.

U kunt dit sneller doen door de offer (offerte) in de lijst te selecteren en vervolgens btn:[Creëer opvolg document] in het context menu of in het hoofdmenu te selecteren.

We hebben nu als documenttype de keuze uit:

 [Acceptance of order]
 [Invoice]
 [Partial Invoice]
 [final Invoice]
 [Progress Payment Invoice]

image:followup_1.png[Folloup document,float="right"]

We selecteren nu "Acceptance of order". We hebben nu een kopie van de offerte als een Acceptance of order (vergeet niet om de alternatief items en de op verzoek items aan te passen.)

image:followup_2.png[Folloup document,float="right"]

U kunt dit ook doen voor de creatie van de invoice (rekening) als opvolging van de opdrachtbevestiging. Elk documenttype heeft een specifieke lijst met opvolg-documenten. Het is een goede gewoonte om op de rekening precies te omschrijven wat is geleverd.

[[Customization]]
== Kraft naar wens aanpassen

Een groot gedeelte van de grafische interface van Kraft kan aangepast worden, met name de uitvoer die het genereert.

=== Documentuitvoer aanpassen

Om PDF's te creëren, moet een sjabloon worden gevuld met de document data die in Kraft is gecreëerd. De sjabloon definieert hoe de het resulterende document eruit komt te zien, d.w.z de ingestelde lettertypes, de plaats van de elementen en dergelijke.

Het bestand dat is samengesteld uit een combinatie van de data en de sjabloon wordt geconverteerd naar een PDF met een speciaal document creation script. Dit alles wordt automatisch door Kraft gestart als een document uitgeprint moet worden.

In Kraft kan elk documenttype zijn eigen sjabloon hebben voor de creatie van een PDF. Welk wordt gebruikt kan u instellen in het instellingsvenster voor documenttypes.

==== WeasyPrint Documenten

NOTE: Kraft still ships with the old ReportLab based converter, but that will be deprecated the future. The WeasyPrint based system is the future. It is a recommended to port existing templates.

With https://weasyprint.org[WeasyPrint] Kraft uses a very powerful generator that makes it very easy to create highly customized documents with great quality.

WeasyPrint converts a html file to PDF. It is integrating a cascading stylesheet (CSS) file which has a huge impact on the PDF document's look.

The html- and CSS input file for WeasyPrint is built from the Kraft template file.

To enable the use of WeasyPrint for a document type in Kraft, simply create a weasyprint compatible template file and save it with the extension *.gtmpl*. Based on the file extension Kraft automatically uses WeasyPrint and the Grantlee templating engine for rendering.

From version 0.95 on Kraft ships with an example template in the Grantlee- and WeasyPrint format. It can be found at `/usr/share/kraft/reports/invoice.gtmpl` or https://github.com/dragotin/kraft/blob/master/reports/invoice.gtmpl[online on Github]. An example CSS file `kraft.css` (https://github.com/dragotin/kraft/blob/master/reports/kraft.css[on Github]) is shipped as a good starting point for adoption.

==== Sjabloon variabelen

To generate the PDF, Kraft has to transfer data from the document you have been working on to the input file that is processed to a PDF. For that, Kraft uses a text template in which Kraft replaces variables with the actual values.

For example, the tag `{{ doc.doctype }}` is replaced with the current document type during the generating process.

De syntax is gebaseerd op de Django syntax voor sjablonen zoals het beschreven wordt in https://docs.djangoproject.com/en/3.1/topics/templates/[de documentatie].

==== EPC QR Code

With Weasyprint based PDF generation Kraft supports the https://en.wikipedia.org/wiki/EPC_QR_code[EPC QR Code] which implements a European standard for payments by computer and mobile devices.

In Germany it is also known as _Giro Code_, in Belgium as _Bancontact QR_, in the Netherlands as _iDEAL QR-code_ and in Spain it is also known as _Bizum QR-code_.

In Germany it is accepted by the _Giro Code_ and in Holland it is accepted by the official https://www.ideal.nl/consumenten/ideal-app/[_iDEAL QR-code_] app.

In Belgium and Holland it is accepted by the apps of many banks, and in Austria and Finland it is accepted by the apps of all banks.

To use the EPC QR code on the invoice printout, the bank account information has to be added to own identity settings dialog in Kraft. The giro code is current only generated for documents with the document type `Rechnung`.

To include the generated EPC QR Code into the PDF document, the Weasyprint template needs to contain a snippet like this:
{%if doc.isInvoice and epcqrcode.valid %}
<p class="epcqrcode">
  <img class="epc" src="file://{{ epcqrcode.svgfilename }}" alt="EPC QR Code" />
  Dieser QR Code ermöglicht einfaches, sicheres und schnelles Begleichen dieser Rechnung via GiroPay:
  Diesen Code mit dem Smartphone scannen und Überweisung per Banking App aufgeben.
</p>
{% endif %}
[[Menu]]
== Menu's en sneltoetsen

=== Hoofdvenster van het programma

[[File]]
==== Het menu Bestand

 [Bestand]>[Afsluiten]
 [Ctrl]+[Q]
 Sluit het programma af.

[[Document]]
==== Het document-menu

[[Show_document]]
 [Document]>[Document tonen]
 [Ctrl]+[R]
 Opent een venster met het geselecteerde document om deze te tonen.
[[Edit_document]]
 [Document]>[Document bewerken]
 [Ctrl+O]
 Opent een venster met het geselecteerde document voor bewerking.
[[Open_document]]
 [Document]>[Open gearchiveerd document]
 [Ctrl]+[A]
 Opent een gearchiveerd document.
[[Create_document]]
 [Document]>[Nieuw document]
 Opent een venster met een wizard voor de creatie van een nieuw client-document.
[[Copy_document]]
 [Document]>[Kopieer Document]
 Maakt een kopie van het geselecteerde client-document naar een nieuw client-document
 Deze kan bij een andere klant horen of zelfs een ander documenttype zijn.
[[Follow_document]]
 [Document]>[Creëer een opvolg Document]
 Kopieert de inhoud van een offerte naar een order-acceptatie of een rekening.
[[Print_document]]
 [Document]>[Document afdrukken]
 Creëert een PDF van het geselecteerde client-document zodat u deze kan emaillen of
 uitprinten.
[[Mail_document]]
 [Document]>[Verzend document]
 [Ctrl]+[M]
 Verzend een document per email.


[[settings]]
==== Het instellingen-menu
[[edit_template]]
 [Voorkeuren]>[Tag sjabloon bewerken]
 [Ctrl]+[E]
 Opent een venster waarin u tags (zoals work,material, plants of discounts)
 kunt toevoegen, bewerken of vertalen.
[[redo]]
 [Voorkeuren]>[De initiële aanmaak opnieuw uitvoeren]
 [Ctrl+R]
 Voert de basisconfiguratie opnieuw uit. Hierna is een herstart van Kraft nodig.
[[toolbars]]
 [Voorkeuren]>[Werkbalken]
 Hier kunt u beslissen of de `hoofdwerkbalk` en de werkbalk `Document acties`
 worden getoond.
[[configure]]
 [Voorkeuren]>[Instellingen]
 [Ctrl]+[Shft]+[,]
 Hier kunt u Kraft instellen.

=== Het document-bewerkingsvenster.

[[context]]
==== Het contextmenu

 [Context]>[Soort item]
 wijzigt de status van dit item tussen
* Normaal
* Alternatief
* Op verzoek
[[Tax]]
 [Context]>[Belasting]
Lijkt niet te werken.
[[Move_up]]
 [Context]>[Omhoog verplaatsen]
 Verplaatst dit item een plaats omhoog in het document.
[[Move_down]]
 [Context]>[Omlaag verplaatsen]
 Verplaatst dit item een plaats omlaag in het document.
[[Lock_item]]
 [Context]>[Item vastzetten]
 Het is niet duidelijk wat het doet.
[[Unlock_item]]
 [Context]>[Item ontgrendelen]
 Het is niet duidelijk wat het doet.
[[Delete_item]]
 [Context]>[Verwijder item]
 Verwijdert dit item uit het document.


[[AdvancedTopics]]
== Geavanceerde onderwerpen

Dit hoofdstuk beschrijft geavanceerde onderwerpen rond het gebruik van Kraft. Daarbij wordt enige kennis van Linux veronderstelt, en het is verstandig om de instellingen door ervaren Linux-beheerders uit te laten voeren en deze vervolgens zorgvuldig en uitgebreid te testen.

=== Kraft gemeenschappelijk gebruiken.

Kraft kan gemeenschappelijk in een gedistribueerde omgeving gebruikt worden. Dat houd in dat meerdere gebruikers op hun eigen desktop met hun eigen Kraft instance met dezelfde data kunnen werken.

De hele situatie is aan verandering onderhevig, omdat Kraft in de nabije toekomst ownCloud als privé Cloud voor de opslag van de data zal gebruiken.

==== Database en Document-pool gezamenlijk gebruiken

De eenvoudigste situatie is als twee of meer Kraft-gebruikers de database gemeenschappelijk gebruiken en toegang tot dezelfde pool van PDF-documenten op de harde schijf hebben. Om het eenvoudig te houden, worden hier de situatie met twee gebruikers beschreven.

Een veelvoorkomende situatie kan als volgt zijn: twee verschillende Linux gebruikers willen Kraft gebruiken. Ze hebben beide hun eigen computer en werken in hetzelfde netwerk. Dit voorbeeld beschrijft een situatie met een hoofdkantoor die Kraft in de normale modus gebruiken, en een Notebook met Kraft, die in de read-only modus is om de documenten te bekijken, de catalogus te raadplegen en dergelijke.

Daarvoor is het volgende vereist:

1. Als Database-Backend wordt MySQL of MariaDB gebruikt. Sqlite is niet mogelijk.
2. De Database is met de gebruiker MySQL vanuit beide computers bereikbaar.
3. De map waarin de documenten worden opgeslagen, wordt voor beide computers bereikbaar zijn (shared).

____
Pas op: Er is geen beveiliging tegen het feit dat beide gebruikers tegelijk hetzelfde document kunnen bewerken. Om dat dit gevaarlijk is en tot onvoorziene resultaten kan leiden, raden wij aan om Kraft buiten het kantoor alleen in de readonly-modus te gebruiken. Deze readonly-modus wordt met de parameter -r ingeschakeld.
____

**De database gezamenlijk gebruiken**

De Database-server moet op de hoofdmachine geïnstalleerd zijn, of het moet op een gespecialiseerd apparaat zoals een NAS geïnstalleerd zijn. De snelheid van het netwerk beïnvloed de bruikbaarheid natuurlijk enorm.

Howtos voor het gebruik van MySQL zijn op het internet te vinden.

**De map met de document Pool delen (sharen)**

Kraft schrijft de gegenereerde PDF's in een lokale map. Welke dat is, kunt u instellen in het config-bestand van Kraft. Het config-bestand moet voor alle exemplaren van Kraft correct ingesteld zijn.

U kunt deze vinden in de thuismap van de gebruiker met de relatieve pad `.config/kraftrc`. Daarin moet de volgende tekst voorkomen:

PdfOutputDir=/data/space/kraftdoc/pdf

Er zijn verschillende manieren om de map te delen (sharen), bijvoorbeeld een NFS of een SMB Server. Het is belangrijk dat gebruikers van beide machines toegang hebben tot deze bestanden. De hoofdgebruiker heeft lees- en schrijfrechten nodig, de read-only gebruiker heeft voor de bestanden alleen lees-rechten nodig.

Een aanbevolen opstelling is een NFS Share met autofs, die op de hoofdmachine is ingesteld. Om de toegang tot de bestanden te beheren, raden wij aan om een gebruikersgroep te creëren waarin u de toegangsrechten kan beheren.

**Kraft in read-only modus**

Om Kraft in de read-only modus te starten, moet het programma met de volgende parameter `-r` gestart worden.

=== Gebruik van XRechnung

Kraft ondersteund het gebruik van de XRechnung standaard. Dat is een digitaal formaat voor electronische rekeningen, en als wet ingevoerd in Duitsland wat een EU richtlijn volgt. De XRechnung is een XML-bestandsformaat ontworpen voor dat doel.

Om de XRechnung Export productief te gebruiken, is nog een beetje handwerk in Kraft nodig. Kraft creëert het XML-bestand aan de hand van een sjabloon, vergelijkbaar met de normale PDF documenten. Dit houdt in dat het een sjabloon laadt wat statische elementen bevat (b.v. het adres van het bedrijf) die niet veranderen tussen de verschillende rekeningen. De dynamische elementen (data over de klant, items enz.) worden in het sjabloon geplaatst tijdens de stap van het generen.

Om correcte XRechnung-bestanden te generen voor het desbetreffende bedrijf, moet de gebruiker het sjabloonbestand handmatig aanpassen aan de eisen van het bedrijf. Merk op dat u dat maar eenmalig hoeft te doen en dat het niet moeilijk is voor iemand met een beetje computerervaring (Basiskennis van XML is gewenst).

Om het bestand aan te passen aan de eisen van het bedrijf, kunt u het beste beginnen met het https://raw.githubusercontent.com/dragotin/kraft/master/reports/xrechnung.xrtmpl[voorbeeld XRechnung-bestand]. U moet het downloaden en vervolgens opslaan op een plek waar u het kan bewerken. Open het in een normale tekstverwerker, zoals https://kate-editor.org/[Kate].

Bestudeer nauwkeurig het bestand zonder dat u afgeschrikt wordt door het XML-opmaak. Alle user strings (d.w.z. bedrijfsnaam, adres en dergelijke) zijn specifiek voor de gebruiker en moeten daarom overeenkomstig vervangen worden. Zoek https://www.xoev.de/xrechnung-16828[de details over de opmaak] hier op voor een beter begrip van de betekenis van de velden.

Zorg ervoor dat u de correcte XML-opmaak niet verstoort en wijzig niet de locatie van waar `{{ template_name }}` is gebruikt.

Nadat het bestand is aangepast aan de wensen, opent u het dialoogvenster voor de instellingen van Kraft en voer de bestandsnaam in het invoerveld voor het XRechnung Sjabloonbestand in de pagina voor document-standaarden.

Na deze stap zal het menu item btn:[Export XRechung] een dialoogvenster openen voor het ingeven van het bestandsnaam waarmee de XRechnung rekening wordt opgeslagen.

Dit bestand kan nu verzonden worden naar de ontvanger van de rekening.

NOTE: Er zijn validators voor rekeningen in het XRechnung formaat op het internet te vinden. Het is verstandig om het bestandsformaat van de XRechnung dat uit Kraft is geëxporteerd te laten valideren.

=== Changing the Locale

If it is needed that Kraft runs under a different locale than the actual desktop environment, this can be achieved by setting the desired locale in the start file of Kraft.

On the linux desktop, apps are usually started through a so called https://specifications.freedesktop.org/desktop-entry-spec/latest/[desktop file]. It contains the information how the Kraft binary is started if user clicks on the icon on the desktop or in the start menu.

The desktop file can usually be found in `/usr/share/applications/de.volle-kraft-voraus.kraft.desktop`.

It contains the line ``` Exec=kraft %u ``` which starts the application with the default locale.

Changing it to ``` Exec=env LANG=de_DE.UTF-8 kraft %u ``` would change that to run in the German locale for example, independent from the desktop environment location.


[[Credits]]
== Dankbetuigingen en licentie

Program and documentation copyright 2004–2023 Klaas Freitag

Documentation copyright 2020-2023 Ronald Stroethoff
kraft-1.1/manual/kraft.adoc000066400000000000000000001127631450127457600157230ustar00rootroot00000000000000= The Kraft Handbook Ronald Stroethoff, Klaas Freitag :toc: left :doctype: article :author: Ronald Stroethoff :email: :description: Kraft is a Qt program for organizing documents like quotes and invoices in a small business. :keywords: Qt;office;bookkeeping :experimental: :imagesdir: images/{lang}/ include::locale/attributes.adoc[] == Introduction Kraft is a Qt and KDE application to organize office documents like quotes and invoices in a small business. It eases the creation of documents and helps with repeating tasks. Using Kraft, there is no need for fiddling with a text processor any more. Documents are created by a few clicks, edited, generated and archived automatically. Kraft generates high quality PDF output for printing, mailing and archiving. Feature Overview:: * Simple creation of offers, invoices and similar documents. * Customer management, deeply integrated with the mature KDE KAddressbook. * Maintenance of document relations, ie. Partial invoices vs. invoices. * Templates for document header- and footertexts and for document items. * Pre calculation of item prices. * Material management. * Configurable document creation in PDF format for print and email. The code of Kraft is open source and is released under the https://en.wikipedia.org/wiki/GNU_General_Public_License[GNU General Public License]. NOTE: Kraft is driven by community of users, coders, artists and others by voluntary work. + Also this manual needs contributions! + + Learn more on https://github.com/dragotin/kraft/blob/master/manual/Readme.md[how to contribute]! == First Use and Basic Configuration When Kraft is started for the first time, it automatically enters the initial setup process. During the initial setup you are asked to select a database to use and give the name and address of your company. You can fill in your company address (that appears on the printed documents) in two ways: in the setup procedure use the first tab *Select from Addressbook* for to select your on address in KAddressBook (if you have filled your own address in KaddressBook) or use the second tab *Manual entry* for to fill in the information of the address from your company manually. This step is necessary for the correct generation of your documents as the address is automatically used in the document generation step. image:company_adress1.png[Company adress,float="right"] After the initial setup, select menu:Preferences[Settings]. That allows to prepare Kraft correctly so it can be used in a proper way. In the Preferences dialog we have the tabs: *Document Defaults *Taxes *Documunt Types *Wages *Units *Own identity Each of the tabs allows to enter useful values for the specific use case. === Document Types At the first use you find a list of different document types, such as: * Acceptance of order * Delivery receipt * Invoice * Offer image:documentype.png[Document type,float="right"] Translate this types to your own language. You can also add new ones and remove document types you wont use. ==== Numbercycles image:numbercycles.png[Numbercycles,float="right"] Each document has to have an unique identifier that identifies the document. There must not be two documents in Kraft with the same identifier. The format of the identifier is configuratable in Kraft. For that, Kraft has a concept of so called number cycles. Number cycles are used to define the form of the *document number* which is printed on every document. All documents of a certain type have identifiers taken out of one number cycle. Each document type has a number cycle assigned. Different document types can use the same number cycle to generate ids from. That way, for example the document types Invoice and Final Invoice can use numbers from the same number cycle, even thought they are different document types in Kraft. Number cycles are identified by their name. User can create new number cycles and edit them clicking on the button btn:[Edit Number Cycles...] The format of the document numbers are defined by a template that can contain normal, fixed characters and also some variables that are replaced by the respective values when the document is created. Each identifier needs to be unique, and thus has to contain a counter. Kraft supports two types of counter: One (variable `%i`) is incremented globally for every new document. The other (variable `%n`) is reset every day and starts at 1 again on every new day. In addition to the counter, more information can be added to the template form an useful number. Examples are a constant text or parts of the date. The default numbercycle delivered with Kraft contains the year, the month and a serialnumber. That way you can compare offers or orders from last year with this year or the month April of last year with the month April of this year and get on this way an impression from the results of your business. See the following table for available variables which can be used: |=== | `%y` or `%yyyy` | the year of the document date. | `%yy` | the year of the document (two digits). | `%w` | the week number of the document date. | `%ww` | the week number of the document date with leading zero. | `%d` | the day number of the document date. | `%dd` | the day number of the document date with leading zero. | `%m` or `%M` | the month number of the document date. | `%MM` | the month number with leading zero. | `%c` | the customer id from kaddressbook | `%type` | the localised doc type (offer, invoice etc.) | `%uid` | the contact id of the client. | `%i` .. `%iiiiii`| the unique counter | `%n` .. `%nnnnnn`| the unique day counter (combine with date) |=== A number cycle template needs to contain either `%i` or `%n`, if not, `%i` is appended automatically. Both `%i` and `%n` are numeric values. They can also be padded with with leading zeros. The length is defined by the number of i's or n's put into the template. For example, if a daily counter with length of three and leading zeros is desired, `%nnn` has to be put into the template. This works up to a length of six characters. ____ NOTE: The "design" of the numbercycles and document numbers is very important. With the flexible system of templating Kraft can not prevent invalid number cycles. It is in the responsibility of the user. ____ ==== PDF Template In the entry field Template File: the user can select a custom template for this specific document type. If the file extension of the template file is `.trml`, the ReportLab based document converter is used. If the file extension is `.gtmpl`, Kraft automatically uses the Weasyprint based converter. ____ NOTE: The ReportLab system for PDF creation is deprecated in Kraft. Please, for new templates, always use Grantlee- and Weasyprint based templates. ____ ==== PDF Postprocessing After Kraft has created the PDF document it is possible to merge the created PDF with static, customized PDFs created by the user. With that, it is easy to add a custom stationery with a logo to the resulting PDF ("Watermark"). The static PDFs should have the same page size as the generated documents. Keep in mind to use optimized images for logos etc. to not blow up the size of the result document. image:pdfpostproc.png[PDF Postprocessing,float?"right"] The watermark options are: 1. *No Watermark*: No watermark is created 2. *On first page*: The first page of the watermark.pdf is merged with the first page of the result document 3. *Watermark on all pages*: Merges the first page of the watermark PDF to all pages of the result document 4. *alternating*: For this, the watermark PDF needs to have three pages. The first page is merged to the first page of the result document, the second and third page are alternated merge to subsequent pages. 5. *different first and last page*: the PDF needs to have three pages. The first page is merged to the first page of the result document, the third page to the last, and the second to all page between first and last page. If there is another static PDF document put into the entry field "Append PDF:", it is appended to the generated PDF. With that, Kraft will automatically add for example terms and conditions documents to the final document. === Taxes image:taxes.png[Taxes,float="right"] In many countries there are two kinds of VAT-taxes for sold products. A high level and a low level. Fill here the appropriate amounts in for the high level and the low level. If the tax-level is changing, then you add here the start date with the new tax-levels. === Wages image:wages.png[Wages,float="right"] A list of wage costs is maintained in Kraft. The items are used in templates and during calculation. All data can be edited, customized and new items can be added in the Kraft Configuration Dialog reachable through the Settings menu. Remember that these units are later used in the documents, it is therefor important that you translate them to your own language and to fill in the correct prices. === Units of measurement image:unity.png[Units of measurement,float="right"] A list of units of measurement is maintained in Kraft. In Kraft Configuration Dialog reachable through the Settings menu can you edit and customize items already in the list, and also can you add new items to the list. Remember that these units are later used in the documents, it is therefor important that you translate them to your own language. === Own identity Check here if the information that you have given during the initial setup is correct for the use in the documents. ____ WARNING: If you made the choice to use the information from KaddressBook then is the information from a later manual entry ignored. ____ After we have made some corrections to the configuration, we go back to the main window.Here we see three tabs: * Documents * Timeline * Catalogs == Catalogs Kraft supports so called Catalogs in which templates for document items are kept. With the catalogs creating documents can be significantly accellerated in the day to day business. When creating new documents, the items templates from the catalogs can easily selected and moved over to the document. Since templates are organized in chapters entire documents can be prepared in different chapters to be used as template documents. Of course the items in the documents can be edited after they got picked from a catalog. By default Kraft comes with two different catalogs: `Material` A catalog of material that are sold, with their purchase prices, the profit and the sell-price. and `Standard Templates` A catalog of standard recipes of work like planting trees. Both catalogs can have chapters and sub-chapters for to organize your templates. First we are going to fill in the === Material Catalog A catalog of material that are sold, with their purchase prices, the profit and the sell-price. First we are going to add new chapters and subchapters. ==== New chapters Select with the mouse the column-name `material`, select now in the context-menu [Add a sub chapter] and add an extra chapter like `Trees` ==== New sub chapters We are going to ad sub chapters in the map `Trees`. Select with the mouse the name of the chapter where you like to add a subchapter, select now in the context-menu [Add a sub chapter] and ad an extra subchapters like `Loaf trees` and `needle trees`. After adding the extra chapters and subchapters for dividing the material, we are going to add the material themself. ==== New template Select with the mouse the name of the sub-chapter or chapter where you like to add a material. Select the sub map Loaf trees and select now in the context-menu [Add a template] Add the extra materials `coconut tree`, `apple tree` and `pine-apple tree`. Fill in the price that we have paid. Fill in the profit that we want to have on the material And fill in how much is in a packet. image:catalog_material.png[Material catalog,float="right"] After this we add also in the map 'Wood' a item for a 'support pole' for later use with its price. Now we are going to: === Standard Templates This is a catalog of standard recipes of work like: * planting trees * cutting grass * transport costs * planting grass * sowing grass-seed We add here the standard work of planting a tree. Select with the mouse the name of the chapter [Work] where you like to add the new template, select now the context-menu [New template] and the extra templates `Plant tree` and `cut grass`. After we made the new template, a window opens with 4 tabs: * Template * Time calculation * Fix costs * Material First we go to the tab: ==== Template We give here the name of the new standard template like `Plant tree` image:catalog_standard.png[Standard catalog,float="right"] ____ WARNING: be careful, this name is later used in the invoice ____ we select that this is per piece and that the margin is 8% and that the full VAT is applicable. ==== Time calculation We fill here in a number of work with the time: .Spent time [cols=",,",] |=== |Dig hole |32 min. |worker |Place tree |12 min. |worker |Fill hole |17 min. |worker |give water |5 min. |worker |=== The cost for worker which we have earlier filled in is now used. image:catalog_standard_work.png[Time calculation,float="right"] ____ NOTE: in the invoice we see later only Plant tree, we will not see the parts dig hole,place tree,fill hole,give water ____ Now we go to the tab ==== Fixed costs and fill in: .Fixed item [cols=",,",] |=== |Transportcost |35 euro |1 pcs. |=== image:catalog_standard_fixed_cost.png[Fixed cost,float="right"] After this we go to the tab: ==== Material Here we select btn:[next], after which the window [Add Material to Calculation] opens for a selection of material. We navigate to the map 'wood' where we select the 'support pole'. .Used materials [cols=",,",] |=== |1 |support pole |3,5 euro |=== image:catalog_standard_material.png[Material,float="right"] We go now back to the first tab template On the first tab [template], we can now see the overall cost per one unit Click on [OK] for saving the result or on [cancel] for discarding the result. We make a second template `cut grass` we fill in `cut grass`, as unit we choose sm (square meter), on the second tab we fill in that we need 3 min per square meter. Click on [OK] for saving the result or on [Cancel] for discarding the result. ''' === Header- and Footer Text Templates Kraft supports text templates also for the header- and footer-text of documents. Each document type has it's own set of text templates. To access them, open a document of a certain document type in edit mode and use the btn:[show templates] to make the templates visible. In both the header- and footer-section the stored templates become visible. Directly under the navigation pane on the right side of the window is a list of the names of the available templates. Clicking on one of the names in the list displays the text in the pane below. Underneath there are buttons located with the following functions from left to right: . Add the template to the document: This button replaces the text of the document with the selected template. . Insert the template to the document: The selected template is inserted to the current place of the cursor in the document. . Create a new template: Opens a dialog to enter a complete new template for the current doc type. . Edit the current template: Opens the dialog to edit the currently selected template. . Delete the current template: Removes the template permanently from the list of available templates. NOTE: Templates with the name _Standard_ are the default templates for the document type. They are inserted automatically if a document of this type is created. ==== Macros Both the header- and footer-templates can contain so called macros which are replaced with calculated values once the document is rendered to the final output format. The following list of macros are supported: - `DATE_ADD_DAYS()`: Returns the date of the of document plus the number of days specified as parameter to the macro. - `ITEM_COUNT_WITH_TAG()`: Returns the amount of items tagged with the tag. - `NETTO_SUM_PER_TAG()`: Returns the netto sum of all items that are tagged with the named tag. - `BRUTTO_SUM_PER_TAG()`: Returns the brutto sum of all items that are tagged with the named tag. - `VAT_SUM_PER_TAG()`: Returns the pure tax of all items that are tagged with the named tag. - `IF_ANY_HAS_TAG()` and `END_HAS_TAG`: Includes the text between the two macros only if there is at least one item that is tagged with the tag. As an example, this footer text template can be used to automatically generate useful texts: ---- Please pay this invoice until three weeks after the date of the document, which is the DATE_ADD_DAYS(21). IF_ANY_HAS_TAG(Material) This invoice lists material in ITEM_COUNT_WITH_TAG(Material) items. The net value is NETTO_SUM_PER_TAG(Material), plus VAT_SUM_PER_TAG(Material) = BRUTTO_SUM_PER_TAG(Material). END_HAS_TAG ---- We are now ready for the first invoice. [[Invoice]] == Creating Documents === The first Invoice Open the tab btn:[documents] Click on btn:[create document] The window document [creation wizard opens]. Select in document type `invoice`. Fill in on the whiteboard content a short text about what the invoice is, like: `cut grass and planted tree for mister Jonson` Click on btn:[next] Select on the new window the name and address from the client. (if the name and address is not there, click then on btn:[new contact] or on btn:[edit contact] if you want to edit the contact) Click on btn:[OK]. Now opens the window document [items]. this window has 2 tabs and the 3 buttons on the top: * btn:[Add item...], * btn:[Add discount item], * btn:[Show templates]. In the left tab you can see all the items that we want to place on the invoice, on the right tab we see the text from the header, the total price and the footer. If you click on the text of the header or the footer on the right side then the window changes in such a way that you can edit the header or the footer. Adapt the header and the footer to your situation, on the footer you can place a text: `We make your garden-dream come to reality.`. Click on the button btn:[Show templates]. The right tab changes and show now the earlier made templates, we select in the group Work, the subgroup Plant tree and click then on the button with the to the left pointing arrow on the bottom side. A new window [Create Item from Template] opens. Because we have planted 2 trees, we go to the field [insert] and change this to 2 pcs. Click on btn:[OK] for saving the result or on btn:[cancel] for discarding the result. The window close and we go back to the main window. We click again on btn:[Show templates] and select this time `cut grass`, we click again on the button with the arrow, in the opened window we select that the grass-field was 24 square meter. Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding the result. We add now manually an item by clicking on the button btn:[Add item…] and the window [create new item] opens. Because we have delivered a special tree, we fill here in the name of the special tree `liguster`, at the field insert we fill in the number of the special trees that we have delivered and the price of them. ____ WARNING: Remind that in the catalog we can add a profit on the price of the material, in the invoice and in the offer we can not add a profit on the price of the material. ____ We have now an invoice with 3 items. Click on btn:[OK] for saving the invoice or on btn:[Cancel] for discarding the invoice. We click on btn:[OK] and save the result. Your first invoice is now ready for sending. In the window documents we see our first invoice, notice that this document has a document number which we can see on the left side. On top of the window with all the invoices we see the button [Print Document], on which we click. From the invoice will now a PDF be made which we can print on paper or send by email to the client. After this we are going to create a offer for some work in a garden. [[Offer]] === Creating an Offer The client has asked to plant a tree, we will offer 3 different trees which we can plant. Beside this, we have seen that there is a lifeless three, which we will offer to remove as extra work. image:create_new_doc.png[Numbercycles,float="right"] For the total price we do not want to show the price of the removal of the lifeless tree and we want for the total price only to show the price of one tree and not three. Open again the tab btn:[documents]. Click on btn:[create document] The window _Document Creation Wizard_ opens. select in btn:[document type] > btn:[Offer]. Fill in on the whiteboard content a short text about what the offer is, like: `plant one tree and removal of lifeless tree` Click on btn:[next] Select on the new window the name and address from the client. (if the name and address is not there, click then on btn:[new contact] or on btn:[edit contact] if you want to edit the contact) Click on btn:[OK]. Now the window [edit document] opens. This window has 2 tabs and the 3 buttons on the top: * btn:[Add item...], * btn:[Add discount item], * btn:[Show templates]. Click on the button btn:[Show templates]. The right tab changes and show now the earlier made templates, we select in the group `Work`, the subgroup `Plant tree` and click then on the button with the to the left pointing arrow on the bottom side. A new window [Create Item from Template] opens. Because we want to plant 1 tree, we go to the field [insert] and keep this on 1 pcs. Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding the result. The window close and we go back to the main window. We click on the button btn:[Show templates] and this time we select in catalog Material The material-catalog opens, and we can select in the chapter `trees` the subchapter `loaf trees` in which we select the `apple tree` which we made earlier. Click on we btn:[OK] for saving the result or on btn:[cancel] for discarding the result. The window close and we go back to the main window. We add now manually an item by clicking on the button `Add item…`. the window [create new item] opens. We want that the client can make a choice from an apple, a pear tree and the liguster. Therefor we are going to add also a pear tree manually. We click on the button btn:[Add item…] and the window [create new item] opens. We fill here in the name of the tree `Pear tree`, at the field insert we fill in the number of the special trees that we have delivered and the price of them. We want add this to the material catalog for future use, therefor we select also [select this item as template for future documents] and we select in [save in chapter]`trees`. Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding the result. We does this again but then for the liguster. We have now 3 items with trees in the offer. As last item we add an item with `remove tree` with 0,5 hour for 32 euro. On the left side of an item we can see 2 buttons: a button with a flag and a button with what looks like a page. We select the upper button with the page after which opens a context-menu with the items: image:context1.png[Context menu,float="right"] [Item kind]->[Normal] [Item kind]>[Alternative] [Item kind]>[On demand] [Tax] [Move up] [Move down] [Lock item] [Unlock item] [Delete item] We choose here [Item kind] and change for `pear tree` from [normal] to [alternative]. We do this also for [liguster] and for [remove tree] we change this from [normal] to [on demand]. image:context2.png[Context menu,float="right"] Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding the result. We want to see the result and therefor we click on the button [show document]. We see now that the prize of the pear tree, the liguster and the removal of the tree is not used for the total prize. When we are happy with the result, we can click on the button btn:[close] after which we click on the button btn:[Print Document] for making a PDF what we can print out or send to the client. After your first invoice is now your first offer now also ready for sending. [[Acceptance_of_order]] === Creating an Acceptance of Order The document type "Acceptance of Order" is sent subsequently to an offer. image:acceptance_o_o_context.png[Numbercycles,float="right"] When a client has made a request, we will send an offer in wich we describe which items we will deliver. Hopefully the client will give an order for the work. It is a good practice to respond on the order with an "Acceptance of order" in which we describe all the items we will deliver. We can make the "Acceptance of order" on the same way as we made the invoice or the offer by selecting each item and correcting the number of delivery. This takes time and we can make errors by forgetting items or filling an incorrect number. It can be done quicker by selecting the offer in the list and selecting btn:[Create Followup Document] from either the context menu or the main menu. We have now in documenttype the choice from: [Acceptance of order] [Invoice] [Partial Invoice] [final Invoice] [Progress Payment Invoice] image:followup_1.png[Folloup document,float="right"] We select here "Acceptance of order". We have now a copy from the offer as an Acceptance of order (do not forget to adapt Alternative Delivery items and on demand items.) image:followup_2.png[Folloup document,float="right"] You can do this also for the creation of the invoice as a followup for Acceptance of order. Each document type has a specific list of follow up documents. It is a good practice to describe on the invoice precisely what was delivered. [[Customization]] == Customization Kraft can be customized in most of the graphical user interface and in particular in the output it generates. === Output Document Customization To create PDF output documents, the document data that was edited in the Kraft app is filled into a template. The template defines how the output document looks like, ie. by font settings, placing of elements and such. The file that is assembled from data and the template is converted to PDF using a special document creation script. All that is started automatically by Kraft if a document should be printed. Each document type in Kraft can have it's own template that is used to create a PDF. Which one can be set in the Settings dialog for document types. ==== WeasyPrint Documents NOTE: Kraft still ships with the old ReportLab based converter, but that will be deprecated the future. The WeasyPrint based system is the future. It is a recommended to port existing templates. With https://weasyprint.org[WeasyPrint] Kraft uses a very powerful generator that makes it very easy to create highly customized documents with great quality. WeasyPrint converts a html file to PDF. It is integrating a cascading stylesheet (CSS) file which has a huge impact on the PDF document's look. The html- and CSS input file for WeasyPrint is built from the Kraft template file. To enable the use of WeasyPrint for a document type in Kraft, simply create a weasyprint compatible template file and save it with the extension *.gtmpl*. Based on the file extension Kraft automatically uses WeasyPrint and the Grantlee templating engine for rendering. From version 0.95 on Kraft ships with an example template in the Grantlee- and WeasyPrint format. It can be found at `/usr/share/kraft/reports/invoice.gtmpl` or https://github.com/dragotin/kraft/blob/master/reports/invoice.gtmpl[online on Github]. An example CSS file `kraft.css` (https://github.com/dragotin/kraft/blob/master/reports/kraft.css[on Github]) is shipped as a good starting point for adoption. ==== Template Variables To generate the PDF, Kraft has to transfer data from the document you have been working on to the input file that is processed to a PDF. For that, Kraft uses a text template in which Kraft replaces variables with the actual values. For example, the tag `{{ doc.doctype }}` is replaced with the current document type during the generating process. The syntax is based on the Django syntax for templates described in the https://docs.djangoproject.com/en/3.1/topics/templates/[the docs]. ==== EPC QR Code With Weasyprint based PDF generation Kraft supports the https://en.wikipedia.org/wiki/EPC_QR_code[EPC QR Code] which implements a European standard for payments by computer and mobile devices. In Germany it is also known as _Giro Code_, in Belgium as _Bancontact QR_, in the Netherlands as _iDEAL QR-code_ and in Spain it is also known as _Bizum QR-code_. In Germany it is accepted by the _Giro Code_ and in Holland it is accepted by the official https://www.ideal.nl/consumenten/ideal-app/[_iDEAL QR-code_] app. In Belgium and Holland it is accepted by the apps of many banks, and in Austria and Finland it is accepted by the apps of all banks. To use the EPC QR code on the invoice printout, the bank account information has to be added to own identity settings dialog in Kraft. The giro code is current only generated for documents with the document type `Rechnung`. To include the generated EPC QR Code into the PDF document, the Weasyprint template needs to contain a snippet like this: ---- {%if doc.isInvoice and epcqrcode.valid %}

EPC QR Code Dieser QR Code ermöglicht einfaches, sicheres und schnelles Begleichen dieser Rechnung via GiroPay: Diesen Code mit dem Smartphone scannen und Überweisung per Banking App aufgeben.

{% endif %} ---- [[Menu]] == Menus and Shortcuts === Main Application Menu [[File]] ==== The File Menu [File]>[Quit] [Ctrl]+[Q] Quits the application. [[Document]] ==== The Document Menu [[Show_document]] [Document]>[Show Document] [Ctrl]+[R] Opens a window with the selected document for showing it. [[Edit_document]] [Document]>[Edit Document] [Ctrl+O] Opens a window with the selected document for editing it. [[Open_document]] [Document]>[Open Archived document] [Ctrl]+[A] Opens an archived document. [[Create_document]] [Document]>[Create Document] Opens a window with a wizard for creating a new client-document. [[Copy_document]] [Document]>[Copy Document] Makes a copy of the selected client-document to a new client-document which can belong to an other client or an other documenttype. [[Follow_document]] [Document]>[Follow Document] Opens the selected client-document for editing. [[Print_document]] [Document]>[Print document] Makes a PDf from the selected client-document for to be mailed or printed. [[Mail_document]] [Document]>[Mail document] [Ctrl]+[M] Mails a document. [[settings]] ==== The Settings menu [[edit_template]] [Settings]>[Edit Tag Templates] [Ctrl]+[E] Opens a window where you add, edit or translate the tags (like work, material, plants or discounts). [[redo]] [Settings]>[Redo initial setup] [Ctrl+R] Redoes the initial setup. After this, a restart of Kraft is required. [[toolbars]] [Settings]>[Showed toolbars] Here you can decide if the `main toolbar` and the toolbar `Document Actions` are shown. [[configure]] [Settings]>[Configure Kraft] [Ctrl]+[Shft]+[,] Here you can configure Kraft. === Document Edit Window [[context]] ==== The context Menu [Context]>[Item kind] change the status from this item between * Normal * Alternative * On demand [[Tax]] [Context]>[Tax] Seems not working. [[Move_up]] [Context]>[Move up] Moves this item a place up in document. [[Move_down]] [Context]>[Move down] Moves this item a place down in document. [[Lock_item]] [Context]>[Lock item] It is not clear what is does. [[Unlock_item]] [Context]>[Unlock item] It is not clear what is does. [[Delete_item]] [Context]>[Delete item] Removes this item from document. [[AdvancedTopics]] == Advanced Topics This chapter describes advanced topics around Kraft. Some Linux knowledge is required, and setups should be done by experienced Linux administrators and should be tested carefully. === Using Kraft Collaboratively Kraft can be used collaborative in a distributed environment. That means that multiple users work on their desktops with their own Kraft instance on the same data. This whole topic is a subject to change, as Kraft will evolve to use ownCloud as a private cloud solution to store the data. ==== Sharing Database and Document Pool The simplest case is that two or more Kraft instances use a database together and access the same pool of PDF documents on the harddisk. For simplicity this describes only two Kraft instances. A typical use case would be: Two different Linux users want to use Kraft. They both have their own computer but only work in the same network. For example this would describe a situation with one main office machine that runs Kraft in normal mode, plus a notebook with Kraft in read only mode to view documents, check catalogs and such. For that, the following prerequisites have to be met: 1. MySQL or MariaDB is used as database backend. Sqlite is not supported. 2. The database is accessible with a mysql user and from each machine for both users. 3. The document store directory has to be shared. ____ WARNING: There is no protection against having both users editing the same document. Because that is dangerous and can lead to unpredictable results, it is recommended to run all instances of Kraft except the main one in read only mode. This is done by starting Kraft with the `-r` command line switch. ____ **Sharing the Database** The database server should be installed on the main machine or a dedicated device like a NAS. Networking speed influences the comfort to use obviously. Find howtos on the internet how to setup MySQL accordingly. **Sharing the Document Pool Directory** Kraft writes generated PDF documents into a local directory. Where that is can be configured in the Kraft Config file. The config file has to be adopted on all instances. That is located in each users home directory, in the path `.config/kraftrc`. It has to contain the following config value: ---- [reporting] PdfOutputDir=/data/space/kraftdoc/pdf ---- There are different ways how share that directory, ie. NFS or SMB storages. It is important that both users from both machines can list and access the files. The main user needs read and write access, read only users only need read access to the files. A recommended setup is a NFS share with autofs which is set up on the main machine. To manage file access a certain group should be set up on the machines with which access can be managed. **Starting Kraft in read-only mode** To start Kraft in read-only mode, start the binary with the `-r` command line switch. === XRechnung Support Kraft supports the XRechnung standard. That is a digital format for electronic invoicing, and it passed as law in Germany and follows a EU directive. The XRechnung is a XML file format designed for that purpose. To use the XRechnung Export productivly, a little manual work is still needed in Kraft. Kraft creates the XML file based on a template, very similar to the normal PDF documents. That means that it loads a template that contains static elements (ie. the company address) that do not change between different invoices. The dynamic elements (customer data, items etc.) are filled into the template during the generation step. In order to generate correct XRechnung files for the specific company, the user has to adopt the template file manually to the companies needs. Note that this has only to be done once and should be easy for a person with a bit computer experience (Basic knowledge about XML appreciated!). To adapt the file to the needs of the company, it is best to start with the https://raw.githubusercontent.com/dragotin/kraft/master/reports/xrechnung.xrtmpl[example XRechnung file]. It has to be downloaded and saved into a location that the user can edit. Open it in a normal text editor, such as https://kate-editor.org/[Kate]. Read carefully through the file without being scared off by the XML format. All user strings (ie. company name, address and such) are user specific and should be replaced accordingly. Find https://www.xoev.de/xrechnung-16828[details about the format] here to better understand the meaning of the fields. Make sure to not disturb the proper XML format and do not change places where the template format `{{ template_name }}` is used. Once the file is adopted to the needs, open the Settings dialog of Kraft and insert the filename into the entry field for the XRechnung Template File on the Document Defaults page. After that step, the btn:[Export XRechung] menu item will open a dialog to pick a filename where to save the XRechnung invoice to. This file can now be transfered to the receiver of the invoice. NOTE: There are validators for invoices in XRechnung format out there in the internet. It is useful to verify the format of the Kraft exported XRechnung. === Changing the Locale If it is needed that Kraft runs under a different locale than the actual desktop environment, this can be achieved by setting the desired locale in the start file of Kraft. On the linux desktop, apps are usually started through a so called https://specifications.freedesktop.org/desktop-entry-spec/latest/[desktop file]. It contains the information how the Kraft binary is started if user clicks on the icon on the desktop or in the start menu. The desktop file can usually be found in `/usr/share/applications/de.volle-kraft-voraus.kraft.desktop`. It contains the line ---- Exec=kraft %u ---- which starts the application with the default locale. Changing it to ---- Exec=env LANG=de_DE.UTF-8 kraft %u ---- would change that to run in the German locale for example, independent from the desktop environment location. [[Credits]] == Credits and License Program and documentation copyright 2004–2023 Klaas Freitag Documentation copyright 2020-2023 Ronald Stroethoff kraft-1.1/manual/kraftmanual.css000066400000000000000000001037561450127457600170050ustar00rootroot00000000000000@import url(http://cdnjs.cloudflare.com/ajax/libs/font-awesome/3.2.0/css/font-awesome.css); /* normalize.css v2.1.1 | MIT License | git.io/normalize */ /* ========================================================================== HTML5 display definitions ========================================================================== */ /** Correct `block` display not defined in IE 8/9. */ article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { display: block; } /** Correct `inline-block` display not defined in IE 8/9. */ audio, canvas, video { display: inline-block; } /** Prevent modern browsers from displaying `audio` without controls. Remove excess height in iOS 5 devices. */ audio:not([controls]) { display: none; height: 0; } /** Address styling not present in IE 8/9. */ [hidden] { display: none; } /* ========================================================================== Base ========================================================================== */ /** 1. Prevent system color scheme's background color being used in Firefox, IE, and Opera. 2. Prevent system color scheme's text color being used in Firefox, IE, and Opera. 3. Set default font family to sans-serif. 4. Prevent iOS text size adjust after orientation change, without disabling user zoom. */ html { background: #fff; /* 1 */ color: #000; /* 2 */ font-family: sans-serif; /* 3 */ -ms-text-size-adjust: 100%; /* 4 */ -webkit-text-size-adjust: 100%; /* 4 */ } /** Remove default margin. */ body { margin: 0; } /* ========================================================================== Links ========================================================================== */ /** Address `outline` inconsistency between Chrome and other browsers. */ a:focus { outline: thin dotted; } /** Improve readability when focused and also mouse hovered in all browsers. */ a:active, a:hover { outline: 0; } /* ========================================================================== Typography ========================================================================== */ /** Address variable `h1` font-size and margin within `section` and `article` contexts in Firefox 4+, Safari 5, and Chrome. */ h1 { font-size: 2em; margin: 0.67em 0; } /** Address styling not present in IE 8/9, Safari 5, and Chrome. */ abbr[title] { border-bottom: 1px dotted; } /** Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. */ b, strong { font-weight: bold; } /** Address styling not present in Safari 5 and Chrome. */ dfn { font-style: italic; } /** Address differences between Firefox and other browsers. */ hr { -moz-box-sizing: content-box; box-sizing: content-box; height: 0; } /** Address styling not present in IE 8/9. */ mark { background: #ff0; color: #000; } /** Correct font family set oddly in Safari 5 and Chrome. */ code, kbd, pre, samp { font-family: monospace, serif; font-size: 1em; } /** Improve readability of pre-formatted text in all browsers. */ pre { white-space: pre-wrap; } /** Set consistent quote types. */ q { quotes: "\201C" "\201D" "\2018" "\2019"; } /** Address inconsistent and variable font size in all browsers. */ small { font-size: 80%; } /** Prevent `sub` and `sup` affecting `line-height` in all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sup { top: -0.5em; } sub { bottom: -0.25em; } /* ========================================================================== Embedded content ========================================================================== */ /** Remove border when inside `a` element in IE 8/9. */ img { border: 0; } /** Correct overflow displayed oddly in IE 9. */ svg:not(:root) { overflow: hidden; } /* ========================================================================== Figures ========================================================================== */ /** Address margin not present in IE 8/9 and Safari 5. */ figure { margin: 0; } /* ========================================================================== Forms ========================================================================== */ /** Define consistent border, margin, and padding. */ fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; } /** 1. Correct `color` not being inherited in IE 8/9. 2. Remove padding so people aren't caught out if they zero out fieldsets. */ legend { border: 0; /* 1 */ padding: 0; /* 2 */ } /** 1. Correct font family not being inherited in all browsers. 2. Correct font size not being inherited in all browsers. 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. */ button, input, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 2 */ margin: 0; /* 3 */ } /** Address Firefox 4+ setting `line-height` on `input` using `!important` in the UA stylesheet. */ button, input { line-height: normal; } /** Address inconsistent `text-transform` inheritance for `button` and `select`. All other form control elements do not inherit `text-transform` values. Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. Correct `select` style inheritance in Firefox 4+ and Opera. */ button, select { text-transform: none; } /** 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 2. Correct inability to style clickable `input` types in iOS. 3. Improve usability and consistency of cursor style between image-type `input` and others. */ button, html input[type="button"], input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ } /** Re-set default cursor for disabled elements. */ button[disabled], html input[disabled] { cursor: default; } /** 1. Address box sizing set to `content-box` in IE 8/9. 2. Remove excess padding in IE 8/9. */ input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /** 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome (include `-moz` to future-proof). */ input[type="search"] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; } /** Remove inner padding and search cancel button in Safari 5 and Chrome on OS X. */ input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /** Remove inner padding and border in Firefox 4+. */ button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } /** 1. Remove default vertical scrollbar in IE 8/9. 2. Improve readability and alignment in all browsers. */ textarea { overflow: auto; /* 1 */ vertical-align: top; /* 2 */ } /* ========================================================================== Tables ========================================================================== */ /** Remove most spacing between table cells. */ table { border-collapse: collapse; border-spacing: 0; } *, *:before, *:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } html, body { font-size: 100%; } body { background: white; color: #222222; padding: 0; margin: 0; font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; font-weight: normal; font-style: normal; line-height: 1; position: relative; cursor: auto; } a:hover { cursor: pointer; } a:focus { outline: none; } img, object, embed { max-width: 100%; height: auto; } object, embed { height: 100%; } img { -ms-interpolation-mode: bicubic; } #map_canvas img, #map_canvas embed, #map_canvas object, .map_canvas img, .map_canvas embed, .map_canvas object { max-width: none !important; } .left { float: left !important; } .right { float: right !important; } .text-left { text-align: left !important; } .text-right { text-align: right !important; } .text-center { text-align: center !important; } .text-justify { text-align: justify !important; } .hide { display: none; } .antialiased, body { -webkit-font-smoothing: antialiased; } img { display: inline-block; vertical-align: middle; } textarea { height: auto; min-height: 50px; } select { width: 100%; } p.lead, .paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { font-size: 1.21875em; line-height: 1.6; } .subheader, #content #toctitle, .admonitionblock td.content > .title, .exampleblock > .title, .imageblock > .title, .videoblock > .title, .listingblock > .title, .literalblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, .sidebarblock > .title, .tableblock > .title, .verseblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title, .tableblock > caption { line-height: 1.4; color: #777777; font-weight: 300; margin-top: 0.2em; margin-bottom: 0.5em; } /* Typography resets */ div, dl, dt, dd, ul, ol, li, h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6, pre, form, p, blockquote, th, td { margin: 0; padding: 0; direction: ltr; } /* Default Link Styles */ a { color: #417b06; text-decoration: none; line-height: inherit; } a:hover, a:focus { color: #417b06; } a img { border: none; } /* Default paragraph styles */ p { font-family: inherit; font-weight: normal; font-size: 1em; line-height: 1.6; margin-bottom: 1.25em; text-rendering: optimizeLegibility; } p aside { font-size: 0.875em; line-height: 1.35; font-style: italic; } /* Default header styles */ h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; font-weight: normal; font-style: normal; color: #417b06; text-rendering: optimizeLegibility; margin-top: 1em; margin-bottom: 0.5em; line-height: 1.2125em; } h1 small, h2 small, h3 small, #toctitle small, .sidebarblock > .content > .title small, h4 small, h5 small, h6 small { font-size: 60%; color: gray; line-height: 0; } h1 { font-size: 2.125em; } h2 { font-size: 1.6875em; } h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.375em; } h4 { font-size: 1.125em; } h5 { font-size: 1.125em; } h6 { font-size: 1em; } hr { border: dotted #cccccc; border-width: 1px 0 0; clear: both; margin: 1.25em 0 1.1875em; height: 0; } /* Helpful Typography Defaults */ em, i { font-style: italic; line-height: inherit; } strong, b { font-weight: bold; line-height: inherit; } small { font-size: 60%; line-height: inherit; } code { font-family: Consolas, "Liberation Mono", Courier, monospace; font-weight: bold; color: #417b06; } /* Lists */ ul, ol, dl { font-size: 1em; line-height: 1.6; margin-bottom: 1.25em; list-style-position: outside; font-family: inherit; } ul, ol { margin-left: 1.5em; } /* Unordered Lists */ ul li ul, ul li ol { margin-left: 1.25em; margin-bottom: 0; font-size: 1em; /* Override nested font-size change */ } ul.square li ul, ul.circle li ul, ul.disc li ul { list-style: inherit; } ul.square { list-style-type: square; } ul.circle { list-style-type: circle; } ul.disc { list-style-type: disc; } ul.no-bullet { list-style: none; } /* Ordered Lists */ ol li ul, ol li ol { margin-left: 1.25em; margin-bottom: 0; } /* Definition Lists */ dl dt { margin-bottom: 0.3125em; font-weight: bold; } dl dd { margin-bottom: 1.25em; } /* Abbreviations */ abbr, acronym { text-transform: uppercase; font-size: 90%; color: #555555; border-bottom: 1px dotted #dddddd; cursor: help; } abbr { text-transform: none; } /* Blockquotes */ blockquote { margin: 0 0 1.25em; padding: 0.5625em 1.25em 0 1.1875em; border-left: 1px solid #efefef; } blockquote cite { display: block; font-size: 0.8125em; color: #5e5e5e; } blockquote cite:before { content: "\2014 \0020"; } blockquote cite a, blockquote cite a:visited { color: #5e5e5e; } blockquote, blockquote p { line-height: 1.6; color: #777777; } /* Microformats */ .vcard { display: inline-block; margin: 0 0 1.25em 0; border: 1px solid #dddddd; padding: 0.625em 0.75em; } .vcard li { margin: 0; display: block; } .vcard .fn { font-weight: bold; font-size: 0.9375em; } .vevent .summary { font-weight: bold; } .vevent abbr { cursor: auto; text-decoration: none; font-weight: bold; border: none; padding: 0 0.0625em; } @media only screen and (min-width: 768px) { h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { line-height: 1.4; } h1 { font-size: 2.75em; } h2 { font-size: 2.3125em; } h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.6875em; } h4 { font-size: 1.4375em; } } /* Print styles. Inlined to avoid required HTTP connection: www.phpied.com/delay-loading-your-print-css/ Credit to Paul Irish and HTML5 Boilerplate (html5boilerplate.com) */ .print-only { display: none !important; } @media print { * { background: transparent !important; color: #000 !important; /* Black prints faster: h5bp.com/s */ box-shadow: none !important; text-shadow: none !important; } a, a:visited { text-decoration: underline; } a[href]:after { content: " (" attr(href) ")"; } abbr[title]:after { content: " (" attr(title) ")"; } .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } thead { display: table-header-group; /* h5bp.com/t */ } tr, img { page-break-inside: avoid; } img { max-width: 100% !important; } @page { margin: 0.5cm; } p, h2, h3, #toctitle, .sidebarblock > .content > .title { orphans: 3; widows: 3; } h2, h3, #toctitle, .sidebarblock > .content > .title { page-break-after: avoid; } .hide-on-print { display: none !important; } .print-only { display: block !important; } .hide-for-print { display: none !important; } .show-for-print { display: inherit !important; } } /* Tables */ table { background: white; margin-bottom: 1.25em; border: solid 1px #dddddd; } table thead, table tfoot { background: whitesmoke; font-weight: normal; } table thead tr th, table thead tr td, table tfoot tr th, table tfoot tr td { padding: 0.5em 0.625em 0.625em; font-size: inherit; color: #333333; text-align: left; } table tr th, table tr td { padding: 0.5625em 0.625em; font-size: inherit; color: #555555; } table tr.even, table tr.alt, table tr:nth-of-type(even) { background: #f9f9f9; } table thead tr th, table tfoot tr th, table tbody tr td, table tr td, table tfoot tr td { display: table-cell; line-height: 1.4; } .clearfix:before, .clearfix:after, .float-group:before, .float-group:after { content: " "; display: table; } .clearfix:after, .float-group:after { clear: both; } *:not(pre) > code { font-size: inherit; padding: 0; white-space: nowrap; background-color: inherit; border: 0 solid #dddddd; -webkit-border-radius: 0; border-radius: 0; text-shadow: none; } pre, pre > code { line-height: 1.4; color: black; font-family: monospace, serif; font-weight: normal; } kbd.keyseq { color: #888888; } kbd:not(.keyseq) { display: inline-block; color: #555555; font-size: 0.75em; line-height: 1.4; background-color: #F7F7F7; border: 1px solid #ccc; -webkit-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 2px white inset; box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 2px white inset; margin: -0.15em 0.15em 0 0.15em; padding: 0.2em 0.6em 0.2em 0.5em; vertical-align: middle; white-space: nowrap; } kbd kbd:first-child { margin-left: 0; } kbd kbd:last-child { margin-right: 0; } .menuseq, .menu { color: #3b3b3b; } #header, #content, #footnotes, #footer { width: 100%; margin-left: auto; margin-right: auto; margin-top: 0; margin-bottom: 0; max-width: 62.5em; *zoom: 1; position: relative; padding-left: 0.9375em; padding-right: 0.9375em; } #header:before, #header:after, #content:before, #content:after, #footnotes:before, #footnotes:after, #footer:before, #footer:after { content: " "; display: table; } #header:after, #content:after, #footnotes:after, #footer:after { clear: both; } #header { margin-bottom: 2.5em; } #header > h1 { color: #417b06; font-weight: bold; border-bottom: 1px dotted #cccccc; margin-bottom: -28px; padding-bottom: 32px; } #header span { color: #777777; } #header #revnumber { text-transform: capitalize; } #header br { display: none; } #header br + span { padding-left: 3px; } #header br + span:before { content: "\2013 \0020"; } #header br + span.author { padding-left: 0; } #header br + span.author:before { content: ", "; } #toc { border-bottom: 1px solid #cccccc; padding-bottom: 1.25em; } #toc > ul { margin-left: 0.25em; } #toc ul.sectlevel0 > li > a { font-style: italic; } #toc ul.sectlevel0 ul.sectlevel1 { margin-left: 0; margin-top: 0.5em; margin-bottom: 0.5em; } #toc ul { list-style-type: none; } #toctitle { color: #777777; } @media only screen and (min-width: 1280px) { body.toc2 { padding-left: 20em; } #toc.toc2 { position: fixed; width: 20em; left: 0; top: 0; border-right: 1px solid #cccccc; border-bottom: 0; z-index: 1000; padding: 1em; height: 100%; overflow: auto; } #toc.toc2 #toctitle { margin-top: 0; } #toc.toc2 > ul { font-size: .95em; } #toc.toc2 ul ul { margin-left: 0; padding-left: 1.25em; } #toc.toc2 ul.sectlevel0 ul.sectlevel1 { padding-left: 0; margin-top: 0.5em; margin-bottom: 0.5em; } body.toc2.toc-right { padding-left: 0; padding-right: 20em; } body.toc2.toc-right #toc.toc2 { border-right: 0; border-left: 1px solid #cccccc; left: auto; right: 0; } } #content #toc { border-style: solid; border-width: 1px; border-color: #d9d9d9; margin-bottom: 1.25em; padding: 1.25em; background: #f2f2f2; border-width: 0; -webkit-border-radius: 0; border-radius: 0; } #content #toc > :first-child { margin-top: 0; } #content #toc > :last-child { margin-bottom: 0; } #content #toc a { text-decoration: none; } #content #toctitle { font-weight: bold; font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; font-size: 1em; padding-left: 0.125em; } #footer { max-width: 100%; background-color: #272727; padding: 1.25em; } #footer-text { color: #bcbcbc; line-height: 1.44; } .sect1 { padding-bottom: 1.25em; } .sect1 + .sect1 { border-top: 1px solid #cccccc; } #content h1 > a.anchor, h2 > a.anchor, h3 > a.anchor, #toctitle > a.anchor, .sidebarblock > .content > .title > a.anchor, h4 > a.anchor, h5 > a.anchor, h6 > a.anchor { position: absolute; width: 1em; margin-left: -1em; display: block; text-decoration: none; visibility: hidden; text-align: center; font-weight: normal; } #content h1 > a.anchor:before, h2 > a.anchor:before, h3 > a.anchor:before, #toctitle > a.anchor:before, .sidebarblock > .content > .title > a.anchor:before, h4 > a.anchor:before, h5 > a.anchor:before, h6 > a.anchor:before { content: '\00A7'; font-size: .85em; vertical-align: text-top; display: block; margin-top: 0.05em; } #content h1:hover > a.anchor, #content h1 > a.anchor:hover, h2:hover > a.anchor, h2 > a.anchor:hover, h3:hover > a.anchor, #toctitle:hover > a.anchor, .sidebarblock > .content > .title:hover > a.anchor, h3 > a.anchor:hover, #toctitle > a.anchor:hover, .sidebarblock > .content > .title > a.anchor:hover, h4:hover > a.anchor, h4 > a.anchor:hover, h5:hover > a.anchor, h5 > a.anchor:hover, h6:hover > a.anchor, h6 > a.anchor:hover { visibility: visible; } #content h1 > a.link, h2 > a.link, h3 > a.link, #toctitle > a.link, .sidebarblock > .content > .title > a.link, h4 > a.link, h5 > a.link, h6 > a.link { color: #333333; text-decoration: none; } #content h1 > a.link:hover, h2 > a.link:hover, h3 > a.link:hover, #toctitle > a.link:hover, .sidebarblock > .content > .title > a.link:hover, h4 > a.link:hover, h5 > a.link:hover, h6 > a.link:hover { color: #262626; } .imageblock, .literalblock, .listingblock, .verseblock, .videoblock { margin-bottom: 1.25em; } .admonitionblock td.content > .title, .exampleblock > .title, .imageblock > .title, .videoblock > .title, .listingblock > .title, .literalblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, .sidebarblock > .title, .tableblock > .title, .verseblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { text-align: left; font-weight: bold; } .tableblock > caption { text-align: left; font-weight: bold; white-space: nowrap; overflow: visible; max-width: 0; } table.tableblock #preamble > .sectionbody > .paragraph:first-of-type p { font-size: inherit; } .admonitionblock > table { border: 0; background: none; width: 100%; } .admonitionblock > table td.icon { text-align: center; width: 80px; } .admonitionblock > table td.icon img { max-width: none; } .admonitionblock > table td.icon .title { font-weight: bold; text-transform: uppercase; } .admonitionblock > table td.content { padding-left: 1.125em; padding-right: 1.25em; border-left: 1px dotted #cccccc; color: #777777; } .admonitionblock > table td.content > :last-child > :last-child { margin-bottom: 0; } .exampleblock > .content { border-style: solid; border-width: 1px; border-color: #e6e6e6; margin-bottom: 1.25em; padding: 1.25em; background: white; -webkit-border-radius: 0; border-radius: 0; } .exampleblock > .content > :first-child { margin-top: 0; } .exampleblock > .content > :last-child { margin-bottom: 0; } .exampleblock > .content h1, .exampleblock > .content h2, .exampleblock > .content h3, .exampleblock > .content #toctitle, .sidebarblock.exampleblock > .content > .title, .exampleblock > .content h4, .exampleblock > .content h5, .exampleblock > .content h6, .exampleblock > .content p { color: #555555; } .exampleblock > .content h1, .exampleblock > .content h2, .exampleblock > .content h3, .exampleblock > .content #toctitle, .sidebarblock.exampleblock > .content > .title, .exampleblock > .content h4, .exampleblock > .content h5, .exampleblock > .content h6 { line-height: 1; margin-bottom: 0.625em; } .exampleblock > .content h1.subheader, .exampleblock > .content h2.subheader, .exampleblock > .content h3.subheader, .exampleblock > .content .subheader#toctitle, .sidebarblock.exampleblock > .content > .subheader.title, .exampleblock > .content h4.subheader, .exampleblock > .content h5.subheader, .exampleblock > .content h6.subheader { line-height: 1.4; } .exampleblock.result > .content { -webkit-box-shadow: 0 1px 8px #d9d9d9; box-shadow: 0 1px 8px #d9d9d9; } .sidebarblock { border-style: solid; border-width: 1px; border-color: #d9d9d9; margin-bottom: 1.25em; padding: 1.25em; background: #f2f2f2; -webkit-border-radius: 0; border-radius: 0; } .sidebarblock > :first-child { margin-top: 0; } .sidebarblock > :last-child { margin-bottom: 0; } .sidebarblock h1, .sidebarblock h2, .sidebarblock h3, .sidebarblock #toctitle, .sidebarblock > .content > .title, .sidebarblock h4, .sidebarblock h5, .sidebarblock h6, .sidebarblock p { color: #555555; } .sidebarblock h1, .sidebarblock h2, .sidebarblock h3, .sidebarblock #toctitle, .sidebarblock > .content > .title, .sidebarblock h4, .sidebarblock h5, .sidebarblock h6 { line-height: 1; margin-bottom: 0.625em; } .sidebarblock h1.subheader, .sidebarblock h2.subheader, .sidebarblock h3.subheader, .sidebarblock .subheader#toctitle, .sidebarblock > .content > .subheader.title, .sidebarblock h4.subheader, .sidebarblock h5.subheader, .sidebarblock h6.subheader { line-height: 1.4; } .sidebarblock > .content > .title { color: #777777; margin-top: 0; line-height: 1.6; } .exampleblock > .content > :last-child > :last-child, .exampleblock > .content .olist > ol > li:last-child > :last-child, .exampleblock > .content .ulist > ul > li:last-child > :last-child, .exampleblock > .content .qlist > ol > li:last-child > :last-child, .sidebarblock > .content > :last-child > :last-child, .sidebarblock > .content .olist > ol > li:last-child > :last-child, .sidebarblock > .content .ulist > ul > li:last-child > :last-child, .sidebarblock > .content .qlist > ol > li:last-child > :last-child { margin-bottom: 0; } .literalblock > .content pre, .listingblock > .content pre { background: #efefef; border-width: 1px; border-style: solid; border-color: #cccccc; -webkit-border-radius: 0; border-radius: 0; padding: 0.75em 0.75em 0.625em 0.75em; word-wrap: break-word; } .literalblock > .content pre.nowrap, .listingblock > .content pre.nowrap { overflow-x: auto; white-space: pre; word-wrap: normal; } .literalblock > .content pre > code, .listingblock > .content pre > code { display: block; } @media only screen { .literalblock > .content pre, .listingblock > .content pre { font-size: 0.72em; } } @media only screen and (min-width: 768px) { .literalblock > .content pre, .listingblock > .content pre { font-size: 0.81em; } } @media only screen and (min-width: 1280px) { .literalblock > .content pre, .listingblock > .content pre { font-size: 0.9em; } } .listingblock > .content { position: relative; } .listingblock:hover code[class*=" language-"]:before { text-transform: uppercase; font-size: 0.9em; color: #999; position: absolute; top: 0.375em; right: 0.375em; } .listingblock:hover code.asciidoc:before { content: "asciidoc"; } .listingblock:hover code.clojure:before { content: "clojure"; } .listingblock:hover code.css:before { content: "css"; } .listingblock:hover code.groovy:before { content: "groovy"; } .listingblock:hover code.html:before { content: "html"; } .listingblock:hover code.java:before { content: "java"; } .listingblock:hover code.javascript:before { content: "javascript"; } .listingblock:hover code.python:before { content: "python"; } .listingblock:hover code.ruby:before { content: "ruby"; } .listingblock:hover code.scss:before { content: "scss"; } .listingblock:hover code.xml:before { content: "xml"; } .listingblock:hover code.yaml:before { content: "yaml"; } .listingblock.terminal pre .command:before { content: attr(data-prompt); padding-right: 0.5em; color: #999; } .listingblock.terminal pre .command:not([data-prompt]):before { content: '$'; } table.pyhltable { border: 0; margin-bottom: 0; } table.pyhltable td { vertical-align: top; padding-top: 0; padding-bottom: 0; } table.pyhltable td.code { padding-left: .75em; padding-right: 0; } .highlight.pygments .lineno, table.pyhltable td:not(.code) { color: #999; padding-left: 0; padding-right: .5em; border-right: 1px solid #cccccc; } .highlight.pygments .lineno { display: inline-block; margin-right: .25em; } table.pyhltable .linenodiv { background-color: transparent !important; padding-right: 0 !important; } .quoteblock { margin: 0 0 1.25em; padding: 0.5625em 1.25em 0 1.1875em; border-left: 1px solid #efefef; } .quoteblock blockquote { margin: 0 0 1.25em 0; padding: 0 0 0.5625em 0; border: 0; } .quoteblock blockquote > .paragraph:last-child p { margin-bottom: 0; } .quoteblock .attribution { margin-top: -.25em; padding-bottom: 0.5625em; font-size: 0.8125em; color: #5e5e5e; } .quoteblock .attribution br { display: none; } .quoteblock .attribution cite { display: block; margin-bottom: 0.625em; } table thead th, table tfoot th { font-weight: normal; } table.tableblock.grid-all { border-collapse: separate; border-spacing: 1px; -webkit-border-radius: 0; border-radius: 0; border-top: 1px solid #dddddd; border-bottom: 1px solid #dddddd; } table.tableblock.frame-topbot, table.tableblock.frame-none { border-left: 0; border-right: 0; } table.tableblock.frame-sides, table.tableblock.frame-none { border-top: 0; border-bottom: 0; } table.tableblock td .paragraph:last-child p, table.tableblock td > p:last-child { margin-bottom: 0; } th.tableblock.halign-left, td.tableblock.halign-left { text-align: left; } th.tableblock.halign-right, td.tableblock.halign-right { text-align: right; } th.tableblock.halign-center, td.tableblock.halign-center { text-align: center; } th.tableblock.valign-top, td.tableblock.valign-top { vertical-align: top; } th.tableblock.valign-bottom, td.tableblock.valign-bottom { vertical-align: bottom; } th.tableblock.valign-middle, td.tableblock.valign-middle { vertical-align: middle; } p.tableblock.header { color: #333333; font-weight: normal; } td > div.verse { white-space: pre; } ol { margin-left: 1.75em; } ul li ol { margin-left: 1.5em; } dl dd { margin-left: 1.125em; } dl dd:last-child, dl dd:last-child > :last-child { margin-bottom: 0; } ol > li p, ul > li p, ul dd, ol dd, .olist .olist, .ulist .ulist, .ulist .olist, .olist .ulist { margin-bottom: 0.625em; } ul.unstyled, ol.unnumbered, ul.checklist, ul.none { list-style-type: none; } ul.unstyled, ol.unnumbered, ul.checklist { margin-left: 0.625em; } ul.checklist li > p:first-child > i[class^="icon-check"]:first-child, ul.checklist li > p:first-child > input[type="checkbox"]:first-child { margin-right: 0.25em; } ul.checklist li > p:first-child > input[type="checkbox"]:first-child { position: relative; top: 1px; } ul.inline { margin: 0 auto 0.625em auto; margin-left: -1.375em; margin-right: 0; padding: 0; list-style: none; overflow: hidden; } ul.inline > li { list-style: none; float: left; margin-left: 1.375em; display: block; } ul.inline > li > * { display: block; } .unstyled dl dt { font-weight: normal; font-style: normal; } ol.arabic { list-style-type: decimal; } ol.decimal { list-style-type: decimal-leading-zero; } ol.loweralpha { list-style-type: lower-alpha; } ol.upperalpha { list-style-type: upper-alpha; } ol.lowerroman { list-style-type: lower-roman; } ol.upperroman { list-style-type: upper-roman; } ol.lowergreek { list-style-type: lower-greek; } .hdlist > table, .colist > table { border: 0; background: none; } .hdlist > table > tbody > tr, .colist > table > tbody > tr { background: none; } td.hdlist1 { padding-right: .8em; font-weight: bold; } td.hdlist1, td.hdlist2 { vertical-align: top; } .literalblock + .colist, .listingblock + .colist { margin-top: -0.5em; } .colist > table tr > td:first-of-type { padding: 0 .8em; line-height: 1; } .colist > table tr > td:last-of-type { padding: 0.25em 0; } .qanda > ol > li > p > em:only-child { color: #cde62c; } .thumb, .th { line-height: 0; display: inline-block; border: solid 4px white; -webkit-box-shadow: 0 0 0 1px #dddddd; box-shadow: 0 0 0 1px #dddddd; } .imageblock.left, .imageblock[style*="float: left"] { margin: 0.25em 0.625em 1.25em 0; } .imageblock.right, .imageblock[style*="float: right"] { margin: 0.25em 0 1.25em 0.625em; } .imageblock > .title { margin-bottom: 0; } .imageblock.thumb, .imageblock.th { border-width: 6px; } .imageblock.thumb > .title, .imageblock.th > .title { padding: 0 0.125em; } .image.left, .image.right { margin-top: 0.25em; margin-bottom: 0.25em; display: inline-block; line-height: 0; } .image.left { margin-right: 0.625em; } .image.right { margin-left: 0.625em; } a.image { text-decoration: none; } span.footnote, span.footnoteref { vertical-align: super; font-size: 0.875em; } span.footnote a, span.footnoteref a { text-decoration: none; } #footnotes { padding-top: 0.75em; padding-bottom: 0.75em; margin-bottom: 0.625em; } #footnotes hr { width: 20%; min-width: 6.25em; margin: -.25em 0 .75em 0; border-width: 1px 0 0 0; } #footnotes .footnote { padding: 0 0.375em; line-height: 1.3; font-size: 0.875em; margin-left: 1.2em; text-indent: -1.2em; margin-bottom: .2em; } #footnotes .footnote a:first-of-type { font-weight: bold; text-decoration: none; } #footnotes .footnote:last-of-type { margin-bottom: 0; } #content #footnotes { margin-top: -0.625em; margin-bottom: 0; padding: 0.75em 0; } .gist .file-data > table { border: none; background: #fff; width: 100%; margin-bottom: 0; } .gist .file-data > table td.line-data { width: 99%; } div.unbreakable { page-break-inside: avoid; } .big { font-size: larger; } .small { font-size: smaller; } .underline { text-decoration: underline; } .overline { text-decoration: overline; } .line-through { text-decoration: line-through; } .aqua { color: #00bfbf; } .aqua-background { background-color: #00fafa; } .black { color: black; } .black-background { background-color: black; } .blue { color: #0000bf; } .blue-background { background-color: #0000fa; } .fuchsia { color: #bf00bf; } .fuchsia-background { background-color: #fa00fa; } .gray { color: #606060; } .gray-background { background-color: #7d7d7d; } .green { color: #006000; } .green-background { background-color: #007d00; } .lime { color: #00bf00; } .lime-background { background-color: #00fa00; } .maroon { color: #600000; } .maroon-background { background-color: #7d0000; } .navy { color: #000060; } .navy-background { background-color: #00007d; } .olive { color: #606000; } .olive-background { background-color: #7d7d00; } .purple { color: #600060; } .purple-background { background-color: #7d007d; } .red { color: #bf0000; } .red-background { background-color: #fa0000; } .silver { color: #909090; } .silver-background { background-color: #bcbcbc; } .teal { color: #006060; } .teal-background { background-color: #007d7d; } .white { color: #bfbfbf; } .white-background { background-color: #fafafa; } .yellow { color: #bfbf00; } .yellow-background { background-color: #fafa00; } span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; } .admonitionblock td.icon [class^="icon-"]:before { font-size: 2.5em; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); cursor: default; } .admonitionblock td.icon .icon-note:before { content: "\f05a"; color: #d2e943; color: #b1c918; } .admonitionblock td.icon .icon-tip:before { content: "\f0eb"; text-shadow: 1px 1px 2px rgba(155, 155, 0, 0.8); color: #111; } .admonitionblock td.icon .icon-warning:before { content: "\f071"; color: #bf6900; } .admonitionblock td.icon .icon-caution:before { content: "\f06d"; color: #bf3400; } .admonitionblock td.icon .icon-important:before { content: "\f06a"; color: #bf0000; } .conum { display: inline-block; color: white !important; background-color: #555555; -webkit-border-radius: 100px; border-radius: 100px; text-align: center; width: 20px; height: 20px; font-size: 12px; font-weight: bold; line-height: 20px; font-family: Arial, sans-serif; font-style: normal; position: relative; top: -2px; letter-spacing: -1px; } .conum * { color: white !important; } .conum + b { display: none; } .conum:after { content: attr(data-value); } .conum:not([data-value]):empty { display: none; } #header > h1 { border-bottom-style: solid; } #toctitle { color: #333333; } .listingblock > .content > pre, .literalblock > .content > pre { background: -moz-linear-gradient(top, white 0%, #f4f4f4 100%); background: -webkit-linear-gradient(top, white 0%, #f4f4f4 100%); background: linear-gradient(to bottom, #ffffff 0%, #f4f4f4 100%); -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15); box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15); } .sidebarblock { background: none; border: none; -webkit-box-shadow: 0 0 5px rgba(118, 137, 4, 0.5); box-shadow: 0 0 5px rgba(118, 137, 4, 0.5); } .sidebarblock > .content > .title { color: #181818; } kraft-1.1/manual/locale/000077500000000000000000000000001450127457600152115ustar00rootroot00000000000000kraft-1.1/manual/locale/attributes-de.adoc000066400000000000000000000013161450127457600206160ustar00rootroot00000000000000// German translation, courtesy of Florian Wilhelm :appendix-caption: Anhang :appendix-refsig: {appendix-caption} :caution-caption: Achtung :chapter-label: Kapitel :chapter-refsig: {chapter-label} :example-caption: Beispiel :figure-caption: Abbildung :important-caption: Wichtig :last-update-label: Zuletzt aktualisiert ifdef::listing-caption[:listing-caption: Listing] ifdef::manname-title[:manname-title: Bezeichnung] :note-caption: Anmerkung :part-label: Teil :part-refsig: {part-label} ifdef::preface-title[:preface-title: Vorwort] :section-refsig: Abschnitt :table-caption: Tabelle :tip-caption: Hinweis :toc-title: Inhaltsverzeichnis :untitled-label: Ohne Titel :version-label: Version :warning-caption: Warnung kraft-1.1/manual/locale/attributes-en.adoc000066400000000000000000000013161450127457600206300ustar00rootroot00000000000000// English translation, for reference only; matches the built-in behavior of core :appendix-caption: Appendix :appendix-refsig: {appendix-caption} :caution-caption: Caution :chapter-label: Chapter :chapter-refsig: {chapter-label} :example-caption: Example :figure-caption: Figure :important-caption: Important :last-update-label: Last updated ifdef::listing-caption[:listing-caption: Listing] ifdef::manname-title[:manname-title: Name] :note-caption: Note :part-label: Part :part-refsig: {part-label} ifdef::preface-title[:preface-title: Preface] :section-refsig: Section :table-caption: Table :tip-caption: Tip :toc-title: Table of Contents :untitled-label: Untitled :version-label: Version :warning-caption: Warning kraft-1.1/manual/locale/attributes-nl.adoc000066400000000000000000000013571450127457600206440ustar00rootroot00000000000000// Dutch translation, courtesy of Roel Van Steenberghe :appendix-caption: Bijlage :appendix-refsig: {appendix-caption} :caution-caption: Opgelet :chapter-signifier: Hoofdstuk :chapter-refsig: {chapter-signifier} :example-caption: Voorbeeld :figure-caption: Figuur :important-caption: Belangrijk :last-update-label: Laatste aanpassing ifdef::listing-caption[:listing-caption: Lijst] ifdef::manname-title[:manname-title: Naam] :note-caption: Noot :part-signifier: Deel :part-refsig: {part-signifier} ifdef::preface-title[:preface-title: Inleiding] :section-refsig: Paragraaf :table-caption: Tabel :tip-caption: Tip :toc-title: Inhoudsopgave :untitled-label: Naamloos :version-label: Versie :warning-caption: Waarschuwing kraft-1.1/manual/locale/attributes.adoc000066400000000000000000000013751450127457600202350ustar00rootroot00000000000000// This directory provides translations for all built-in attributes in Asciidoctor that emit translatable strings. // See http://asciidoctor.org/docs/user-manual/#customizing-labels to learn how to apply this file. // // If you're introducing a new translation, create a file named attributes-.adoc, where is the IANA subtag for the language. // Next, assign a translation for each attribute, using attributes-en.adoc as a reference. // // IMPORTANT: Do not include any blank lines in the transation file. // // NOTE: Please wrap the listing-caption and preface-title entries in a preprocessor conditional directive. // These attributes should only be updated if set explicitly by the user. ifdef::lang[include::attributes-{lang}.adoc[]] kraft-1.1/manual/makeman.sh000077500000000000000000000032101450127457600157160ustar00rootroot00000000000000#!/bin/bash # set -euxo pipefail # FIXME: Check if the tools ascidoctor and po4a-translate are installed # FIXME: Be compatible with other ascii doc generators # ===================================================================== showhelp() { echo "Usage: $0 " >&2 echo echo " Creates the Kraft manual and its translations." echo " asciidoctor and po4trans need to be installed." echo "" echo " To read the source from elsewhere, the script" echo " takes a source directory as argument" echo "" echo " Output happens to the current directory." exit 1 } # ===================================================================== srcdir="${1:-.}" srcfile="${srcdir}/kraft.adoc" version="1.0" outfile="kraft-en.html" if [ -n "$1" ] && [ "$1" == "-h" ]; then showhelp fi echo "Building $srcfile in ${srcdir}" outdir=`pwd` pushd "${srcdir}" lang=en asciidocargs="-D ${outdir} -a path=${srcdir} -a VERSION=${version} -a stylesheet=kraftmanual.css" # english master doc asciidoctor ${asciidocargs} -a lang=${lang} -o ${outfile} ${srcfile} echo "built ${outfile}" # build the internationalized versions languages="de nl" for lang in ${languages} do transsrc="${srcdir}/po/kraft-${lang}.po" if [ -f "${transsrc}" ]; then po4a-translate -f asciidoc -M utf-8 -m ${srcfile} -p ${transsrc} -k 0 -l kraft-${lang}.adoc outfile="kraft-${lang}.html" asciidoctor ${asciidocargs} -a lang=${lang} -o ${outfile} kraft-${lang}.adoc rm kraft-${lang}.adoc echo "built ${transsrc} to ${outfile}" else echo "File ${transsrc} does not exist!" fi done popd kraft-1.1/manual/po/000077500000000000000000000000001450127457600143705ustar00rootroot00000000000000kraft-1.1/manual/po/kraft-de.po000066400000000000000000002217751450127457600164430ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE # Copyright (C) YEAR Free Software Foundation, Inc. # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: 2023-09-12 14:32+0200\n" "PO-Revision-Date: 2021-10-13 22:21+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: de_DE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Language: de_DE\n" "X-Source-Language: en_US\n" "X-Generator: Poedit 2.3\n" #. type: Title = #: kraft.adoc:1 #, no-wrap msgid "The Kraft Handbook" msgstr "Das Kraft Handbuch" #. type: Plain text #: kraft.adoc:3 #, fuzzy msgid "Ronald Stroethoff, Klaas Freitag" msgstr "Roland Stroethoff, Klaas Freitag" #. type: Title == #: kraft.adoc:16 #, no-wrap msgid "Introduction" msgstr "Einführung" #. type: Plain text #: kraft.adoc:19 #, fuzzy msgid "" "Kraft is a Qt and KDE application to organize office documents like quotes " "and invoices in a small business. It eases the creation of documents and " "helps with repeating tasks." msgstr "" "Kraft ist ein Qt- und KDE-Programm zum Organisieren von Bürodokumenten wie " "Angeboten und Rechnungen in kleinen Unternehmen. Es erleichtert die " "Erstellung der Dokument und vereinfacht wiederkehrende Aufgaben." #. type: Plain text #: kraft.adoc:21 #, fuzzy msgid "" "Using Kraft, there is no need for fiddling with a text processor any more. " "Documents are created by a few clicks, edited, generated and archived " "automatically. Kraft generates high quality PDF output for printing, mailing " "and archiving." msgstr "" "Mit Kraft wird kein Textbearbeitungsprogramm mehr benötigt. Rechnungs- und " "Angebotsdokumente werden mit ein paar Klicks erstellt und automatisch " "abgelegt. Kraft generiert hochqualitative PDF Dokumente für Druck, EMail und " "Archivierung." #. type: Labeled list #: kraft.adoc:22 #, no-wrap msgid "Feature Overview" msgstr "Funktionen" #. type: Plain text #: kraft.adoc:25 #, fuzzy msgid "Simple creation of offers, invoices and similar documents." msgstr "" "Unterstütztes Erstellen von Angeboten, Rechnungen und ähnlichen Dokumenten." #. type: Plain text #: kraft.adoc:26 #, fuzzy msgid "" "Customer management, deeply integrated with the mature KDE KAddressbook." msgstr "" "Kundenverwaltung, durch die Verwendung von KAdressbuch tief in die KDE " "Infrastruktur integriert." #. type: Plain text #: kraft.adoc:27 #, fuzzy msgid "Maintenance of document relations, ie. Partial invoices vs. invoices." msgstr "" "Verwaltung der Dokument-Beziehungen, zum Beispiel Teilrechnungen und " "Rechnungen." #. type: Plain text #: kraft.adoc:28 msgid "Templates for document header- and footertexts and for document items." msgstr "Vorlagen für Dokument-Kopf- und Fusstexte sowie Dokumentposten." #. type: Plain text #: kraft.adoc:29 #, fuzzy msgid "Pre calculation of item prices." msgstr "Kalkulation von einzelnen Posten." #. type: Plain text #: kraft.adoc:30 msgid "Material management." msgstr "Materialverwaltung." #. type: Plain text #: kraft.adoc:31 msgid "Configurable document creation in PDF format for print and email." msgstr "" "Konfigurierbare Dokument-Erstellung im PDF Format zum Druck und Versenden " "per Email." #. type: Plain text #: kraft.adoc:33 msgid "" "The code of Kraft is open source and is released under the https://en." "wikipedia.org/wiki/GNU_General_Public_License[GNU General Public License]." msgstr "" "Der Quelltext zu Kraft ist open source and wird unter der Lizenz https://en." "wikipedia.org/wiki/GNU_General_Public_License[GNU General Public License] " "veröffentlicht." #. type: Plain text #: kraft.adoc:38 #, fuzzy, no-wrap msgid "" "Kraft is driven by community of users, coders, artists and others by voluntary work. +\n" "Also this manual needs contributions! +\n" " +\n" " Learn more on https://github.com/dragotin/kraft/blob/master/manual/Readme.md[how to contribute]!\n" msgstr "" "Kraft wird durch eine Gemeinschaft von Benutzern, Entwicklern und anderen vorangetrieben. +\n" "Dieses Benutzerhandbuch benötigt Ihre Hilfe zur Verbesserung. +\n" " +\n" "Lernen Sie mehr auf https://github.com/dragotin/kraft/blob/master/manual/Readme.md[how to contribute]!\n" #. type: Title == #: kraft.adoc:40 #, no-wrap msgid "First Use and Basic Configuration" msgstr "Erster Start und Grundkonfiguration" #. type: Plain text #: kraft.adoc:43 #, fuzzy msgid "" "When Kraft is started for the first time, it automatically enters the " "initial setup process." msgstr "" "Wenn Kraft das erste Mal gestartet wird, wird automatisch mit der " "Einrichtung begonnen." #. type: Plain text #: kraft.adoc:45 #, fuzzy msgid "" "During the initial setup you are asked to select a database to use and give " "the name and address of your company." msgstr "" "Während des initialen Setup wird der Datenbank-Typ und die Adresse der Firma " "abgefragt." #. type: Plain text #: kraft.adoc:47 #, fuzzy msgid "" "You can fill in your company address (that appears on the printed documents) " "in two ways: in the setup procedure use the first tab *Select from " "Addressbook* for to select your on address in KAddressBook (if you have " "filled your own address in KaddressBook) or use the second tab *Manual " "entry* for to fill in the information of the address from your company " "manually. This step is necessary for the correct generation of your " "documents as the address is automatically used in the document generation " "step." msgstr "" "Die Adresse der eigenen Firma, die automatisch auf dem Ausgabedokument " "erscheint, kann auf zwei Arten eingegeben werden: In der Prozedur nach dem " "ersten Start im entsprechenden Tab, oder später über den Einstellungsdialog. " "Die Adresse kann entweder aus dem Adressbuch gewählt werden oder per Hand " "eingegeben werden. Dieser Schritt ist für die fehlerfreie Erstellung der " "Dokumente nötig." #. type: Plain text #: kraft.adoc:49 #, fuzzy msgid "image:company_adress1.png[Company adress,float=\"right\"]" msgstr "image:company_adress1.png[Firmenadresse,float=\"right\"]" #. type: Plain text #: kraft.adoc:52 #, fuzzy msgid "" "After the initial setup, select menu:Preferences[Settings]. That allows to " "prepare Kraft correctly so it can be used in a proper way." msgstr "" "Nach dem initialen Setup kann Kraft über das Menü Preferences[Settings] " "konfiguriert werden. Das erlaubt, Kraft für die eigenen Bedürfnisse " "anzupassen." #. type: Plain text #: kraft.adoc:54 #, fuzzy msgid "In the Preferences dialog we have the tabs:" msgstr "Im Einstellungsfenster befinden sich die Tabs:" #. type: Plain text #: kraft.adoc:61 #, no-wrap msgid "" " *Document Defaults\n" " *Taxes\n" " *Documunt Types\n" " *Wages\n" " *Units\n" " *Own identity\n" msgstr "" " *Dokument Voreinstellungen\n" " *Steuern\n" " *Dokumenttypen\n" " *Stundensätze\n" " *Einheiten\n" " *die eigene Identität\n" #. type: Plain text #: kraft.adoc:63 #, fuzzy msgid "" "Each of the tabs allows to enter useful values for the specific use case." msgstr "" "Jeder der Tabs erlaub es, sinnvolle Werte für die spezielle Anforderung " "einzugeben." #. type: Title === #: kraft.adoc:64 #, no-wrap msgid "Document Types" msgstr "Dokumenttypen" #. type: Plain text #: kraft.adoc:67 msgid "At the first use you find a list of different document types, such as:" msgstr "Beim ersten Start finden sich folgende Dokumenttypen:" #. type: Plain text #: kraft.adoc:69 msgid "Acceptance of order" msgstr "Auftragsbestätigung" #. type: Plain text #: kraft.adoc:70 msgid "Delivery receipt" msgstr "Lieferschein" #. type: Plain text #: kraft.adoc:71 msgid "Invoice" msgstr "Rechnung" #. type: Plain text #: kraft.adoc:72 msgid "Offer" msgstr "Angebot" #. type: Plain text #: kraft.adoc:74 #, fuzzy msgid "image:documentype.png[Document type,float=\"right\"]" msgstr "image:documentype.png[Dokumenttyp,float=\"right\"]" #. type: Plain text #: kraft.adoc:77 msgid "" "Translate this types to your own language. You can also add new ones and " "remove document types you wont use." msgstr "" "Übersetze diese Typen in die eigene Sprache. Du kannst ebenso neue " "hinzufügen und Einträge entfernen, die Du nicht benutzen wirst." #. type: Title ==== #: kraft.adoc:78 #, no-wrap msgid "Numbercycles" msgstr "Nummernkreise" #. type: Plain text #: kraft.adoc:82 #, fuzzy msgid "" "image:numbercycles.png[Numbercycles,float=\"right\"] Each document has to " "have an unique identifier that identifies the document. There must not be " "two documents in Kraft with the same identifier." msgstr "" "image:numbercycles.png[Numbercycles,float=\"right\"] Jedes Dokument muss " "eine eindeutige Dokumentnummer haben, das es identifiziert. Es dürfen keine " "zwei Dokumente die selbe Dokumentnummer haben." #. type: Plain text #: kraft.adoc:85 #, fuzzy msgid "" "The format of the identifier is configuratable in Kraft. For that, Kraft has " "a concept of so called number cycles. Number cycles are used to define the " "form of the *document number* which is printed on every document." msgstr "" "Das Format der Dokumentnummer ist einstellbar in Kraft. Dazu hat Kraft die " "sogenannten Nummernkreise. Mit ihnen wird das Format der Dokumentnummern " "definiert, die auf jedes Dokument gedruckt werden." #. type: Plain text #: kraft.adoc:89 #, fuzzy msgid "" "All documents of a certain type have identifiers taken out of one number " "cycle. Each document type has a number cycle assigned. Different document " "types can use the same number cycle to generate ids from. That way, for " "example the document types Invoice and Final Invoice can use numbers from " "the same number cycle, even thought they are different document types in " "Kraft. Number cycles are identified by their name. User can create new " "number cycles and edit them clicking on the button btn:[Edit Number " "Cycles...]" msgstr "" "Alle Dokumente eines bestimmten Dokument-Typs entnehmen die Nummern einem " "Nummernkreis. Jeder Dokument-Typ hat einen Nummernkreis zugewiesen. " "Verschiedene Dokument-Typen können den selben Nummernkreis haben, von dem " "Dokumentnummern erzeugt werden. Auf diese Weise können zum Beispiel die " "Dokumenttypen Rechnung und Teilrechnung Nummern vom selben Nummernkreis " "generieren, obwohl Kraft sie als verschiedene Dokumenttypen kennt. " "Nummernkreise werden anhand ihres Namen identifiziert. Benutzer können neue " "Nummernkreise anlegen und sie durch einen klick auf btn:[Nummernkreise " "bearbeiten...] bearbeiten." #. type: Plain text #: kraft.adoc:91 #, fuzzy msgid "" "The format of the document numbers are defined by a template that can " "contain normal, fixed characters and also some variables that are replaced " "by the respective values when the document is created." msgstr "" "Das Format der Nummernkreise wird durch eine Vorlage defininiert, die aus " "festen Zeichen wie auch einigen Variablen bestehen, die durch Werte ersetzt " "werden, wenn das Dokument erzeugt wird." #. type: Plain text #: kraft.adoc:94 #, fuzzy msgid "" "Each identifier needs to be unique, and thus has to contain a counter. Kraft " "supports two types of counter: One (variable `%i`) is incremented globally " "for every new document. The other (variable `%n`) is reset every day and " "starts at 1 again on every new day. In addition to the counter, more " "information can be added to the template form an useful number. Examples are " "a constant text or parts of the date." msgstr "" "Kraft unterstützt Zähler, die automatisch für jedes neue Dokument eines " "bestimmten Dokumenttypes erhöht werden. Zusätzlich zu dem Zähler können " "weitere Informationen hinzugefügt werden um eine nützliche Dokumentnummer zu " "erzeugen, so wie konstanten Text oder Teile des Datums." #. type: Plain text #: kraft.adoc:96 #, fuzzy msgid "" "The default numbercycle delivered with Kraft contains the year, the month " "and a serialnumber. That way you can compare offers or orders from last year " "with this year or the month April of last year with the month April of this " "year and get on this way an impression from the results of your business." msgstr "" "Der Standard-Nummernkreis, mit dem Kraft ausgeliefert wird, besteht aus dem " "Jahr, dem Monat und einer Seriennummer. Auf diese Art können die Dokumente " "anhand des Jahres verglichen werden, um leicht einen Eindruck über die " "Resultate des Unternehmens zu bekommen." #. type: Plain text #: kraft.adoc:98 msgid "See the following table for available variables which can be used:" msgstr "Folgende Variablen stehen zur Verfügung:" #. type: Table #: kraft.adoc:115 #, fuzzy, no-wrap msgid "" "| `%y` or `%yyyy` | the year of the document date.\n" "| `%yy` | the year of the document (two digits).\n" "| `%w` | the week number of the document date.\n" "| `%ww` | the week number of the document date with leading zero.\n" "| `%d` | the day number of the document date.\n" "| `%dd` | the day number of the document date with leading zero.\n" "| `%m` or `%M` | the month number of the document date.\n" "| `%MM` | the month number with leading zero.\n" "| `%c` | the customer id from kaddressbook\n" "| `%type` | the localised doc type (offer, invoice etc.)\n" "| `%uid` | the contact id of the client.\n" "| `%i` .. `%iiiiii`| the unique counter\n" "| `%n` .. `%nnnnnn`| the unique day counter (combine with date)\n" "\n" msgstr "" "| `%y` or `%yyyy` | das Jahr im Datum des Dokuments.\n" "| `%yy` | das Jahr im Datum des Dokuments (zwei Stellen).\n" "| `%w` | die Wochennummer im Datum des Dokuments.\n" "| `%ww` | die Wochennummer im Datum des Dokuments mit führender Null .\n" "| `%d` | der Tag im Datum des Dokuments.\n" "| `%dd` | der Tag im Datum des Dokuments mit führender Null.\n" "| `%m` or `%M` | der Monat als Nummer im Datum des Dokuments.\n" "| `%MM` | der Monat als Nummer im Datum des Dokuments mit führender Null.\n" "| `%c` | die Kund*innen-ID aus kaddressbook\n" "| `%i` | the unique counter *(mandatory)*\n" "| `%type` | der Dokumententyp (Angebot, Rechnung usw.)\n" "| `%uid` | Die Kontakt-ID der Kundin / des Kunden.\n" "| `%i` .. `%iiiiii`| ein eindeutiger Zähler, der mit jedem Dokument um eins erhöht wird.\n" "| `%n` .. `%nnnnnn`| eindeutiger Tageszähler, der jeden Tag auf eins zurückgesetzt wird (Kombination mit dem Datum)\n" "\n" #. type: Plain text #: kraft.adoc:118 #, fuzzy msgid "" "A number cycle template needs to contain either `%i` or `%n`, if not, `%i` " "is appended automatically." msgstr "" "Die Nummernkreisvorlage muss entweder `%i` oder `%n` enthalten. Wenn nicht, " "wird `%i` automatisch angehängt." #. type: Plain text #: kraft.adoc:120 #, fuzzy msgid "" "Both `%i` and `%n` are numeric values. They can also be padded with with " "leading zeros. The length is defined by the number of i's or n's put into " "the template. For example, if a daily counter with length of three and " "leading zeros is desired, `%nnn` has to be put into the template. This works " "up to a length of six characters." msgstr "" "Sowohl `%i`als auch `%n`sind Zahlen. Sie können auch mit führenden Nullen " "aufgefüllt werden. Die Länge wird durch die Anzahl der i's oder n's in der " "Vorlage definiert. Zum Beispiel müssen in der Vorlage drei n angegeben " "werden (`%nnn`), wenn drei führende Nullen gewünscht sind. Dies funktioniert " "mit bis zu sechs führenden Nullen." #. type: delimited block _ #: kraft.adoc:123 #, fuzzy msgid "" "NOTE: The \"design\" of the numbercycles and document numbers is very " "important. With the flexible system of templating Kraft can not prevent " "invalid number cycles. It is in the responsibility of the user." msgstr "" "NOTE: Das \"Design\" der Nummernkreise und der Dokument Nummern ist sehr " "wichtig. Mit dem flexiblen System mit Vorlagen in Kraft können ungültige " "Nummernkreise nicht vermieden werden. Es liegt in der Verantwortung der " "Nutzenden." #. type: Title ==== #: kraft.adoc:125 #, fuzzy, no-wrap msgid "PDF Template" msgstr "Textvorlagen" #. type: Plain text #: kraft.adoc:128 #, fuzzy msgid "" "In the entry field Template File: the user can select a custom template for " "this specific document type." msgstr "" "Im Eingabefeld btn:[Nummernkreise bearbeiten] können nutzerdefinierte " "Vorlagen für den Dokument Typ festgelegt werden." #. type: Plain text #: kraft.adoc:130 #, fuzzy msgid "" "If the file extension of the template file is `.trml`, the ReportLab based " "document converter is used. If the file extension is `.gtmpl`, Kraft " "automatically uses the Weasyprint based converter." msgstr "" "Wenn die Dateinamenerweiterung der Vorlagendatei `.trml` ist, wird der " "ReportLab basierte Dokument Konverter benutzt. Wenn die Erweiterung `.gtmpl` " "ist, wird automatisch der Weasyprint Konverter verwendet." #. type: delimited block _ #: kraft.adoc:133 #, fuzzy msgid "" "NOTE: The ReportLab system for PDF creation is deprecated in Kraft. Please, " "for new templates, always use Grantlee- and Weasyprint based templates." msgstr "" "NOTE: Das ReportLab basierte Konvertierungssystem für PDF ist abgekündigt in " "Kraft. Für neue Vorlagen sollte immer das Grantlee- und Weasyprint basierte " "System verwendet werden." #. type: Title ==== #: kraft.adoc:135 #, fuzzy, no-wrap msgid "PDF Postprocessing" msgstr "PDF Nachbearbeitung" #. type: Plain text #: kraft.adoc:138 #, fuzzy msgid "" "After Kraft has created the PDF document it is possible to merge the created " "PDF with static, customized PDFs created by the user. With that, it is easy " "to add a custom stationery with a logo to the resulting PDF (\"Watermark\")." msgstr "" "Nachdem das PDF Dokument in Kraft erzeugt wurde, können statische, " "benutzerdefinierte PDF Dateien mit dem Dokument verbunden werden. Damit ist " "es leicht, eigenes Briefpapier with einem Logo zu verwenden im endgültigen " "PDF (Wasserzeichen)." #. type: Plain text #: kraft.adoc:140 #, fuzzy msgid "" "The static PDFs should have the same page size as the generated documents. " "Keep in mind to use optimized images for logos etc. to not blow up the size " "of the result document." msgstr "" "Das statische PDF sollte die gleiche Seitengröße wie das generierte Dokument " "haben. Es sollten optimierte Bilder für Logos verwendet werden, um die " "resultierenden PDFs nicht aufzublähen." #. type: Plain text #: kraft.adoc:142 #, fuzzy msgid "image:pdfpostproc.png[PDF Postprocessing,float?\"right\"]" msgstr "image:pdfpostproc.png[PDF Nachbearbeitung,float?\"right\"]" #. type: Plain text #: kraft.adoc:144 #, fuzzy msgid "The watermark options are:" msgstr "Die Wasserzeichen-Optionen sind:" #. type: Plain text #: kraft.adoc:146 #, fuzzy, no-wrap msgid "*No Watermark*: No watermark is created\n" msgstr "*Kein Wasserzecihen*: Kein Wasserzeichen wird angezeigt" #. type: Plain text #: kraft.adoc:147 #, fuzzy, no-wrap msgid "*On first page*: The first page of the watermark.pdf is merged with the first page of the result document\n" msgstr "*Auf der ersten Seite*: Die erste Seite des wasserzeichen.pdf wird verwendet und der ersten Seite des generierten Dokumentes hinterlegt" #. type: Plain text #: kraft.adoc:148 #, fuzzy, no-wrap msgid "*Watermark on all pages*: Merges the first page of the watermark PDF to all pages of the result document\n" msgstr "*Wasserzeichen auf allen Seiten*: Verbindet die erste Seite des Wasserzeichen PDFs mit allen Seiten des generierten Dokumentes" #. type: Plain text #: kraft.adoc:149 #, fuzzy, no-wrap msgid "*alternating*: For this, the watermark PDF needs to have three pages. The first page is merged to the first page of the result document, the second and third page are alternated merge to subsequent pages.\n" msgstr "*abwechselnd*: Hierfür muss das Wasserzeichen-PDF drei Seiten haben. Die erste Seite wird mit der ersten Seite des generierten Dokumentes verbunden, die zweite und dritte Seite werden abwechselnd mit den folgenden Seiten des generierten Dokumentes verbunden." #. type: Plain text #: kraft.adoc:150 #, fuzzy, no-wrap msgid "*different first and last page*: the PDF needs to have three pages. The first page is merged to the first page of the result document, the third page to the last, and the second to all page between first and last page.\n" msgstr "*Unterschiedliche erste und letzte Seite*: Das Wasserzeichen PDF muss drei Seiten haben. Die erste Seite wird mit der ersten Seite des generierten Dokumentes verbunden, die dritte Seite mit der letzten und die zweite Seite des Wasserzeichen PDFs mit den Seiten zwischen erster und letzter Seite des generierten PDFs." #. type: Plain text #: kraft.adoc:152 msgid "" "If there is another static PDF document put into the entry field \"Append " "PDF:\", it is appended to the generated PDF. With that, Kraft will " "automatically add for example terms and conditions documents to the final " "document." msgstr "" #. type: Title === #: kraft.adoc:153 #, no-wrap msgid "Taxes" msgstr "Steuern" #. type: Plain text #: kraft.adoc:157 #, fuzzy msgid "" "image:taxes.png[Taxes,float=\"right\"] In many countries there are two kinds " "of VAT-taxes for sold products." msgstr "" "In vielen Ländern gibt es zwei Arten von Mehrwertsteuer für veräusserte " "Produkte." #. type: Plain text #: kraft.adoc:160 msgid "A high level and a low level." msgstr "Ein hoher und ein niedriger Steuersatz." #. type: Plain text #: kraft.adoc:163 msgid "" "Fill here the appropriate amounts in for the high level and the low level. " "If the tax-level is changing, then you add here the start date with the new " "tax-levels." msgstr "" #. type: Title === #: kraft.adoc:164 #, no-wrap msgid "Wages" msgstr "" #. type: Plain text #: kraft.adoc:169 msgid "" "image:wages.png[Wages,float=\"right\"] A list of wage costs is maintained in " "Kraft. The items are used in templates and during calculation." msgstr "" #. type: Plain text #: kraft.adoc:172 msgid "" "All data can be edited, customized and new items can be added in the Kraft " "Configuration Dialog reachable through the Settings menu." msgstr "" #. type: Plain text #: kraft.adoc:176 msgid "" "Remember that these units are later used in the documents, it is therefor " "important that you translate them to your own language and to fill in the " "correct prices." msgstr "" #. type: Title === #: kraft.adoc:177 #, no-wrap msgid "Units of measurement" msgstr "" #. type: Plain text #: kraft.adoc:182 msgid "" "image:unity.png[Units of measurement,float=\"right\"] A list of units of " "measurement is maintained in Kraft. In Kraft Configuration Dialog reachable " "through the Settings menu can you edit and customize items already in the " "list, and also can you add new items to the list." msgstr "" #. type: Plain text #: kraft.adoc:185 msgid "" "Remember that these units are later used in the documents, it is therefor " "important that you translate them to your own language." msgstr "" #. type: Title === #: kraft.adoc:186 #, no-wrap msgid "Own identity" msgstr "" #. type: Plain text #: kraft.adoc:190 msgid "" "Check here if the information that you have given during the initial setup " "is correct for the use in the documents." msgstr "" #. type: delimited block _ #: kraft.adoc:195 msgid "" "WARNING: If you made the choice to use the information from KaddressBook " "then is the information from a later manual entry ignored." msgstr "" #. type: Plain text #: kraft.adoc:199 msgid "" "After we have made some corrections to the configuration, we go back to the " "main window.Here we see three tabs:" msgstr "" #. type: Plain text #: kraft.adoc:201 msgid "Documents" msgstr "" #. type: Plain text #: kraft.adoc:202 msgid "Timeline" msgstr "" #. type: Title == #: kraft.adoc:203 kraft.adoc:205 #, no-wrap msgid "Catalogs" msgstr "" #. type: Plain text #: kraft.adoc:208 msgid "" "Kraft supports so called Catalogs in which templates for document items are " "kept. With the catalogs creating documents can be significantly accellerated " "in the day to day business. When creating new documents, the items templates " "from the catalogs can easily selected and moved over to the document." msgstr "" #. type: Plain text #: kraft.adoc:210 msgid "" "Since templates are organized in chapters entire documents can be prepared " "in different chapters to be used as template documents." msgstr "" #. type: Plain text #: kraft.adoc:212 msgid "" "Of course the items in the documents can be edited after they got picked " "from a catalog." msgstr "" #. type: Plain text #: kraft.adoc:214 msgid "By default Kraft comes with two different catalogs:" msgstr "" #. type: Plain text #: kraft.adoc:216 msgid "`Material`" msgstr "" #. type: Plain text #: kraft.adoc:219 msgid "" "A catalog of material that are sold, with their purchase prices, the profit " "and the sell-price." msgstr "" #. type: Plain text #: kraft.adoc:221 msgid "and `Standard Templates`" msgstr "" #. type: Plain text #: kraft.adoc:223 msgid "A catalog of standard recipes of work like planting trees." msgstr "" #. type: Plain text #: kraft.adoc:226 msgid "" "Both catalogs can have chapters and sub-chapters for to organize your " "templates. First we are going to fill in the" msgstr "" #. type: Title === #: kraft.adoc:227 #, fuzzy, no-wrap msgid "Material Catalog" msgstr "Materialverwaltung." #. type: Plain text #: kraft.adoc:232 msgid "" "A catalog of material that are sold, with their purchase prices, the profit " "and the sell-price. First we are going to add new chapters and subchapters." msgstr "" #. type: Title ==== #: kraft.adoc:233 #, no-wrap msgid "New chapters" msgstr "" #. type: Plain text #: kraft.adoc:237 msgid "" "Select with the mouse the column-name `material`, select now in the context-" "menu [Add a sub chapter]" msgstr "" #. type: Plain text #: kraft.adoc:239 msgid "and add an extra chapter like `Trees`" msgstr "" #. type: Title ==== #: kraft.adoc:240 #, no-wrap msgid "New sub chapters" msgstr "" #. type: Plain text #: kraft.adoc:248 msgid "" "We are going to ad sub chapters in the map `Trees`. Select with the mouse " "the name of the chapter where you like to add a subchapter, select now in " "the context-menu [Add a sub chapter] and ad an extra subchapters like `Loaf " "trees` and `needle trees`. After adding the extra chapters and subchapters " "for dividing the material, we are going to add the material themself." msgstr "" #. type: Title ==== #: kraft.adoc:249 #, no-wrap msgid "New template" msgstr "" #. type: Plain text #: kraft.adoc:254 msgid "" "Select with the mouse the name of the sub-chapter or chapter where you like " "to add a material. Select the sub map Loaf trees and select now in the " "context-menu" msgstr "" #. type: Plain text #: kraft.adoc:257 msgid "" "Add the extra materials `coconut tree`, `apple tree` and `pine-apple tree`." msgstr "" #. type: Plain text #: kraft.adoc:259 msgid "Fill in the price that we have paid." msgstr "" #. type: Plain text #: kraft.adoc:261 msgid "Fill in the profit that we want to have on the material" msgstr "" #. type: Plain text #: kraft.adoc:263 msgid "And fill in how much is in a packet." msgstr "" #. type: Plain text #: kraft.adoc:266 msgid "" "image:catalog_material.png[Material catalog,float=\"right\"] After this we " "add also in the map 'Wood' a item for a 'support pole' for later use with " "its price." msgstr "" #. type: Plain text #: kraft.adoc:268 msgid "Now we are going to:" msgstr "" #. type: Title === #: kraft.adoc:269 #, no-wrap msgid "Standard Templates" msgstr "" #. type: Plain text #: kraft.adoc:272 msgid "This is a catalog of standard recipes of work like:" msgstr "" #. type: Plain text #: kraft.adoc:274 msgid "planting trees" msgstr "" #. type: Plain text #: kraft.adoc:275 msgid "cutting grass" msgstr "" #. type: Plain text #: kraft.adoc:276 msgid "transport costs" msgstr "" #. type: Plain text #: kraft.adoc:277 msgid "planting grass" msgstr "" #. type: Plain text #: kraft.adoc:278 msgid "sowing grass-seed" msgstr "" #. type: Plain text #: kraft.adoc:280 msgid "We add here the standard work of planting a tree." msgstr "" #. type: Plain text #: kraft.adoc:283 msgid "" "Select with the mouse the name of the chapter [Work] where you like to add " "the new template," msgstr "" #. type: Plain text #: kraft.adoc:285 msgid "select now the context-menu [New template]" msgstr "" #. type: Plain text #: kraft.adoc:287 msgid "and the extra templates `Plant tree` and `cut grass`." msgstr "" #. type: Plain text #: kraft.adoc:289 msgid "After we made the new template, a window opens with 4 tabs:" msgstr "" #. type: Title ==== #: kraft.adoc:291 kraft.adoc:297 #, no-wrap msgid "Template" msgstr "" #. type: Title ==== #: kraft.adoc:292 kraft.adoc:309 #, no-wrap msgid "Time calculation" msgstr "" #. type: Plain text #: kraft.adoc:293 msgid "Fix costs" msgstr "Fixkosten" #. type: Title ==== #: kraft.adoc:294 kraft.adoc:346 #, no-wrap msgid "Material" msgstr "Material" #. type: Plain text #: kraft.adoc:296 msgid "First we go to the tab:" msgstr "" #. type: Plain text #: kraft.adoc:301 msgid "" "We give here the name of the new standard template like `Plant tree` image:" "catalog_standard.png[Standard catalog,float=\"right\"]" msgstr "" #. type: delimited block _ #: kraft.adoc:304 msgid "WARNING: be careful, this name is later used in the invoice" msgstr "" #. type: Plain text #: kraft.adoc:308 msgid "" "we select that this is per piece and that the margin is 8% and that the full " "VAT is applicable." msgstr "" #. type: Plain text #: kraft.adoc:312 msgid "We fill here in a number of work with the time:" msgstr "" #. type: Block title #: kraft.adoc:313 #, no-wrap msgid "Spent time" msgstr "" #. type: Table #: kraft.adoc:320 #, no-wrap msgid "" "|Dig hole |32 min. |worker\n" "|Place tree |12 min. |worker\n" "|Fill hole |17 min. |worker\n" "|give water |5 min. |worker\n" msgstr "" #. type: Plain text #: kraft.adoc:324 msgid "" "The cost for worker which we have earlier filled in is now used. image:" "catalog_standard_work.png[Time calculation,float=\"right\"]" msgstr "" #. type: delimited block _ #: kraft.adoc:328 msgid "" "NOTE: in the invoice we see later only Plant tree, we will not see the parts " "dig hole,place tree,fill hole,give water" msgstr "" #. type: Plain text #: kraft.adoc:331 msgid "Now we go to the tab" msgstr "" #. type: Title ==== #: kraft.adoc:332 #, no-wrap msgid "Fixed costs" msgstr "" #. type: Plain text #: kraft.adoc:335 msgid "and fill in:" msgstr "" #. type: Block title #: kraft.adoc:336 #, no-wrap msgid "Fixed item" msgstr "" #. type: Table #: kraft.adoc:340 #, no-wrap msgid "|Transportcost |35 euro |1 pcs.\n" msgstr "" #. type: Plain text #: kraft.adoc:343 msgid "image:catalog_standard_fixed_cost.png[Fixed cost,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:345 msgid "After this we go to the tab:" msgstr "" #. type: Plain text #: kraft.adoc:350 msgid "" "Here we select btn:[next], after which the window [Add Material to " "Calculation] opens for a selection of material. We navigate to the map " "'wood' where we select the 'support pole'." msgstr "" #. type: Block title #: kraft.adoc:351 #, no-wrap msgid "Used materials" msgstr "" #. type: Table #: kraft.adoc:355 #, no-wrap msgid "|1 |support pole |3,5 euro\n" msgstr "" #. type: Plain text #: kraft.adoc:358 msgid "image:catalog_standard_material.png[Material,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:360 msgid "We go now back to the first tab template" msgstr "" #. type: Plain text #: kraft.adoc:363 msgid "" "On the first tab [template], we can now see the overall cost per one unit" msgstr "" #. type: Plain text #: kraft.adoc:366 msgid "" "Click on [OK] for saving the result or on [cancel] for discarding the result." msgstr "" #. type: Plain text #: kraft.adoc:368 msgid "We make a second template `cut grass`" msgstr "" #. type: Plain text #: kraft.adoc:371 msgid "" "we fill in `cut grass`, as unit we choose sm (square meter), on the second " "tab we fill in that we need 3 min per square meter." msgstr "" #. type: Plain text #: kraft.adoc:374 msgid "" "Click on [OK] for saving the result or on [Cancel] for discarding the result." msgstr "" #. type: Plain text #: kraft.adoc:376 msgid "'''" msgstr "" #. type: Title === #: kraft.adoc:377 #, no-wrap msgid "Header- and Footer Text Templates" msgstr "" #. type: Plain text #: kraft.adoc:380 msgid "" "Kraft supports text templates also for the header- and footer-text of " "documents. Each document type has it's own set of text templates. To access " "them, open a document of a certain document type in edit mode and use the " "btn:[show templates] to make the templates visible. In both the header- and " "footer-section the stored templates become visible." msgstr "" #. type: Plain text #: kraft.adoc:382 msgid "" "Directly under the navigation pane on the right side of the window is a list " "of the names of the available templates. Clicking on one of the names in the " "list displays the text in the pane below." msgstr "" #. type: Plain text #: kraft.adoc:384 msgid "" "Underneath there are buttons located with the following functions from left " "to right:" msgstr "" #. type: Plain text #: kraft.adoc:386 msgid "" "Add the template to the document: This button replaces the text of the " "document with the selected template." msgstr "" #. type: Plain text #: kraft.adoc:387 msgid "" "Insert the template to the document: The selected template is inserted to " "the current place of the cursor in the document." msgstr "" #. type: Plain text #: kraft.adoc:388 msgid "" "Create a new template: Opens a dialog to enter a complete new template for " "the current doc type." msgstr "" #. type: Plain text #: kraft.adoc:389 msgid "" "Edit the current template: Opens the dialog to edit the currently selected " "template." msgstr "" #. type: Plain text #: kraft.adoc:390 msgid "" "Delete the current template: Removes the template permanently from the list " "of available templates." msgstr "" #. type: Plain text #: kraft.adoc:392 msgid "" "Templates with the name _Standard_ are the default templates for the " "document type. They are inserted automatically if a document of this type is " "created." msgstr "" #. type: Title ==== #: kraft.adoc:394 #, no-wrap msgid "Macros" msgstr "" #. type: Plain text #: kraft.adoc:397 msgid "" "Both the header- and footer-templates can contain so called macros which are " "replaced with calculated values once the document is rendered to the final " "output format." msgstr "" #. type: Plain text #: kraft.adoc:399 msgid "The following list of macros are supported:" msgstr "" #. type: Plain text #: kraft.adoc:401 msgid "" "`DATE_ADD_DAYS()`: Returns the date of the of document plus the " "number of days specified as parameter to the macro." msgstr "" #. type: Plain text #: kraft.adoc:402 msgid "" "`ITEM_COUNT_WITH_TAG()`: Returns the amount of items tagged with the " "tag." msgstr "" #. type: Plain text #: kraft.adoc:403 msgid "" "`NETTO_SUM_PER_TAG()`: Returns the netto sum of all items that are " "tagged with the named tag." msgstr "" #. type: Plain text #: kraft.adoc:404 msgid "" "`BRUTTO_SUM_PER_TAG()`: Returns the brutto sum of all items that are " "tagged with the named tag." msgstr "" #. type: Plain text #: kraft.adoc:405 msgid "" "`VAT_SUM_PER_TAG()`: Returns the pure tax of all items that are tagged " "with the named tag." msgstr "" #. type: Plain text #: kraft.adoc:406 msgid "" "`IF_ANY_HAS_TAG()` and `END_HAS_TAG`: Includes the text between the two " "macros only if there is at least one item that is tagged with the tag." msgstr "" #. type: Plain text #: kraft.adoc:408 msgid "" "As an example, this footer text template can be used to automatically " "generate useful texts:" msgstr "" #. type: delimited block - #: kraft.adoc:411 #, no-wrap msgid "Please pay this invoice until three weeks after the date of the document, which is the DATE_ADD_DAYS(21).\n" msgstr "" #. type: delimited block - #: kraft.adoc:416 #, no-wrap msgid "" "IF_ANY_HAS_TAG(Material)\n" "This invoice lists material in ITEM_COUNT_WITH_TAG(Material) items. The net value is NETTO_SUM_PER_TAG(Material),\n" "plus VAT_SUM_PER_TAG(Material) = BRUTTO_SUM_PER_TAG(Material).\n" "END_HAS_TAG\n" msgstr "" #. type: Plain text #: kraft.adoc:419 msgid "We are now ready for the first invoice." msgstr "" #. type: Title == #: kraft.adoc:421 #, no-wrap msgid "Creating Documents" msgstr "" #. type: Title === #: kraft.adoc:423 #, no-wrap msgid "The first Invoice" msgstr "" #. type: Plain text #: kraft.adoc:426 msgid "Open the tab btn:[documents]" msgstr "" #. type: Plain text #: kraft.adoc:428 kraft.adoc:533 msgid "Click on btn:[create document]" msgstr "" #. type: Plain text #: kraft.adoc:430 msgid "The window document [creation wizard opens]." msgstr "" #. type: Plain text #: kraft.adoc:432 msgid "Select in document type `invoice`." msgstr "" #. type: Plain text #: kraft.adoc:435 msgid "" "Fill in on the whiteboard content a short text about what the invoice is, " "like: `cut grass and planted tree for mister Jonson`" msgstr "" #. type: Plain text #: kraft.adoc:437 kraft.adoc:542 msgid "Click on btn:[next]" msgstr "" #. type: Plain text #: kraft.adoc:439 kraft.adoc:544 msgid "Select on the new window the name and address from the client." msgstr "" #. type: Plain text #: kraft.adoc:442 kraft.adoc:547 msgid "" "(if the name and address is not there, click then on btn:[new contact] or on " "btn:[edit contact] if you want to edit the contact)" msgstr "" #. type: Plain text #: kraft.adoc:444 kraft.adoc:549 msgid "Click on btn:[OK]." msgstr "" #. type: Plain text #: kraft.adoc:446 msgid "Now opens the window document [items]." msgstr "" #. type: Plain text #: kraft.adoc:448 msgid "this window has 2 tabs and the 3 buttons on the top:" msgstr "" #. type: Plain text #: kraft.adoc:450 kraft.adoc:555 msgid "btn:[Add item...]," msgstr "" #. type: Plain text #: kraft.adoc:451 kraft.adoc:556 msgid "btn:[Add discount item]," msgstr "" #. type: Plain text #: kraft.adoc:452 kraft.adoc:557 msgid "btn:[Show templates]." msgstr "" #. type: Plain text #: kraft.adoc:456 msgid "" "In the left tab you can see all the items that we want to place on the " "invoice, on the right tab we see the text from the header, the total price " "and the footer." msgstr "" #. type: Plain text #: kraft.adoc:460 msgid "" "If you click on the text of the header or the footer on the right side then " "the window changes in such a way that you can edit the header or the footer." msgstr "" #. type: Plain text #: kraft.adoc:463 msgid "" "Adapt the header and the footer to your situation, on the footer you can " "place a text: `We make your garden-dream come to reality.`." msgstr "" #. type: Plain text #: kraft.adoc:465 kraft.adoc:559 msgid "Click on the button btn:[Show templates]." msgstr "" #. type: Plain text #: kraft.adoc:469 msgid "" "The right tab changes and show now the earlier made templates, we select in " "the group Work, the subgroup Plant tree and click then on the button with " "the to the left pointing arrow on the bottom side." msgstr "" #. type: Plain text #: kraft.adoc:471 kraft.adoc:565 msgid "A new window [Create Item from Template] opens." msgstr "" #. type: Plain text #: kraft.adoc:474 msgid "" "Because we have planted 2 trees, we go to the field [insert] and change this " "to 2 pcs." msgstr "" #. type: Plain text #: kraft.adoc:477 msgid "" "Click on btn:[OK] for saving the result or on btn:[cancel] for discarding " "the result." msgstr "" #. type: Plain text #: kraft.adoc:479 kraft.adoc:573 kraft.adoc:584 msgid "The window close and we go back to the main window." msgstr "" #. type: Plain text #: kraft.adoc:483 msgid "" "We click again on btn:[Show templates] and select this time `cut grass`, we " "click again on the button with the arrow, in the opened window we select " "that the grass-field was 24 square meter." msgstr "" #. type: Plain text #: kraft.adoc:486 kraft.adoc:571 kraft.adoc:604 kraft.adoc:640 msgid "" "Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding " "the result." msgstr "" #. type: Plain text #: kraft.adoc:488 msgid "" "We add now manually an item by clicking on the button btn:[Add item…] and " "the window [create new item] opens." msgstr "" #. type: Plain text #: kraft.adoc:492 msgid "" "Because we have delivered a special tree, we fill here in the name of the " "special tree `liguster`, at the field insert we fill in the number of the " "special trees that we have delivered and the price of them." msgstr "" #. type: delimited block _ #: kraft.adoc:498 msgid "" "WARNING: Remind that in the catalog we can add a profit on the price of the " "material, in the invoice and in the offer we can not add a profit on the " "price of the material." msgstr "" #. type: Plain text #: kraft.adoc:501 msgid "We have now an invoice with 3 items." msgstr "" #. type: Plain text #: kraft.adoc:504 msgid "" "Click on btn:[OK] for saving the invoice or on btn:[Cancel] for discarding " "the invoice." msgstr "" #. type: Plain text #: kraft.adoc:506 msgid "We click on btn:[OK] and save the result." msgstr "" #. type: Plain text #: kraft.adoc:508 msgid "Your first invoice is now ready for sending." msgstr "" #. type: Plain text #: kraft.adoc:511 msgid "" "In the window documents we see our first invoice, notice that this document " "has a document number which we can see on the left side." msgstr "" #. type: Plain text #: kraft.adoc:514 msgid "" "On top of the window with all the invoices we see the button [Print " "Document], on which we click." msgstr "" #. type: Plain text #: kraft.adoc:517 msgid "" "From the invoice will now a PDF be made which we can print on paper or send " "by email to the client." msgstr "" #. type: Plain text #: kraft.adoc:519 msgid "After this we are going to create a offer for some work in a garden." msgstr "" #. type: Title === #: kraft.adoc:521 #, no-wrap msgid "Creating an Offer" msgstr "" #. type: Plain text #: kraft.adoc:524 msgid "" "The client has asked to plant a tree, we will offer 3 different trees which " "we can plant." msgstr "" #. type: Plain text #: kraft.adoc:527 msgid "" "Beside this, we have seen that there is a lifeless three, which we will " "offer to remove as extra work. image:create_new_doc.png[Numbercycles," "float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:529 msgid "" "For the total price we do not want to show the price of the removal of the " "lifeless tree and we want for the total price only to show the price of one " "tree and not three." msgstr "" #. type: Plain text #: kraft.adoc:531 msgid "Open again the tab btn:[documents]." msgstr "" #. type: Plain text #: kraft.adoc:535 msgid "The window _Document Creation Wizard_ opens." msgstr "" #. type: Plain text #: kraft.adoc:537 msgid "select in btn:[document type] > btn:[Offer]." msgstr "" #. type: Plain text #: kraft.adoc:540 msgid "" "Fill in on the whiteboard content a short text about what the offer is, " "like: `plant one tree and removal of lifeless tree`" msgstr "" #. type: Plain text #: kraft.adoc:551 msgid "Now the window [edit document] opens." msgstr "" #. type: Plain text #: kraft.adoc:553 msgid "This window has 2 tabs and the 3 buttons on the top:" msgstr "" #. type: Plain text #: kraft.adoc:563 msgid "" "The right tab changes and show now the earlier made templates, we select in " "the group `Work`, the subgroup `Plant tree` and click then on the button " "with the to the left pointing arrow on the bottom side." msgstr "" #. type: Plain text #: kraft.adoc:568 msgid "" "Because we want to plant 1 tree, we go to the field [insert] and keep this " "on 1 pcs." msgstr "" #. type: Plain text #: kraft.adoc:576 msgid "" "We click on the button btn:[Show templates] and this time we select in " "catalog Material" msgstr "" #. type: Plain text #: kraft.adoc:580 msgid "" "The material-catalog opens, and we can select in the chapter `trees` the " "subchapter `loaf trees` in which we select the `apple tree` which we made " "earlier." msgstr "" #. type: Plain text #: kraft.adoc:582 msgid "" "Click on we btn:[OK] for saving the result or on btn:[cancel] for discarding " "the result." msgstr "" #. type: Plain text #: kraft.adoc:586 msgid "We add now manually an item by clicking on the button `Add item…`." msgstr "" #. type: Plain text #: kraft.adoc:588 msgid "the window [create new item] opens." msgstr "" #. type: Plain text #: kraft.adoc:590 msgid "" "We want that the client can make a choice from an apple, a pear tree and the " "liguster." msgstr "" #. type: Plain text #: kraft.adoc:592 msgid "Therefor we are going to add also a pear tree manually." msgstr "" #. type: Plain text #: kraft.adoc:594 msgid "" "We click on the button btn:[Add item…] and the window [create new item] " "opens." msgstr "" #. type: Plain text #: kraft.adoc:598 msgid "" "We fill here in the name of the tree `Pear tree`, at the field insert we " "fill in the number of the special trees that we have delivered and the price " "of them." msgstr "" #. type: Plain text #: kraft.adoc:601 msgid "" "We want add this to the material catalog for future use, therefor we select " "also [select this item as template for future documents] and we select in " "[save in chapter]`trees`." msgstr "" #. type: Plain text #: kraft.adoc:606 msgid "We does this again but then for the liguster." msgstr "" #. type: Plain text #: kraft.adoc:608 msgid "We have now 3 items with trees in the offer." msgstr "" #. type: Plain text #: kraft.adoc:610 msgid "" "As last item we add an item with `remove tree` with 0,5 hour for 32 euro." msgstr "" #. type: Plain text #: kraft.adoc:612 msgid "On the left side of an item we can see 2 buttons:" msgstr "" #. type: Plain text #: kraft.adoc:614 msgid "a button with a flag and a button with what looks like a page." msgstr "" #. type: Plain text #: kraft.adoc:617 msgid "" "We select the upper button with the page after which opens a context-menu " "with the items:" msgstr "" #. type: Plain text #: kraft.adoc:619 msgid "image:context1.png[Context menu,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:629 #, no-wrap msgid "" " [Item kind]->[Normal]\n" " [Item kind]>[Alternative]\n" " [Item kind]>[On demand]\n" " [Tax]\n" " [Move up]\n" " [Move down]\n" " [Lock item]\n" " [Unlock item]\n" " [Delete item]\n" msgstr "" #. type: Plain text #: kraft.adoc:632 msgid "" "We choose here [Item kind] and change for `pear tree` from [normal] to " "[alternative]." msgstr "" #. type: Plain text #: kraft.adoc:635 msgid "" "We do this also for [liguster] and for [remove tree] we change this from " "[normal] to [on demand]." msgstr "" #. type: Plain text #: kraft.adoc:637 msgid "image:context2.png[Context menu,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:643 msgid "" "We want to see the result and therefor we click on the button [show " "document]." msgstr "" #. type: Plain text #: kraft.adoc:649 msgid "" "We see now that the prize of the pear tree, the liguster and the removal of " "the tree is not used for the total prize. When we are happy with the result, " "we can click on the button btn:[close] after which we click on the button " "btn:[Print Document] for making a PDF what we can print out or send to the " "client." msgstr "" #. type: Plain text #: kraft.adoc:652 msgid "" "After your first invoice is now your first offer now also ready for sending." msgstr "" #. type: Title === #: kraft.adoc:654 #, fuzzy, no-wrap msgid "Creating an Acceptance of Order" msgstr "Auftragsbestätigung" #. type: Plain text #: kraft.adoc:657 msgid "" "The document type \"Acceptance of Order\" is sent subsequently to an offer." msgstr "" #. type: Plain text #: kraft.adoc:659 msgid "image:acceptance_o_o_context.png[Numbercycles,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:662 msgid "" "When a client has made a request, we will send an offer in wich we describe " "which items we will deliver. Hopefully the client will give an order for " "the work." msgstr "" #. type: Plain text #: kraft.adoc:666 msgid "" "It is a good practice to respond on the order with an \"Acceptance of " "order\" in which we describe all the items we will deliver. We can make the " "\"Acceptance of order\" on the same way as we made the invoice or the offer " "by selecting each item and correcting the number of delivery. This takes " "time and we can make errors by forgetting items or filling an incorrect " "number." msgstr "" #. type: Plain text #: kraft.adoc:668 msgid "" "It can be done quicker by selecting the offer in the list and selecting btn:" "[Create Followup Document] from either the context menu or the main menu." msgstr "" #. type: Plain text #: kraft.adoc:670 msgid "We have now in documenttype the choice from:" msgstr "" #. type: Plain text #: kraft.adoc:676 #, no-wrap msgid "" " [Acceptance of order]\n" " [Invoice]\n" " [Partial Invoice]\n" " [final Invoice]\n" " [Progress Payment Invoice]\n" msgstr "" #. type: Plain text #: kraft.adoc:678 msgid "image:followup_1.png[Folloup document,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:682 msgid "" "We select here \"Acceptance of order\". We have now a copy from the offer " "as an Acceptance of order (do not forget to adapt Alternative Delivery items " "and on demand items.)" msgstr "" #. type: Plain text #: kraft.adoc:684 msgid "image:followup_2.png[Folloup document,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:688 msgid "" "You can do this also for the creation of the invoice as a followup for " "Acceptance of order. Each document type has a specific list of follow up " "documents. It is a good practice to describe on the invoice precisely what " "was delivered." msgstr "" #. type: Title == #: kraft.adoc:690 #, no-wrap msgid "Customization" msgstr "" #. type: Plain text #: kraft.adoc:694 msgid "" "Kraft can be customized in most of the graphical user interface and in " "particular in the output it generates." msgstr "" #. type: Title === #: kraft.adoc:695 #, no-wrap msgid "Output Document Customization" msgstr "" #. type: Plain text #: kraft.adoc:698 msgid "" "To create PDF output documents, the document data that was edited in the " "Kraft app is filled into a template. The template defines how the output " "document looks like, ie. by font settings, placing of elements and such." msgstr "" #. type: Plain text #: kraft.adoc:700 msgid "" "The file that is assembled from data and the template is converted to PDF " "using a special document creation script. All that is started automatically " "by Kraft if a document should be printed." msgstr "" #. type: Plain text #: kraft.adoc:702 msgid "" "Each document type in Kraft can have it's own template that is used to " "create a PDF. Which one can be set in the Settings dialog for document types." msgstr "" #. type: Title ==== #: kraft.adoc:703 #, no-wrap msgid "WeasyPrint Documents" msgstr "" #. type: Plain text #: kraft.adoc:706 msgid "" "Kraft still ships with the old ReportLab based converter, but that will be " "deprecated the future. The WeasyPrint based system is the future. It is a " "recommended to port existing templates." msgstr "" #. type: Plain text #: kraft.adoc:708 msgid "" "With https://weasyprint.org[WeasyPrint] Kraft uses a very powerful generator " "that makes it very easy to create highly customized documents with great " "quality." msgstr "" #. type: Plain text #: kraft.adoc:710 msgid "" "WeasyPrint converts a html file to PDF. It is integrating a cascading " "stylesheet (CSS) file which has a huge impact on the PDF document's look." msgstr "" #. type: Plain text #: kraft.adoc:712 msgid "" "The html- and CSS input file for WeasyPrint is built from the Kraft template " "file." msgstr "" #. type: Plain text #: kraft.adoc:714 msgid "" "To enable the use of WeasyPrint for a document type in Kraft, simply create " "a weasyprint compatible template file and save it with the extension *." "gtmpl*. Based on the file extension Kraft automatically uses WeasyPrint and " "the Grantlee templating engine for rendering." msgstr "" #. type: Plain text #: kraft.adoc:716 msgid "" "From version 0.95 on Kraft ships with an example template in the Grantlee- " "and WeasyPrint format. It can be found at `/usr/share/kraft/reports/invoice." "gtmpl` or https://github.com/dragotin/kraft/blob/master/reports/invoice." "gtmpl[online on Github]. An example CSS file `kraft.css` (https://github.com/" "dragotin/kraft/blob/master/reports/kraft.css[on Github]) is shipped as a " "good starting point for adoption." msgstr "" #. type: Title ==== #: kraft.adoc:717 #, no-wrap msgid "Template Variables" msgstr "" #. type: Plain text #: kraft.adoc:720 msgid "" "To generate the PDF, Kraft has to transfer data from the document you have " "been working on to the input file that is processed to a PDF. For that, " "Kraft uses a text template in which Kraft replaces variables with the actual " "values." msgstr "" #. type: Plain text #: kraft.adoc:722 msgid "" "For example, the tag `{{ doc.doctype }}` is replaced with the current " "document type during the generating process." msgstr "" #. type: Plain text #: kraft.adoc:724 msgid "" "The syntax is based on the Django syntax for templates described in the " "https://docs.djangoproject.com/en/3.1/topics/templates/[the docs]." msgstr "" #. type: Title ==== #: kraft.adoc:725 #, no-wrap msgid "EPC QR Code" msgstr "" #. type: Plain text #: kraft.adoc:728 msgid "" "With Weasyprint based PDF generation Kraft supports the https://en.wikipedia." "org/wiki/EPC_QR_code[EPC QR Code] which implements a European standard for " "payments by computer and mobile devices." msgstr "" #. type: Plain text #: kraft.adoc:730 msgid "" "In Germany it is also known as _Giro Code_, in Belgium as _Bancontact QR_, " "in the Netherlands as _iDEAL QR-code_ and in Spain it is also known as " "_Bizum QR-code_." msgstr "" #. type: Plain text #: kraft.adoc:732 msgid "" "In Germany it is accepted by the _Giro Code_ and in Holland it is accepted " "by the official https://www.ideal.nl/consumenten/ideal-app/[_iDEAL QR-code_] " "app." msgstr "" #. type: Plain text #: kraft.adoc:734 msgid "" "In Belgium and Holland it is accepted by the apps of many banks, and in " "Austria and Finland it is accepted by the apps of all banks." msgstr "" #. type: Plain text #: kraft.adoc:736 msgid "" "To use the EPC QR code on the invoice printout, the bank account information " "has to be added to own identity settings dialog in Kraft. The giro code is " "current only generated for documents with the document type `Rechnung`." msgstr "" #. type: Plain text #: kraft.adoc:738 msgid "" "To include the generated EPC QR Code into the PDF document, the Weasyprint " "template needs to contain a snippet like this:" msgstr "" #. type: delimited block - #: kraft.adoc:747 #, no-wrap msgid "" " {%if doc.isInvoice and epcqrcode.valid %}\n" "

\n" " \"EPC\n" " Dieser QR Code ermöglicht einfaches, sicheres und schnelles Begleichen dieser Rechnung via GiroPay:\n" " Diesen Code mit dem Smartphone scannen und Überweisung per Banking App aufgeben.\n" "

\n" " {% endif %}\n" msgstr "" #. type: Title == #: kraft.adoc:751 #, no-wrap msgid "Menus and Shortcuts" msgstr "" #. type: Title === #: kraft.adoc:753 #, no-wrap msgid "Main Application Menu" msgstr "" #. type: Title ==== #: kraft.adoc:756 #, no-wrap msgid "The File Menu" msgstr "" #. type: Plain text #: kraft.adoc:761 #, no-wrap msgid "" " [File]>[Quit]\n" " [Ctrl]+[Q]\n" " Quits the application.\n" msgstr "" #. type: Title ==== #: kraft.adoc:763 #, no-wrap msgid "The Document Menu" msgstr "" #. type: Plain text #: kraft.adoc:769 #, no-wrap msgid "" " [Document]>[Show Document]\n" " [Ctrl]+[R]\n" " Opens a window with the selected document for showing it.\n" msgstr "" #. type: Plain text #: kraft.adoc:773 #, no-wrap msgid "" " [Document]>[Edit Document]\n" " [Ctrl+O]\n" " Opens a window with the selected document for editing it.\n" msgstr "" #. type: Plain text #: kraft.adoc:777 #, no-wrap msgid "" " [Document]>[Open Archived document]\n" " [Ctrl]+[A]\n" " Opens an archived document.\n" msgstr "" #. type: Plain text #: kraft.adoc:780 #, no-wrap msgid "" " [Document]>[Create Document]\n" " Opens a window with a wizard for creating a new client-document.\n" msgstr "" #. type: Plain text #: kraft.adoc:784 #, no-wrap msgid "" " [Document]>[Copy Document]\n" " Makes a copy of the selected client-document to a new client-document\n" " which can belong to an other client or an other documenttype.\n" msgstr "" #. type: Plain text #: kraft.adoc:787 #, no-wrap msgid "" " [Document]>[Follow Document]\n" " Opens the selected client-document for editing.\n" msgstr "" #. type: Plain text #: kraft.adoc:791 #, no-wrap msgid "" " [Document]>[Print document]\n" " Makes a PDf from the selected client-document for to be mailed or\n" " printed.\n" msgstr "" #. type: Plain text #: kraft.adoc:795 #, no-wrap msgid "" " [Document]>[Mail document]\n" " [Ctrl]+[M]\n" " Mails a document.\n" msgstr "" #. type: Title ==== #: kraft.adoc:798 #, no-wrap msgid "The Settings menu" msgstr "" #. type: Plain text #: kraft.adoc:804 #, no-wrap msgid "" " [Settings]>[Edit Tag Templates]\n" " [Ctrl]+[E]\n" " Opens a window where you add, edit or translate the tags (like work,\n" " material, plants or discounts).\n" msgstr "" #. type: Plain text #: kraft.adoc:808 #, no-wrap msgid "" " [Settings]>[Redo initial setup]\n" " [Ctrl+R]\n" " Redoes the initial setup. After this, a restart of Kraft is required.\n" msgstr "" #. type: Plain text #: kraft.adoc:812 #, no-wrap msgid "" " [Settings]>[Showed toolbars]\n" " Here you can decide if the `main toolbar` and the toolbar `Document Actions`\n" " are shown.\n" msgstr "" #. type: Plain text #: kraft.adoc:816 #, no-wrap msgid "" " [Settings]>[Configure Kraft]\n" " [Ctrl]+[Shft]+[,]\n" " Here you can configure Kraft.\n" msgstr "" #. type: Title === #: kraft.adoc:817 #, no-wrap msgid "Document Edit Window" msgstr "" #. type: Title ==== #: kraft.adoc:820 #, no-wrap msgid "The context Menu" msgstr "" #. type: Plain text #: kraft.adoc:824 #, no-wrap msgid "" " [Context]>[Item kind]\n" " change the status from this item between\n" msgstr "" #. type: Plain text #: kraft.adoc:825 #, no-wrap msgid "Normal\n" msgstr "" #. type: Plain text #: kraft.adoc:826 #, no-wrap msgid "Alternative\n" msgstr "" #. type: Plain text #: kraft.adoc:827 #, no-wrap msgid "On demand\n" msgstr "" #. type: Plain text #: kraft.adoc:830 #, no-wrap msgid "" " [Context]>[Tax]\n" " Seems not working.\n" msgstr "" #. type: Plain text #: kraft.adoc:833 #, no-wrap msgid "" " [Context]>[Move up]\n" " Moves this item a place up in document.\n" msgstr "" #. type: Plain text #: kraft.adoc:836 #, no-wrap msgid "" " [Context]>[Move down]\n" " Moves this item a place down in document.\n" msgstr "" #. type: Plain text #: kraft.adoc:839 #, no-wrap msgid "" " [Context]>[Lock item]\n" " It is not clear what is does.\n" msgstr "" #. type: Plain text #: kraft.adoc:842 #, no-wrap msgid "" " [Context]>[Unlock item]\n" " It is not clear what is does.\n" msgstr "" #. type: Plain text #: kraft.adoc:845 #, no-wrap msgid "" " [Context]>[Delete item]\n" " Removes this item from document.\n" msgstr "" #. type: Title == #: kraft.adoc:848 #, no-wrap msgid "Advanced Topics" msgstr "Fortgeschrittene Themen" #. type: Plain text #: kraft.adoc:851 msgid "" "This chapter describes advanced topics around Kraft. Some Linux knowledge is " "required, and setups should be done by experienced Linux administrators and " "should be tested carefully." msgstr "" "Dieses Kapitel beschreibt fortgeschrittene Themen um Kraft. Dabei wird etwas " "Linux-Kenntnis vorausgesetzt, und das Aufsetzen sollte von erfahreneren " "Linux Administratoren durchgeführt und gut testet werden." #. type: Title === #: kraft.adoc:852 #, fuzzy, no-wrap msgid "Using Kraft Collaboratively" msgstr "Kraft kollaborativ verwenden" #. type: Plain text #: kraft.adoc:855 msgid "" "Kraft can be used collaborative in a distributed environment. That means " "that multiple users work on their desktops with their own Kraft instance on " "the same data." msgstr "" "Kraft kann kollaborativ in einer verteilten Umgebung verwendet werden. Das " "heisst, dass mehrere Benutzer an ihren jeweiligen Arbeitsplatzrechnern mit " "ihrer eigenen Kraft Instanz arbeiten können und dabei die selben Daten " "verwenden." #. type: Plain text #: kraft.adoc:857 msgid "" "This whole topic is a subject to change, as Kraft will evolve to use " "ownCloud as a private cloud solution to store the data." msgstr "" "Das ganze Thema ist Veränderung unterworfen, da Kraft in naher Zukunft " "ownCloud als private Cloud Lösung zur Datenspeicherung verwenden wird." #. type: Title ==== #: kraft.adoc:858 #, no-wrap msgid "Sharing Database and Document Pool" msgstr "Datenbank und Dokumentpool teilen" #. type: Plain text #: kraft.adoc:861 msgid "" "The simplest case is that two or more Kraft instances use a database " "together and access the same pool of PDF documents on the harddisk. For " "simplicity this describes only two Kraft instances." msgstr "" "Der einfachste Fall ist das zwei oder wenige mehr Kraft Instanzen die " "Datenbank gemeinsam benutzen und den Pool von PDF Dokumenten gemeinsam " "verwenden. Um es einfach zu halten werden hier zwei Instanzen beschrieben." #. type: Plain text #: kraft.adoc:863 msgid "" "A typical use case would be: Two different Linux users want to use Kraft. " "They both have their own computer but only work in the same network. For " "example this would describe a situation with one main office machine that " "runs Kraft in normal mode, plus a notebook with Kraft in read only mode to " "view documents, check catalogs and such." msgstr "" "Ein typischer Anwendungsfall könnte sein: Zwei verschiedene Linux user " "möchten Kraft verwenden. Sie haben beide ihren eigenen Computer und arbeiten " "im selben Netzwerk. Dieses Beispiel beschreibt eine Situation mit einem " "Hauptbüro das Kraft im normalen Modus betreibt, und einem Notebook mit " "Kraft, das im NurLesen Modus um Dokumente anzusehen, Kataloge zu überprüfen " "und ähnliches." #. type: Plain text #: kraft.adoc:865 msgid "For that, the following prerequisites have to be met:" msgstr "Dafür müssen die folgenden Voraussetzungen erfüllt sein:" #. type: Plain text #: kraft.adoc:867 msgid "MySQL or MariaDB is used as database backend. Sqlite is not supported." msgstr "" "Als Datenbank-Backend wird MySQL oder MariaDB verwendet. Sqlite wird nicht " "unterstützt." #. type: Plain text #: kraft.adoc:868 msgid "" "The database is accessible with a mysql user and from each machine for both " "users." msgstr "" "Die Datenbank ist mit dem MySQL Benutzer von beiden Rechnern aus erreichbar." #. type: Plain text #: kraft.adoc:869 msgid "The document store directory has to be shared." msgstr "Das Dokument-Speicher-Verzeichnis muss geteilt werden." #. type: delimited block _ #: kraft.adoc:873 msgid "" "WARNING: There is no protection against having both users editing the same " "document. Because that is dangerous and can lead to unpredictable results, " "it is recommended to run all instances of Kraft except the main one in read " "only mode. This is done by starting Kraft with the `-r` command line switch." msgstr "" "Achtung: Es gibt keinen Schutz dagegen, dass beide Benutzer das gleiche " "Dokument zur gleichen Zeit bearbeiten. Weil das gefährlich ist und zu " "unvorhersehbaren Resultaten führen kann, ist es empfohlen, Kraft in allen " "ausser der Haupt-Instanz im Nur-Lese Modus zu betreiben. Der Nur-Lese Modus " "wird mit Krafts Kommandozeilenschalter -r eingeschaltet." #. type: Plain text #: kraft.adoc:876 #, no-wrap msgid "**Sharing the Database**\n" msgstr "**Die Datenbank teilen**\n" #. type: Plain text #: kraft.adoc:878 msgid "" "The database server should be installed on the main machine or a dedicated " "device like a NAS. Networking speed influences the comfort to use obviously." msgstr "" "Der Datenbankserver sollte auf der Haupt-Maschine installiert sein, oder es " "sollte ein spezialisiertes Gerät wie ein NAS verwendet werden. Die Netzwerk " "Geschwindigkeit beeinflusst die Benutzbarkeit natürlich erheblich." #. type: Plain text #: kraft.adoc:880 msgid "Find howtos on the internet how to setup MySQL accordingly." msgstr "Howtos um MySQL aufzusetzen sind im Internet zu finden." #. type: Plain text #: kraft.adoc:882 #, no-wrap msgid "**Sharing the Document Pool Directory**\n" msgstr "**Den Dokument Pool teilen**\n" #. type: Plain text #: kraft.adoc:884 msgid "" "Kraft writes generated PDF documents into a local directory. Where that is " "can be configured in the Kraft Config file. The config file has to be " "adopted on all instances." msgstr "" "Kraft schreibt generierte PDFs in ein lokales Verzeichnis. Welches " "Verzeichnis das ist kann im Kraft Konfigfile eingerichtet werden. Das " "Konfigfile muss auf allen Instanzen angepasst werden." #. type: Plain text #: kraft.adoc:886 msgid "" "That is located in each users home directory, in the path `.config/kraftrc`. " "It has to contain the following config value:" msgstr "" "Es ist in jedem Benutzer Homeverzeichnis unter dem releativen Pfad `.config/" "kraftrc`. Es muss den folgenden Konfigurations-Wert enthalten:" #. type: delimited block - #: kraft.adoc:890 #, fuzzy, no-wrap #| msgid "PdfOutputDir=/data/space/kraftdoc/pdf" msgid "" "[reporting]\n" "PdfOutputDir=/data/space/kraftdoc/pdf\n" msgstr "PdfOutputDir=/data/space/kraftdoc/pdf" #. type: Plain text #: kraft.adoc:893 msgid "" "There are different ways how share that directory, ie. NFS or SMB storages. " "It is important that both users from both machines can list and access the " "files. The main user needs read and write access, read only users only need " "read access to the files." msgstr "" "Es gibt verschiedene Wege wie das Verzeichnis geteilt werden kann, zum " "Beispiel NFS und SMB Server. Es ist entscheidend, dass beide Benutzer von " "beiden Maschinen die Dateien auflisten und zugreifen können. Der " "Hauptbenutzer braucht Schreib- und Leserecht., Nur-Lese Bentuzer brauchen " "nur Lesezugriff auf die Dateien." #. type: Plain text #: kraft.adoc:895 msgid "" "A recommended setup is a NFS share with autofs which is set up on the main " "machine. To manage file access a certain group should be set up on the " "machines with which access can be managed." msgstr "" "Ein empfohlenes Setup benutzt ein NFS Share über autofs, das auf der " "Hauptmaschine aufgesetzt werden muss. Um Dateizugriff zu verwalten, sollte " "eine Gruppe aufgesetzt werden." #. type: Plain text #: kraft.adoc:897 #, no-wrap msgid "**Starting Kraft in read-only mode**\n" msgstr "**Kraft im Nur-Lesen Modus**\n" #. type: Plain text #: kraft.adoc:899 msgid "" "To start Kraft in read-only mode, start the binary with the `-r` command " "line switch." msgstr "" "Um Kraft im Nur-Lese Modus zu starten, muss das Programm mit dem " "Kommandozeilenschalter `-r` gestartet werden." #. type: Title === #: kraft.adoc:900 #, no-wrap msgid "XRechnung Support" msgstr "" #. type: Plain text #: kraft.adoc:903 msgid "" "Kraft supports the XRechnung standard. That is a digital format for " "electronic invoicing, and it passed as law in Germany and follows a EU " "directive. The XRechnung is a XML file format designed for that purpose." msgstr "" #. type: Plain text #: kraft.adoc:905 msgid "" "To use the XRechnung Export productivly, a little manual work is still " "needed in Kraft. Kraft creates the XML file based on a template, very " "similar to the normal PDF documents. That means that it loads a template " "that contains static elements (ie. the company address) that do not change " "between different invoices. The dynamic elements (customer data, items etc.) " "are filled into the template during the generation step." msgstr "" #. type: Plain text #: kraft.adoc:907 msgid "" "In order to generate correct XRechnung files for the specific company, the " "user has to adopt the template file manually to the companies needs. Note " "that this has only to be done once and should be easy for a person with a " "bit computer experience (Basic knowledge about XML appreciated!)." msgstr "" #. type: Plain text #: kraft.adoc:909 msgid "" "To adapt the file to the needs of the company, it is best to start with the " "https://raw.githubusercontent.com/dragotin/kraft/master/reports/xrechnung." "xrtmpl[example XRechnung file]. It has to be downloaded and saved into a " "location that the user can edit. Open it in a normal text editor, such as " "https://kate-editor.org/[Kate]." msgstr "" #. type: Plain text #: kraft.adoc:911 msgid "" "Read carefully through the file without being scared off by the XML format. " "All user strings (ie. company name, address and such) are user specific and " "should be replaced accordingly. Find https://www.xoev.de/" "xrechnung-16828[details about the format] here to better understand the " "meaning of the fields." msgstr "" #. type: Plain text #: kraft.adoc:913 msgid "" "Make sure to not disturb the proper XML format and do not change places " "where the template format `{{ template_name }}` is used." msgstr "" #. type: Plain text #: kraft.adoc:915 msgid "" "Once the file is adopted to the needs, open the Settings dialog of Kraft and " "insert the filename into the entry field for the XRechnung Template File on " "the Document Defaults page." msgstr "" #. type: Plain text #: kraft.adoc:917 msgid "" "After that step, the btn:[Export XRechung] menu item will open a dialog to " "pick a filename where to save the XRechnung invoice to." msgstr "" #. type: Plain text #: kraft.adoc:919 msgid "This file can now be transfered to the receiver of the invoice." msgstr "" #. type: Plain text #: kraft.adoc:921 msgid "" "There are validators for invoices in XRechnung format out there in the " "internet. It is useful to verify the format of the Kraft exported XRechnung." msgstr "" #. type: Title === #: kraft.adoc:922 #, no-wrap msgid "Changing the Locale" msgstr "" #. type: Plain text #: kraft.adoc:925 msgid "" "If it is needed that Kraft runs under a different locale than the actual " "desktop environment, this can be achieved by setting the desired locale in " "the start file of Kraft." msgstr "" #. type: Plain text #: kraft.adoc:927 msgid "" "On the linux desktop, apps are usually started through a so called https://" "specifications.freedesktop.org/desktop-entry-spec/latest/[desktop file]. It " "contains the information how the Kraft binary is started if user clicks on " "the icon on the desktop or in the start menu." msgstr "" #. type: Plain text #: kraft.adoc:929 msgid "" "The desktop file can usually be found in `/usr/share/applications/de.volle-" "kraft-voraus.kraft.desktop`." msgstr "" #. type: Plain text #: kraft.adoc:931 msgid "It contains the line" msgstr "" #. type: delimited block - #: kraft.adoc:934 #, no-wrap msgid "Exec=kraft %u\n" msgstr "" #. type: Plain text #: kraft.adoc:937 msgid "which starts the application with the default locale." msgstr "" #. type: Plain text #: kraft.adoc:939 msgid "Changing it to" msgstr "" #. type: delimited block - #: kraft.adoc:942 #, no-wrap msgid "Exec=env LANG=de_DE.UTF-8 kraft %u\n" msgstr "" #. type: Plain text #: kraft.adoc:945 msgid "" "would change that to run in the German locale for example, independent from " "the desktop environment location." msgstr "" #. type: Title == #: kraft.adoc:948 #, no-wrap msgid "Credits and License" msgstr "Credits und Lizenz" #. type: Plain text #: kraft.adoc:951 #, fuzzy msgid "Program and documentation copyright 2004–2023 Klaas Freitag" msgstr "Software und Dokumentation Copyright 2004-2021 Klaas Freitag" #. type: Plain text #: kraft.adoc:952 #, fuzzy #| msgid "Documentation copyright 2020 Ronald Stroethoff" msgid "Documentation copyright 2020-2023 Ronald Stroethoff" msgstr "Dokumentation Copyright 2020 Ronald Stroethoff" #~ msgid "```" #~ msgstr "```" #, fuzzy, no-wrap #~ msgid "Template " #~ msgstr "Textvorlagen" #, fuzzy, no-wrap #~ msgid "Material " #~ msgstr "Material" #, fuzzy #~ msgid "btn:[Show templates]. " #~ msgstr "Textvorlagen" #~ msgid "" #~ "image:numbercycles.png[Numbercycles,float=\"right\"] Numbercycles are " #~ "used to define the *document number* which is printed on every document. " #~ "The document number is an important unique identifier of the document and " #~ "often must follow regulations." #~ msgstr "" #~ "image:numbercycles.png[Numbercycles,float=\"right\"] Nummernkreise werden " #~ "zur Definition der *Dokumentnummern* benötigt, die auf jedem Dokument " #~ "gedruckt wird. Die Dokumentnummer ist eine wichtige und eindeutige " #~ "Kennzahl des Dokuments und muss Regularien gehorchen." #~ msgid "" #~ "Different document types can use the same number cycle to generate ids " #~ "from. Number cycles are identified by their name. User can create new " #~ "number cycles and edit them clicking on the button btn:[Edit Number " #~ "Cycles...]" #~ msgstr "" #~ "Verschiedene Dokumenttypen können die selben Nummernkreise verwenden um " #~ "Ids aus ihnen zu generieren. Nummernkreise werden durch ihren Namen " #~ "identifiziert. Benutzer können neue Nummernkreise anlegen und sie durch " #~ "Klicken auf btn:[Nummernkreise bearbeiten...] bearbeiten" #~ msgid "" #~ "Kraft is designed to use the data entries from the KDE address book which " #~ "is a module of the https://community.kde.org/KDE_PIM[KDE PIM], an " #~ "information management application. All addresses are collected in the " #~ "https://userbase.kde.org/KAddressBook[KAdressBook]." #~ msgstr "" #~ "Kraft arbeitet mit den Adressdaten aus dem KDE Adressbuch, das ein Modul " #~ "von https://community.kde.org/KDE_PIM[KDE PIM], einer Informations-" #~ "Management-Anwendung ist. Alle Adressen werden in der Anwendung https://" #~ "userbase.kde.org/KAddressBook[KAdressBook] gesammelt." #~ msgid "Features" #~ msgstr "Funktionen" kraft-1.1/manual/po/kraft-nl.po000066400000000000000000003022721450127457600164540ustar00rootroot00000000000000# Copyright (C) 2022 Free Software Foundation, Inc. # This file is distributed under the same license as the KRAFT package. # # Ronald Stroethoff , 2022. msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: 2023-09-12 14:32+0200\n" "PO-Revision-Date: 2022-09-17 08:44+0200\n" "Last-Translator: Ronald Stroethoff \n" "Language-Team: Dutch \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Lokalize 21.12.3\n" #. type: Title = #: kraft.adoc:1 #, no-wrap msgid "The Kraft Handbook" msgstr "Het handboek van Kraft" #. type: Plain text #: kraft.adoc:3 msgid "Ronald Stroethoff, Klaas Freitag" msgstr "Ronald Stroethoff, Klaas Freitag" #. type: Title == #: kraft.adoc:16 #, no-wrap msgid "Introduction" msgstr "Inleiding" #. type: Plain text #: kraft.adoc:19 msgid "" "Kraft is a Qt and KDE application to organize office documents like quotes " "and invoices in a small business. It eases the creation of documents and " "helps with repeating tasks." msgstr "" "Kraft is een Qt- en KDE-Programma voor het organiseren van kantoor " "documenten zoals offertes en rekeningen in een klein bedrijf. Het " "vergemakkelijkt de creatie van documenten en helpt bij vaak voorkomende " "taken." #. type: Plain text #: kraft.adoc:21 msgid "" "Using Kraft, there is no need for fiddling with a text processor any more. " "Documents are created by a few clicks, edited, generated and archived " "automatically. Kraft generates high quality PDF output for printing, mailing " "and archiving." msgstr "" "Met gebruik van Kraft is geen tekstverwerker meer nodig. Rekeningen en " "offertes stelt u met slechts een paar muisklikken samen en worden " "automatisch gearchiveerd. Kraft genereert kwalitatief goede PDF-documenten " "geschikt om uit te printen, voor email en voor archivering." #. type: Labeled list #: kraft.adoc:22 #, no-wrap msgid "Feature Overview" msgstr "Overzicht van de mogelijkheden" #. type: Plain text #: kraft.adoc:25 msgid "Simple creation of offers, invoices and similar documents." msgstr "" "De eenvoudige creatie van offertes, rekeningen en vergelijkbare documenten." #. type: Plain text #: kraft.adoc:26 msgid "" "Customer management, deeply integrated with the mature KDE KAddressbook." msgstr "" "Beheer van klanten, door het gebruik van KAddressbook in de KDE-" "infrastructuur geïntegreerd." #. type: Plain text #: kraft.adoc:27 msgid "Maintenance of document relations, ie. Partial invoices vs. invoices." msgstr "" "Beheer van relaties tussen documenten, bv. Partial invoices (Gedeeltelijke " "factuur) ten opzichte van invoices (rekening)." #. type: Plain text #: kraft.adoc:28 msgid "Templates for document header- and footertexts and for document items." msgstr "Sjablonen voor kop- en voetteksten maar ook voor document-items." #. type: Plain text #: kraft.adoc:29 msgid "Pre calculation of item prices." msgstr "De voorcalculatie van prijzen." #. type: Plain text #: kraft.adoc:30 msgid "Material management." msgstr "Materiaalgebruik" #. type: Plain text #: kraft.adoc:31 msgid "Configurable document creation in PDF format for print and email." msgstr "" "Instelbare aanmaak van documenten in PDF Formaat voor uitprinten en " "verzenden per Email." #. type: Plain text #: kraft.adoc:33 msgid "" "The code of Kraft is open source and is released under the https://en." "wikipedia.org/wiki/GNU_General_Public_License[GNU General Public License]." msgstr "" "De broncode van Kraft is open source en wordt onder de licentie https://en." "wikipedia.org/wiki/GNU_General_Public_License[GNU General Public License] " "vrij gegeven." #. type: Plain text #: kraft.adoc:38 #, no-wrap msgid "" "Kraft is driven by community of users, coders, artists and others by voluntary work. +\n" "Also this manual needs contributions! +\n" " +\n" " Learn more on https://github.com/dragotin/kraft/blob/master/manual/Readme.md[how to contribute]!\n" msgstr "" "Kraft wordt door een gemeenschap van gebruikers, programmeurs artiesten en anderen vrijwilligers gedragen. +\n" "Ook dit gebruikershandboek heeft uw hulp nodig om verbeterd te worden. +\n" " +\n" "Lees hier https://github.com/dragotin/kraft/blob/master/manual/Readme.md[hier]over hoe u kan bijdragen\n" #. type: Title == #: kraft.adoc:40 #, no-wrap msgid "First Use and Basic Configuration" msgstr "Eerste gebruik en basisconfiguratie" #. type: Plain text #: kraft.adoc:43 msgid "" "When Kraft is started for the first time, it automatically enters the " "initial setup process." msgstr "" "Als Kraft voor de eerste keer wordt opgestart, dan komt het automatisch in " "een initiële proces voor het maken van instellingen terecht." #. type: Plain text #: kraft.adoc:45 msgid "" "During the initial setup you are asked to select a database to use and give " "the name and address of your company." msgstr "" "Tijdens de basisconfiguratie wordt u gevraagd om een database-type te " "selecteren en wordt naar de naam en adres van uw firma gevraagd." #. type: Plain text #: kraft.adoc:47 msgid "" "You can fill in your company address (that appears on the printed documents) " "in two ways: in the setup procedure use the first tab *Select from " "Addressbook* for to select your on address in KAddressBook (if you have " "filled your own address in KaddressBook) or use the second tab *Manual " "entry* for to fill in the information of the address from your company " "manually. This step is necessary for the correct generation of your " "documents as the address is automatically used in the document generation " "step." msgstr "" "Het adres van uw eigen bedrijf, die automatisch op het uitgeprinte document " "verschijnt, kan op twee manieren opgegeven worden: Bij het eerste gebruik: " "gebruik in de basisconfiguratie de eerste tab 'Uit adresboek' om in " "KAdressbook uw eigen adres te selecteren (als u in KAdressbook uw eigen " "adres heeft ingevuld) of u gebruikt de tweede tab 'Handmatige adres' om " "handmatig de informatie van uw bedrijf in te vullen. Deze stap is " "noodzakelijk voor de correcte aanmaak van uw documenten, omdat het " "automatisch wordt gebruikt in het proces voor de generatie van het document." #. type: Plain text #: kraft.adoc:49 msgid "image:company_adress1.png[Company adress,float=\"right\"]" msgstr "image:company_adress1.png[Company adress,float=\"right\"]" #. type: Plain text #: kraft.adoc:52 msgid "" "After the initial setup, select menu:Preferences[Settings]. That allows to " "prepare Kraft correctly so it can be used in a proper way." msgstr "" "Na de basisconfiguratie, selecteert u menu:Voorkeuren[Instellingen]. Hier " "kunt u Kraft correct voorbereiden zodat het op de juiste manier gebruikt kan " "worden." #. type: Plain text #: kraft.adoc:54 msgid "In the Preferences dialog we have the tabs:" msgstr "In het dialoogvenster voor de instellingen hebben we de tabs:" #. type: Plain text #: kraft.adoc:61 #, no-wrap msgid "" " *Document Defaults\n" " *Taxes\n" " *Documunt Types\n" " *Wages\n" " *Units\n" " *Own identity\n" msgstr "" " *Standaarddocument\n" " *Belastingen\n" " *Dokumenttypes\n" " *Salarissen\n" " *Eenheden\n" " *Uw eigen identiteit\n" #. type: Plain text #: kraft.adoc:63 msgid "" "Each of the tabs allows to enter useful values for the specific use case." msgstr "" "In elke tab is het mogelijk om voor uw specifieke geval realistische waarden " "in te voeren." #. type: Title === #: kraft.adoc:64 #, no-wrap msgid "Document Types" msgstr "Document typen" #. type: Plain text #: kraft.adoc:67 msgid "At the first use you find a list of different document types, such as:" msgstr "" "Bij het eerste gebruik vindt u een lijst met verschillende documenttypes, " "zoals:" #. type: Plain text #: kraft.adoc:69 msgid "Acceptance of order" msgstr "Acceptance of order (opdrachtbevestiging)" #. type: Plain text #: kraft.adoc:70 msgid "Delivery receipt" msgstr "Delivery receipt (afleverbon)" #. type: Plain text #: kraft.adoc:71 msgid "Invoice" msgstr "Invoice (rekening)" #. type: Plain text #: kraft.adoc:72 msgid "Offer" msgstr "Offer (offerte)" #. type: Plain text #: kraft.adoc:74 msgid "image:documentype.png[Document type,float=\"right\"]" msgstr "image:documentype.png[Document type,float=\"right\"]" #. type: Plain text #: kraft.adoc:77 msgid "" "Translate this types to your own language. You can also add new ones and " "remove document types you wont use." msgstr "" "Vertaal deze typen naar uw eigen taal. U kan ook nieuwe documenten toevoegen " "en documenten verwijderen waarvan u denkt dat u die niet zal gebruiken." #. type: Title ==== #: kraft.adoc:78 #, no-wrap msgid "Numbercycles" msgstr "Uniek documentnummer" #. type: Plain text #: kraft.adoc:82 msgid "" "image:numbercycles.png[Numbercycles,float=\"right\"] Each document has to " "have an unique identifier that identifies the document. There must not be " "two documents in Kraft with the same identifier." msgstr "" "image:numbercycles.png[Numbercycles,float=\"right\"] Elk document moet een " "uniek identificatie hebben die het document identificeert. Er mogen in Kraft " "geen twee documenten aanwezig zijn met dezelfde identificatie." #. type: Plain text #: kraft.adoc:85 msgid "" "The format of the identifier is configuratable in Kraft. For that, Kraft has " "a concept of so called number cycles. Number cycles are used to define the " "form of the *document number* which is printed on every document." msgstr "" "De opbouw van het identificatie is in Kraft instelbaar. Hiervoor heeft Kraft " "het concept van zogeheten volgnummers. Volgnummers worden gebruikt om de " "opbouw van het *documentnummer* te definiëren dat op elk document wordt " "geprint." #. type: Plain text #: kraft.adoc:89 msgid "" "All documents of a certain type have identifiers taken out of one number " "cycle. Each document type has a number cycle assigned. Different document " "types can use the same number cycle to generate ids from. That way, for " "example the document types Invoice and Final Invoice can use numbers from " "the same number cycle, even thought they are different document types in " "Kraft. Number cycles are identified by their name. User can create new " "number cycles and edit them clicking on the button btn:[Edit Number " "Cycles...]" msgstr "" "Alle documenten van een bepaald type hebben een identificatie die uit een " "één volgnummersysteem komen. Aan elk documenttype is een volgnummersysteem " "gekoppeld. Verschillende documenttypes kunnen hetzelfde volgnummersysteem " "gebruiken om hun identificatie uit te generen. Op die manier kunnen " "bijvoorbeeld de documenttypes Invoice (rekening) en Final Invoice " "(eindafrekening) nummers uit dezelfde volgnummersysteem gebruiken, terwijl " "ze in Kraft verschillende documenttypes zijn. Volgnummersystemen worden " "geïdentificeerd door hun naam. Gebruikers kunnen nieuwe volgnummersystemen " "creëren en deze bewerken door op de knop btn:[Volgnummersysteem bewerken...] " "te klikken" #. type: Plain text #: kraft.adoc:91 msgid "" "The format of the document numbers are defined by a template that can " "contain normal, fixed characters and also some variables that are replaced " "by the respective values when the document is created." msgstr "" "De opbouw van de documentnummers worden gedefinieerd in een sjabloon waarin " "normale, vaste karakters maar ook enkele variabelen aanwezig kunnen zijn die " "worden vervangen door hun respectievelijke waarden bij de creatie van het " "document." #. type: Plain text #: kraft.adoc:94 msgid "" "Each identifier needs to be unique, and thus has to contain a counter. Kraft " "supports two types of counter: One (variable `%i`) is incremented globally " "for every new document. The other (variable `%n`) is reset every day and " "starts at 1 again on every new day. In addition to the counter, more " "information can be added to the template form an useful number. Examples are " "a constant text or parts of the date." msgstr "" "Elk documentnummer moet uniek zijn, en moet dus een teller hebben. Kraft kan " "twee soorten tellers gebruiken: Een type (variabele `%i`) wordt bij elk " "nieuw document verhoogt. De andere (variabele `%n`) wordt elke dag " "teruggezet en begint dus weer bij 1 op elke nieuwe dag. Behalve de teller " "kan extra informatie toegevoegd worden om een bruikbaar documentnummer te " "krijgen, zoals een constante tekst of gedeeltes van de datum." #. type: Plain text #: kraft.adoc:96 msgid "" "The default numbercycle delivered with Kraft contains the year, the month " "and a serialnumber. That way you can compare offers or orders from last year " "with this year or the month April of last year with the month April of this " "year and get on this way an impression from the results of your business." msgstr "" "Het standaard volgnummersysteem dat met Kraft wordt geleverd bevat het jaar, " "de maand en een serienummer. Op deze manier kunt u offertes of opdrachten " "van het vorige jaar vergelijken met die van dit jaar of van de maand April " "van het vorige jaar met de maand April van dit jaar en op die manier een " "indruk krijgen van de resultaten van uw bedrijf." #. type: Plain text #: kraft.adoc:98 msgid "See the following table for available variables which can be used:" msgstr "" "Zie de volgende tabel voor de beschikbare variabelen die gebruikt kunnen " "worden:" #. type: Table #: kraft.adoc:115 #, no-wrap msgid "" "| `%y` or `%yyyy` | the year of the document date.\n" "| `%yy` | the year of the document (two digits).\n" "| `%w` | the week number of the document date.\n" "| `%ww` | the week number of the document date with leading zero.\n" "| `%d` | the day number of the document date.\n" "| `%dd` | the day number of the document date with leading zero.\n" "| `%m` or `%M` | the month number of the document date.\n" "| `%MM` | the month number with leading zero.\n" "| `%c` | the customer id from kaddressbook\n" "| `%type` | the localised doc type (offer, invoice etc.)\n" "| `%uid` | the contact id of the client.\n" "| `%i` .. `%iiiiii`| the unique counter\n" "| `%n` .. `%nnnnnn`| the unique day counter (combine with date)\n" "\n" msgstr "" "| `%y` of `%yyyy` | het jaar van de documentdatum.\n" "| `%yy` | het jaar van de documentdatum (twee cijfers).\n" "| `%w` | het weeknummer van de documentdatum.\n" "| `%ww` | het weeknummer van het documentdatum met een nul (twee cijfers).\n" "| `%d` | de dag van de week als getal van de documentdatum.\n" "| `%dd` | de dag van de week als getal van het documentdatum met een nul (wee cijfers).\n" "| `%m` of `%M` | de maand van het documentdatum als getal.\n" "| `%MM` | de maand van het documentdatum als getal met een nul (twee cijfers).\n" "| `%c` | de ID van de klant in het kaddressbook\n" "| `%type` | het vertaalde doc type (offerte, rekening enz.)\n" "| `%uid` | het contact id van de klant.\n" " |`%i` .. `%iiiiii`| de unieke teller *(verplicht)*\n" "| `%n` .. `%nnnnnn`| de unieke dagteller (te combineren met de datum)\n" "\n" #. type: Plain text #: kraft.adoc:118 msgid "" "A number cycle template needs to contain either `%i` or `%n`, if not, `%i` " "is appended automatically." msgstr "" "In een volgnummersysteem-sjabloon moet naar keuze `%i` of `%n` aanwezig " "zijn, als dat niet het geval is dan wordt automatisch `%i` eraan toegevoegd." #. type: Plain text #: kraft.adoc:120 msgid "" "Both `%i` and `%n` are numeric values. They can also be padded with with " "leading zeros. The length is defined by the number of i's or n's put into " "the template. For example, if a daily counter with length of three and " "leading zeros is desired, `%nnn` has to be put into the template. This works " "up to a length of six characters." msgstr "" "Zowel `%i` als `%n` hebben numerieke waarden. Ze kunnen ook worden " "voorafgegaan door extra nullen. De length is afhankelijk van het aantal i's " "of n's die in het sjabloon voorkomen. Bijvoorbeeld, als u een dagelijkse " "teller met een lengte van drie cijfers en voorloop nullen wenst, dan moet u " "`%nnn` in de sjabloon plaatsen. Dit werkt tot een lengte van zes karakters." #. type: delimited block _ #: kraft.adoc:123 msgid "" "NOTE: The \"design\" of the numbercycles and document numbers is very " "important. With the flexible system of templating Kraft can not prevent " "invalid number cycles. It is in the responsibility of the user." msgstr "" "Opmerking: het \"ontwerp\" van het volgnummersysteem en documentnummers is " "erg belangrijk. Door het flexibele systeem van sjablonen in Kraft kan niet " "ongeldige volgnummersystemen voorkomen. Dit is de verantwoordelijkheid van " "de gebruiker." #. type: Title ==== #: kraft.adoc:125 #, fuzzy, no-wrap #| msgid "Template" msgid "PDF Template" msgstr "Sjabloon" #. type: Plain text #: kraft.adoc:128 msgid "" "In the entry field Template File: the user can select a custom template for " "this specific document type." msgstr "" #. type: Plain text #: kraft.adoc:130 msgid "" "If the file extension of the template file is `.trml`, the ReportLab based " "document converter is used. If the file extension is `.gtmpl`, Kraft " "automatically uses the Weasyprint based converter." msgstr "" #. type: delimited block _ #: kraft.adoc:133 msgid "" "NOTE: The ReportLab system for PDF creation is deprecated in Kraft. Please, " "for new templates, always use Grantlee- and Weasyprint based templates." msgstr "" #. type: Title ==== #: kraft.adoc:135 #, no-wrap msgid "PDF Postprocessing" msgstr "" #. type: Plain text #: kraft.adoc:138 msgid "" "After Kraft has created the PDF document it is possible to merge the created " "PDF with static, customized PDFs created by the user. With that, it is easy " "to add a custom stationery with a logo to the resulting PDF (\"Watermark\")." msgstr "" #. type: Plain text #: kraft.adoc:140 msgid "" "The static PDFs should have the same page size as the generated documents. " "Keep in mind to use optimized images for logos etc. to not blow up the size " "of the result document." msgstr "" #. type: Plain text #: kraft.adoc:142 #, fuzzy #| msgid "image:followup_1.png[Folloup document,float=\"right\"]" msgid "image:pdfpostproc.png[PDF Postprocessing,float?\"right\"]" msgstr "image:followup_1.png[Folloup document,float=\"right\"]" #. type: Plain text #: kraft.adoc:144 msgid "The watermark options are:" msgstr "" #. type: Plain text #: kraft.adoc:146 #, no-wrap msgid "*No Watermark*: No watermark is created\n" msgstr "" #. type: Plain text #: kraft.adoc:147 #, no-wrap msgid "*On first page*: The first page of the watermark.pdf is merged with the first page of the result document\n" msgstr "" #. type: Plain text #: kraft.adoc:148 #, no-wrap msgid "*Watermark on all pages*: Merges the first page of the watermark PDF to all pages of the result document\n" msgstr "" #. type: Plain text #: kraft.adoc:149 #, no-wrap msgid "*alternating*: For this, the watermark PDF needs to have three pages. The first page is merged to the first page of the result document, the second and third page are alternated merge to subsequent pages.\n" msgstr "" #. type: Plain text #: kraft.adoc:150 #, no-wrap msgid "*different first and last page*: the PDF needs to have three pages. The first page is merged to the first page of the result document, the third page to the last, and the second to all page between first and last page.\n" msgstr "" #. type: Plain text #: kraft.adoc:152 msgid "" "If there is another static PDF document put into the entry field \"Append " "PDF:\", it is appended to the generated PDF. With that, Kraft will " "automatically add for example terms and conditions documents to the final " "document." msgstr "" #. type: Title === #: kraft.adoc:153 #, no-wrap msgid "Taxes" msgstr "Belastingen" #. type: Plain text #: kraft.adoc:157 msgid "" "image:taxes.png[Taxes,float=\"right\"] In many countries there are two kinds " "of VAT-taxes for sold products." msgstr "" "image:taxes.png[Taxes,float=\"right\"] In veel landen zijn er twee BTW-" "tarieven voor verkochte producten." #. type: Plain text #: kraft.adoc:160 msgid "A high level and a low level." msgstr "Een hoog tarief en een laag tarief." #. type: Plain text #: kraft.adoc:163 msgid "" "Fill here the appropriate amounts in for the high level and the low level. " "If the tax-level is changing, then you add here the start date with the new " "tax-levels." msgstr "" "Geef hier de toepasselijke waarden op voor het hoge tarief en voor het lage " "tarief. Als het belastingtarief wijzigt, dan kunt u hier de startdatum met " "de nieuwe belastingtarieven toevoegen." #. type: Title === #: kraft.adoc:164 #, no-wrap msgid "Wages" msgstr "Salarissen" #. type: Plain text #: kraft.adoc:169 msgid "" "image:wages.png[Wages,float=\"right\"] A list of wage costs is maintained in " "Kraft. The items are used in templates and during calculation." msgstr "" "image:wages.png[Wages,float=\"right\"] In Kraft is een lijst met " "salariskosten aanwezig. De items daarin worden in de sjablonen en in de " "berekeningen gebruikt." #. type: Plain text #: kraft.adoc:172 msgid "" "All data can be edited, customized and new items can be added in the Kraft " "Configuration Dialog reachable through the Settings menu." msgstr "" "Alle data kan bewerkt en aangepast worden in een configuratiedialoog dat u " "kunt bereiken via het menu-item 'voorkeuren', waar u ook nieuwe items kunt " "toevoegen ." #. type: Plain text #: kraft.adoc:176 msgid "" "Remember that these units are later used in the documents, it is therefor " "important that you translate them to your own language and to fill in the " "correct prices." msgstr "" "Vergeet niet dat deze items later worden gebruikt in de documenten, het is " "daarom belangrijk dat u ze vertaalt naar uw eigen taal en dat u de correcte " "bedragen invult." #. type: Title === #: kraft.adoc:177 #, no-wrap msgid "Units of measurement" msgstr "Eenheden" #. type: Plain text #: kraft.adoc:182 msgid "" "image:unity.png[Units of measurement,float=\"right\"] A list of units of " "measurement is maintained in Kraft. In Kraft Configuration Dialog reachable " "through the Settings menu can you edit and customize items already in the " "list, and also can you add new items to the list." msgstr "" "image:unity.png[Units of measurement,float=\"right\"] In Kraft is een " "verzameling eenheden aanwezig. In het configuratiedialoog die u kunt " "bereiken via het menu-item 'Voorkeuren' kunt u de items die al aanwezig zijn " "bewerken, maar u kunt ook nieuwe items toevoegen." #. type: Plain text #: kraft.adoc:185 msgid "" "Remember that these units are later used in the documents, it is therefor " "important that you translate them to your own language." msgstr "" "Vergeet niet dat deze eenheden later worden gebruikt in de documenten, het " "is daarom belangrijk dat u ze vertaalt naar uw eigen taal." #. type: Title === #: kraft.adoc:186 #, no-wrap msgid "Own identity" msgstr "Uw eigen identiteit" #. type: Plain text #: kraft.adoc:190 msgid "" "Check here if the information that you have given during the initial setup " "is correct for the use in the documents." msgstr "" "Controleer hier of de informatie die u heeft opgegeven tijdens de " "basisconfiguratie correct is voor het gebruik in de documenten." #. type: delimited block _ #: kraft.adoc:195 msgid "" "WARNING: If you made the choice to use the information from KaddressBook " "then is the information from a later manual entry ignored." msgstr "" "Pas op: Als u de keuze heeft gemaakt om de informatie in Kaddressbook te " "gebruiken dan wordt de informatie die u handmatig toevoegt genegeerd." #. type: Plain text #: kraft.adoc:199 msgid "" "After we have made some corrections to the configuration, we go back to the " "main window.Here we see three tabs:" msgstr "" "Nadat we indien nodig de gewenste correcties in de configuratie hebben " "aangebracht, gaan we terug naar het hoofdvenster. Hier zien we drie tabs:" #. type: Plain text #: kraft.adoc:201 msgid "Documents" msgstr "Documenten" #. type: Plain text #: kraft.adoc:202 msgid "Timeline" msgstr "Tijdlijn" #. type: Title == #: kraft.adoc:203 kraft.adoc:205 #, no-wrap msgid "Catalogs" msgstr "Catalogi" #. type: Plain text #: kraft.adoc:208 msgid "" "Kraft supports so called Catalogs in which templates for document items are " "kept. With the catalogs creating documents can be significantly accellerated " "in the day to day business. When creating new documents, the items templates " "from the catalogs can easily selected and moved over to the document." msgstr "" "Kraft gebruikt zogeheten Catalogi waarin sjablonen voor document items " "worden bewaard. Door de catalogi te gebruiken kan in het dagelijks gebruik " "het creëren van documenten significant worden versneld. Tijdens de creatie " "van nieuwe documenten, kunt u in de catalogi de items-sjablonen eenvoudig " "selecteren en naar het document verplaatsen." #. type: Plain text #: kraft.adoc:210 msgid "" "Since templates are organized in chapters entire documents can be prepared " "in different chapters to be used as template documents." msgstr "" "Omdat sjablonen worden georganiseerd in mappen, kunnen hele documenten " "worden voorbereid en opgeborgen in verschillende mappen om later als " "documentsjabloon te worden gebruikt." #. type: Plain text #: kraft.adoc:212 msgid "" "Of course the items in the documents can be edited after they got picked " "from a catalog." msgstr "" "Uiteraard kunnen de items in de documenten worden bewerkt nadat ze in een " "catalogus zijn geselecteerd." #. type: Plain text #: kraft.adoc:214 msgid "By default Kraft comes with two different catalogs:" msgstr "Kraft komt standaard met twee verschillende catalogi:" #. type: Plain text #: kraft.adoc:216 msgid "`Material`" msgstr "`Material`" #. type: Plain text #: kraft.adoc:219 msgid "" "A catalog of material that are sold, with their purchase prices, the profit " "and the sell-price." msgstr "" "Een catalogus met materialen die worden verkocht, met hun inkoopprijs, de " "winst en hun verkoopprijs." #. type: Plain text #: kraft.adoc:221 msgid "and `Standard Templates`" msgstr "en `Standard Templates`" #. type: Plain text #: kraft.adoc:223 msgid "A catalog of standard recipes of work like planting trees." msgstr "" "Een catalogus met standaard recepten voor werkzaamheden zoals het planten " "van bomen." #. type: Plain text #: kraft.adoc:226 msgid "" "Both catalogs can have chapters and sub-chapters for to organize your " "templates. First we are going to fill in the" msgstr "" "Beide catalogussen kunnen mappen en submappen hebben om daar uw sjablonen in " "op te bergen . Eerst gaan we gegevens toevoegen aan de " #. type: Title === #: kraft.adoc:227 #, no-wrap msgid "Material Catalog" msgstr "Materiaalcatalogus" #. type: Plain text #: kraft.adoc:232 msgid "" "A catalog of material that are sold, with their purchase prices, the profit " "and the sell-price. First we are going to add new chapters and subchapters." msgstr "" "Een catalogus met materialen die worden verkocht, met hun inkoopprijs, de " "winst en hun verkoopprijs. Eerst gaan we nieuwe mappen en submappen " "toevoegen." #. type: Title ==== #: kraft.adoc:233 #, no-wrap msgid "New chapters" msgstr "Nieuwe mappen" #. type: Plain text #: kraft.adoc:237 msgid "" "Select with the mouse the column-name `material`, select now in the context-" "menu [Add a sub chapter]" msgstr "" "Selecteer met de muis de kolomnaam `material`, selecteer vervolgens in het " "contextmenu [Submap toevoegen]" #. type: Plain text #: kraft.adoc:239 msgid "and add an extra chapter like `Trees`" msgstr "en voeg een extra map zoals `Bomen` toe" #. type: Title ==== #: kraft.adoc:240 #, no-wrap msgid "New sub chapters" msgstr "Nieuwe submappen" #. type: Plain text #: kraft.adoc:248 msgid "" "We are going to ad sub chapters in the map `Trees`. Select with the mouse " "the name of the chapter where you like to add a subchapter, select now in " "the context-menu [Add a sub chapter] and ad an extra subchapters like `Loaf " "trees` and `needle trees`. After adding the extra chapters and subchapters " "for dividing the material, we are going to add the material themself." msgstr "" "We gaan nu submappen toevoegen aan de map `Bomen`. Selecteer met de muis de " "naam van de map waaraan u een submap wilt toevoegen, selecteer nu in het " "contextmenu [Submap toevoegen] en voeg extra submappen zoals `Bladbomen` en " "`Naaldbomen` toe. Nadat we extra mappen en submappen hebben toegevoegd om " "het materiaal onder te verdelen, gaan we het materiaal zelf toevoegen." #. type: Title ==== #: kraft.adoc:249 #, no-wrap msgid "New template" msgstr "Nieuw sjabloon" #. type: Plain text #: kraft.adoc:254 msgid "" "Select with the mouse the name of the sub-chapter or chapter where you like " "to add a material. Select the sub map Loaf trees and select now in the " "context-menu" msgstr "" "Selecteer met de muis de naam van de submap of map waarin u materiaal wilt " "toevoegen. Selecteer de submap bladbomen en selecteer nu in het contextmenu " "nieuw sjabloon." #. type: Plain text #: kraft.adoc:257 msgid "" "Add the extra materials `coconut tree`, `apple tree` and `pine-apple tree`." msgstr "" "Voeg de nieuwe bomen `kokosnoot-boom`, `appelboom` en `ananasboom` toe." #. type: Plain text #: kraft.adoc:259 msgid "Fill in the price that we have paid." msgstr "Vul de prijs in die we hebben betaald." #. type: Plain text #: kraft.adoc:261 msgid "Fill in the profit that we want to have on the material" msgstr "Vul de winst in die we willen hebben op het materiaal." #. type: Plain text #: kraft.adoc:263 msgid "And fill in how much is in a packet." msgstr "En vul in per hoeveel ze verpakt zijn." #. type: Plain text #: kraft.adoc:266 msgid "" "image:catalog_material.png[Material catalog,float=\"right\"] After this we " "add also in the map 'Wood' a item for a 'support pole' for later use with " "its price." msgstr "" "image:catalog_material.png[Material catalog,float=\"right\"] Hierna voegen " "we ook in de map 'Wood' een item toe voor 'boompaal' met zijn prijs voor " "later gebruik." #. type: Plain text #: kraft.adoc:268 msgid "Now we are going to:" msgstr "Nu gaan we naar:" #. type: Title === #: kraft.adoc:269 #, no-wrap msgid "Standard Templates" msgstr "Standard Templates" #. type: Plain text #: kraft.adoc:272 msgid "This is a catalog of standard recipes of work like:" msgstr "Dit is een catalogus met standaard recepten voor werkzaamheden zoals:" #. type: Plain text #: kraft.adoc:274 msgid "planting trees" msgstr "Bomen planten" #. type: Plain text #: kraft.adoc:275 msgid "cutting grass" msgstr "Gras maaien" #. type: Plain text #: kraft.adoc:276 msgid "transport costs" msgstr "Transportkosten" #. type: Plain text #: kraft.adoc:277 msgid "planting grass" msgstr "Graszoden leggen" #. type: Plain text #: kraft.adoc:278 msgid "sowing grass-seed" msgstr "Graszaad zaaien" #. type: Plain text #: kraft.adoc:280 msgid "We add here the standard work of planting a tree." msgstr "" "We gaan hier de standaard werkzaamheden voor het planten van een boom " "toevoegen." #. type: Plain text #: kraft.adoc:283 msgid "" "Select with the mouse the name of the chapter [Work] where you like to add " "the new template," msgstr "" "Selecteer met de muis de naam van de map [Work] waar u de nieuwe sjabloon " "aan wilt toevoegen," #. type: Plain text #: kraft.adoc:285 msgid "select now the context-menu [New template]" msgstr "selecteer nu in het contextmenu btn:[Nieuw sjabloon]" #. type: Plain text #: kraft.adoc:287 msgid "and the extra templates `Plant tree` and `cut grass`." msgstr "en voeg de extra sjablonen `Boom planten` en `Gras maaien` toe." #. type: Plain text #: kraft.adoc:289 msgid "After we made the new template, a window opens with 4 tabs:" msgstr "" "Nadat we de nieuwe sjabloon hebben aangemaakt, opent een venster met 4 tabs:" #. type: Title ==== #: kraft.adoc:291 kraft.adoc:297 #, no-wrap msgid "Template" msgstr "Sjabloon" #. type: Title ==== #: kraft.adoc:292 kraft.adoc:309 #, no-wrap msgid "Time calculation" msgstr "Post arbeid" #. type: Plain text #: kraft.adoc:293 msgid "Fix costs" msgstr "Vaste kosten" #. type: Title ==== #: kraft.adoc:294 kraft.adoc:346 #, no-wrap msgid "Material" msgstr "Materiaal" #. type: Plain text #: kraft.adoc:296 msgid "First we go to the tab:" msgstr "Eerst gaan we naar de tab:" #. type: Plain text #: kraft.adoc:301 msgid "" "We give here the name of the new standard template like `Plant tree` image:" "catalog_standard.png[Standard catalog,float=\"right\"]" msgstr "" "We geven hier de naam op van de nieuwe standaard sjabloon zoals `Boom " "planten` image:catalog_standard.png[Standard catalog,float=\"right\"]" #. type: delimited block _ #: kraft.adoc:304 msgid "WARNING: be careful, this name is later used in the invoice" msgstr "" "Pas op: wees voorzichtig, dit is de naam die later op de rekening komt." #. type: Plain text #: kraft.adoc:308 msgid "" "we select that this is per piece and that the margin is 8% and that the full " "VAT is applicable." msgstr "" "we stellen hier in dat het per stuk is en dat de winst 8% is en dat het hoge " "BTW-tarief van toepassing is." #. type: Plain text #: kraft.adoc:312 msgid "We fill here in a number of work with the time:" msgstr "We vullen hier een aantal werkzaamheden met hun tijd in:" #. type: Block title #: kraft.adoc:313 #, no-wrap msgid "Spent time" msgstr "Gebruikte tijd" #. type: Table #: kraft.adoc:320 #, no-wrap msgid "" "|Dig hole |32 min. |worker\n" "|Place tree |12 min. |worker\n" "|Fill hole |17 min. |worker\n" "|give water |5 min. |worker\n" msgstr "" "|Gat graven |32 min. |worker\n" "|Boom plaatsen |12 min. |worker\n" "|Gat opvullen |17 min. |worker\n" "|Water geven |5 min. |worker\n" #. type: Plain text #: kraft.adoc:324 msgid "" "The cost for worker which we have earlier filled in is now used. image:" "catalog_standard_work.png[Time calculation,float=\"right\"]" msgstr "" "De kosten voor een werknemer die we eerder hebben ingevuld worden nu " "gebruikt.image:catalog_standard_work.png[Time calculation,float=\"right\"]" #. type: delimited block _ #: kraft.adoc:328 msgid "" "NOTE: in the invoice we see later only Plant tree, we will not see the parts " "dig hole,place tree,fill hole,give water" msgstr "" "Opmerking: op de rekening zien we later alleen Boom planten, we zullen dan " "niet de onderdelen Gat graven, boom plaatsen, Gat opvullen, Water geven zien." #. type: Plain text #: kraft.adoc:331 msgid "Now we go to the tab" msgstr "We gaan nu naar de tab:" #. type: Title ==== #: kraft.adoc:332 #, no-wrap msgid "Fixed costs" msgstr "Vaste kosten" #. type: Plain text #: kraft.adoc:335 msgid "and fill in:" msgstr "en we vullen in:" #. type: Block title #: kraft.adoc:336 #, no-wrap msgid "Fixed item" msgstr "Vast item" #. type: Table #: kraft.adoc:340 #, no-wrap msgid "|Transportcost |35 euro |1 pcs.\n" msgstr "|Transportkosten |35 euro |1 pcs.\n" #. type: Plain text #: kraft.adoc:343 msgid "image:catalog_standard_fixed_cost.png[Fixed cost,float=\"right\"]" msgstr "image:catalog_standard_fixed_cost.png[Fixed cost,float=\"right\"]" #. type: Plain text #: kraft.adoc:345 msgid "After this we go to the tab:" msgstr "Hierna gaan we naar de tab:" #. type: Plain text #: kraft.adoc:350 msgid "" "Here we select btn:[next], after which the window [Add Material to " "Calculation] opens for a selection of material. We navigate to the map " "'wood' where we select the 'support pole'." msgstr "" "Hier kiezen we btn:[volgende], waarna het venster [Materiaal toevoegen aan " "Berekening] opent voor de selectie van materiaal. We gaan dan naar de map " "'wood' waar we de 'boompaal' selecteren." #. type: Block title #: kraft.adoc:351 #, no-wrap msgid "Used materials" msgstr "Gebruikte materialen" #. type: Table #: kraft.adoc:355 #, no-wrap msgid "|1 |support pole |3,5 euro\n" msgstr "|1 |boompaal |3,5 euro\n" #. type: Plain text #: kraft.adoc:358 msgid "image:catalog_standard_material.png[Material,float=\"right\"]" msgstr "image:catalog_standard_material.png[Material,float=\"right\"]" #. type: Plain text #: kraft.adoc:360 msgid "We go now back to the first tab template" msgstr "We gaan nu terug naar de eerste tab 'Sjabloon'" #. type: Plain text #: kraft.adoc:363 msgid "" "On the first tab [template], we can now see the overall cost per one unit" msgstr "" "In de eerste tab [Sjabloon], kunnen we nu de totale kosten per eenheid zien." #. type: Plain text #: kraft.adoc:366 msgid "" "Click on [OK] for saving the result or on [cancel] for discarding the result." msgstr "" "Klik op btn:[OK] om het resultaat op te slaan of op btn:[Annuleren] om het " "resultaat te verwijderen." #. type: Plain text #: kraft.adoc:368 msgid "We make a second template `cut grass`" msgstr "We maken een tweede sjabloon 'Gras maaien'." #. type: Plain text #: kraft.adoc:371 msgid "" "we fill in `cut grass`, as unit we choose sm (square meter), on the second " "tab we fill in that we need 3 min per square meter." msgstr "" "we vullen in `Gras maaien`, als eenheid kiezen we sm (square meter in het " "Engels) of m² (in het Nederlands), in de tweede tab vullen we in dat 3 min " "nodig hebben per vierkante meter." #. type: Plain text #: kraft.adoc:374 msgid "" "Click on [OK] for saving the result or on [Cancel] for discarding the result." msgstr "" "Klik op btn:[OK] om het resultaat op te slaan of op btn:[Annuleren] om het " "resultaat te verwijderen." #. type: Plain text #: kraft.adoc:376 msgid "'''" msgstr "" #. type: Title === #: kraft.adoc:377 #, no-wrap msgid "Header- and Footer Text Templates" msgstr "" #. type: Plain text #: kraft.adoc:380 msgid "" "Kraft supports text templates also for the header- and footer-text of " "documents. Each document type has it's own set of text templates. To access " "them, open a document of a certain document type in edit mode and use the " "btn:[show templates] to make the templates visible. In both the header- and " "footer-section the stored templates become visible." msgstr "" #. type: Plain text #: kraft.adoc:382 msgid "" "Directly under the navigation pane on the right side of the window is a list " "of the names of the available templates. Clicking on one of the names in the " "list displays the text in the pane below." msgstr "" #. type: Plain text #: kraft.adoc:384 msgid "" "Underneath there are buttons located with the following functions from left " "to right:" msgstr "" #. type: Plain text #: kraft.adoc:386 msgid "" "Add the template to the document: This button replaces the text of the " "document with the selected template." msgstr "" #. type: Plain text #: kraft.adoc:387 msgid "" "Insert the template to the document: The selected template is inserted to " "the current place of the cursor in the document." msgstr "" #. type: Plain text #: kraft.adoc:388 msgid "" "Create a new template: Opens a dialog to enter a complete new template for " "the current doc type." msgstr "" #. type: Plain text #: kraft.adoc:389 msgid "" "Edit the current template: Opens the dialog to edit the currently selected " "template." msgstr "" #. type: Plain text #: kraft.adoc:390 msgid "" "Delete the current template: Removes the template permanently from the list " "of available templates." msgstr "" #. type: Plain text #: kraft.adoc:392 msgid "" "Templates with the name _Standard_ are the default templates for the " "document type. They are inserted automatically if a document of this type is " "created." msgstr "" #. type: Title ==== #: kraft.adoc:394 #, no-wrap msgid "Macros" msgstr "" #. type: Plain text #: kraft.adoc:397 msgid "" "Both the header- and footer-templates can contain so called macros which are " "replaced with calculated values once the document is rendered to the final " "output format." msgstr "" #. type: Plain text #: kraft.adoc:399 msgid "The following list of macros are supported:" msgstr "" #. type: Plain text #: kraft.adoc:401 msgid "" "`DATE_ADD_DAYS()`: Returns the date of the of document plus the " "number of days specified as parameter to the macro." msgstr "" #. type: Plain text #: kraft.adoc:402 msgid "" "`ITEM_COUNT_WITH_TAG()`: Returns the amount of items tagged with the " "tag." msgstr "" #. type: Plain text #: kraft.adoc:403 msgid "" "`NETTO_SUM_PER_TAG()`: Returns the netto sum of all items that are " "tagged with the named tag." msgstr "" #. type: Plain text #: kraft.adoc:404 msgid "" "`BRUTTO_SUM_PER_TAG()`: Returns the brutto sum of all items that are " "tagged with the named tag." msgstr "" #. type: Plain text #: kraft.adoc:405 msgid "" "`VAT_SUM_PER_TAG()`: Returns the pure tax of all items that are tagged " "with the named tag." msgstr "" #. type: Plain text #: kraft.adoc:406 msgid "" "`IF_ANY_HAS_TAG()` and `END_HAS_TAG`: Includes the text between the two " "macros only if there is at least one item that is tagged with the tag." msgstr "" #. type: Plain text #: kraft.adoc:408 msgid "" "As an example, this footer text template can be used to automatically " "generate useful texts:" msgstr "" #. type: delimited block - #: kraft.adoc:411 #, no-wrap msgid "Please pay this invoice until three weeks after the date of the document, which is the DATE_ADD_DAYS(21).\n" msgstr "" #. type: delimited block - #: kraft.adoc:416 #, no-wrap msgid "" "IF_ANY_HAS_TAG(Material)\n" "This invoice lists material in ITEM_COUNT_WITH_TAG(Material) items. The net value is NETTO_SUM_PER_TAG(Material),\n" "plus VAT_SUM_PER_TAG(Material) = BRUTTO_SUM_PER_TAG(Material).\n" "END_HAS_TAG\n" msgstr "" #. type: Plain text #: kraft.adoc:419 msgid "We are now ready for the first invoice." msgstr "We zijn nu klaar voor de eerste rekening." #. type: Title == #: kraft.adoc:421 #, no-wrap msgid "Creating Documents" msgstr "De creatie van documenten" #. type: Title === #: kraft.adoc:423 #, no-wrap msgid "The first Invoice" msgstr "De eerste rekening" #. type: Plain text #: kraft.adoc:426 msgid "Open the tab btn:[documents]" msgstr "Open de tab btn:[Documenten]" #. type: Plain text #: kraft.adoc:428 kraft.adoc:533 msgid "Click on btn:[create document]" msgstr "Klik op btn:[Nieuw document]" #. type: Plain text #: kraft.adoc:430 msgid "The window document [creation wizard opens]." msgstr "Het document-venster [creation wizard] opent." #. type: Plain text #: kraft.adoc:432 msgid "Select in document type `invoice`." msgstr "Selecteer in document type `invoice` (rekening)." #. type: Plain text #: kraft.adoc:435 msgid "" "Fill in on the whiteboard content a short text about what the invoice is, " "like: `cut grass and planted tree for mister Jonson`" msgstr "" "Vul op het whiteboard een korte tekst over wat de rekening is, zoals: `gras " "maaien en boom planten voor de heer Jansen` ." #. type: Plain text #: kraft.adoc:437 kraft.adoc:542 msgid "Click on btn:[next]" msgstr "Klik op btn:[Volgende]" #. type: Plain text #: kraft.adoc:439 kraft.adoc:544 msgid "Select on the new window the name and address from the client." msgstr "Selecteer in het volgende venster de naam en adres van de klant." #. type: Plain text #: kraft.adoc:442 kraft.adoc:547 msgid "" "(if the name and address is not there, click then on btn:[new contact] or on " "btn:[edit contact] if you want to edit the contact)" msgstr "" "(Als de naam en adres niet aanwezig zijn, klik dan op btn:[nieuw " "contactpersoon] of op btn:[contactpersoon bewerken] als u het contact wilt " "bewerken)" #. type: Plain text #: kraft.adoc:444 kraft.adoc:549 msgid "Click on btn:[OK]." msgstr "Klik op btn:[OK]." #. type: Plain text #: kraft.adoc:446 msgid "Now opens the window document [items]." msgstr "Nu opent het venster document-items." #. type: Plain text #: kraft.adoc:448 msgid "this window has 2 tabs and the 3 buttons on the top:" msgstr "Dit venster heeft bovenaan 2 tabs en 3 knoppen:" #. type: Plain text #: kraft.adoc:450 kraft.adoc:555 msgid "btn:[Add item...]," msgstr "btn:[Item toevoegen...]," #. type: Plain text #: kraft.adoc:451 kraft.adoc:556 msgid "btn:[Add discount item]," msgstr "btn:[Korting geven]," #. type: Plain text #: kraft.adoc:452 kraft.adoc:557 msgid "btn:[Show templates]." msgstr "btn:[Document tonen]." #. type: Plain text #: kraft.adoc:456 msgid "" "In the left tab you can see all the items that we want to place on the " "invoice, on the right tab we see the text from the header, the total price " "and the footer." msgstr "" "Aan de linkerkant kunt u alle items zien die we op de rekening willen " "plaatsen, aan de rechterkant zien we de tekst van de koptekst, de totale " "prijs en de voettekst." #. type: Plain text #: kraft.adoc:460 msgid "" "If you click on the text of the header or the footer on the right side then " "the window changes in such a way that you can edit the header or the footer." msgstr "" "Als u op de tekst van de koptekst of van de voettekst aan de rechterkant " "klikt dan verandert het venster zodanig dat u de koptekst of de voettekst " "kan bewerken." #. type: Plain text #: kraft.adoc:463 msgid "" "Adapt the header and the footer to your situation, on the footer you can " "place a text: `We make your garden-dream come to reality.`." msgstr "" "Pas de koptekst en de voettekst aan naar uw situatie, in de voettekst kan u " "bijvoorbeeld een tekst plaatsen als: Wij maken uw tuindroom werkelijkheid." #. type: Plain text #: kraft.adoc:465 kraft.adoc:559 msgid "Click on the button btn:[Show templates]." msgstr "Klik op de knop btn:[Document tonen]." #. type: Plain text #: kraft.adoc:469 msgid "" "The right tab changes and show now the earlier made templates, we select in " "the group Work, the subgroup Plant tree and click then on the button with " "the to the left pointing arrow on the bottom side." msgstr "" "De rechter tab verandert en toont nu de eerder gemaakte sjablonen, we " "selecteren in de map 'Work', de submap 'Boom planten' en klikken op de knop " "met de naar links wijzende pijl aan de onderkant." #. type: Plain text #: kraft.adoc:471 kraft.adoc:565 msgid "A new window [Create Item from Template] opens." msgstr "Een nieuw venster [Item van sjabloon creëren] opent." #. type: Plain text #: kraft.adoc:474 msgid "" "Because we have planted 2 trees, we go to the field [insert] and change this " "to 2 pcs." msgstr "" "Omdat we 2 bomen hebben geplant, gaan we naar het veld [invoegen] en " "veranderen dit naar 2 pcs (in het Nederlands stk)." #. type: Plain text #: kraft.adoc:477 msgid "" "Click on btn:[OK] for saving the result or on btn:[cancel] for discarding " "the result." msgstr "" "Klik op btn:[OK] om het resultaat op te slaan of op btn:[Annuleren] om het " "resultaat te verwijderen." #. type: Plain text #: kraft.adoc:479 kraft.adoc:573 kraft.adoc:584 msgid "The window close and we go back to the main window." msgstr "Het venster sluit en we gaan terug naar het hoofdvenster." #. type: Plain text #: kraft.adoc:483 msgid "" "We click again on btn:[Show templates] and select this time `cut grass`, we " "click again on the button with the arrow, in the opened window we select " "that the grass-field was 24 square meter." msgstr "" "We klikken opnieuw op btn:[Document tonen] en selecteren deze keer `gras " "maaien`, we klikken opnieuw op de knop met de pijl, in het geopende venster " "stellen we in dat het grasveld 24 vierkante meter was." #. type: Plain text #: kraft.adoc:486 kraft.adoc:571 kraft.adoc:604 kraft.adoc:640 msgid "" "Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding " "the result." msgstr "" "Klik op btn:[OK] om het resultaat op te slaan of op btn:[Annuleren] om het " "resultaat te verwijderen." #. type: Plain text #: kraft.adoc:488 #, fuzzy #| msgid "" #| "We add now manually an item by clicking on the button btn:[Add item…] and " #| "the window [create new item] opens." msgid "" "We add now manually an item by clicking on the button btn:[Add item…] and " "the window [create new item] opens." msgstr "" "We voegen nu handmatig een item toe door te klikken op de knop btn:[Item " "toevoegen…] waarna het venster [Item creëren] opent." #. type: Plain text #: kraft.adoc:492 msgid "" "Because we have delivered a special tree, we fill here in the name of the " "special tree `liguster`, at the field insert we fill in the number of the " "special trees that we have delivered and the price of them." msgstr "" "Omdat we een speciale boom hebben geleverd, vullen we hier de naam van de " "speciale boom `liguster` in, in het veld invoegen vullen we het aantal van " "de speciale boom die we geleverd hebben in en de prijs daarvan." #. type: delimited block _ #: kraft.adoc:498 msgid "" "WARNING: Remind that in the catalog we can add a profit on the price of the " "material, in the invoice and in the offer we can not add a profit on the " "price of the material." msgstr "" "Pas op: verlies niet uit het oog dat we in de catalogus een winst op de " "prijs van het materiaal kunnen toevoegen, in de rekening en in de offerte " "kunnen we geen winst aan de prijs van het materiaal toevoegen." #. type: Plain text #: kraft.adoc:501 msgid "We have now an invoice with 3 items." msgstr "We hebben nu een rekening met 3 items." #. type: Plain text #: kraft.adoc:504 msgid "" "Click on btn:[OK] for saving the invoice or on btn:[Cancel] for discarding " "the invoice." msgstr "" "Klik op btn:[OK] om de rekening op te slaan of op btn:[Annuleren] om de " "rekening te verwijderen." #. type: Plain text #: kraft.adoc:506 msgid "We click on btn:[OK] and save the result." msgstr "We klikken op btn:[OK] en slaan het resultaat op." #. type: Plain text #: kraft.adoc:508 msgid "Your first invoice is now ready for sending." msgstr "Uw eerste rekening is nu klaar voor verzending." #. type: Plain text #: kraft.adoc:511 msgid "" "In the window documents we see our first invoice, notice that this document " "has a document number which we can see on the left side." msgstr "" "In het venster met documenten zien we onze eerste rekening, merk op dat dit " "document een documentnummer heeft die we aan de linkerkant zien." #. type: Plain text #: kraft.adoc:514 msgid "" "On top of the window with all the invoices we see the button [Print " "Document], on which we click." msgstr "" "Bovenaan het venster met alle rekeningen zien we de knop btn: [Print " "Document], waar we op klikken." #. type: Plain text #: kraft.adoc:517 msgid "" "From the invoice will now a PDF be made which we can print on paper or send " "by email to the client." msgstr "" "Van de rekening zal nu een PDF worden gemaakt die we op papier kunnen " "uitprinten of per email naar de klant kunnen versturen." #. type: Plain text #: kraft.adoc:519 msgid "After this we are going to create a offer for some work in a garden." msgstr "Hierna gaan we een offerte maken voor wat werk in een tuin." #. type: Title === #: kraft.adoc:521 #, no-wrap msgid "Creating an Offer" msgstr "Een offerte creëren" #. type: Plain text #: kraft.adoc:524 msgid "" "The client has asked to plant a tree, we will offer 3 different trees which " "we can plant." msgstr "" "De klant heeft gevraagd of we een boom kunnen planten, we bieden 3 " "verschillende bomen aan die we kunnen planten." #. type: Plain text #: kraft.adoc:527 msgid "" "Beside this, we have seen that there is a lifeless three, which we will " "offer to remove as extra work. image:create_new_doc.png[Numbercycles," "float=\"right\"]" msgstr "" "Daarnaast hebben we gezien dat er een dode boom is, waarvoor we een aanbod " "doen om deze als extra werk te verwijderen. image:create_new_doc." "png[Numbercycles,float=\"right\"]" #. type: Plain text #: kraft.adoc:529 msgid "" "For the total price we do not want to show the price of the removal of the " "lifeless tree and we want for the total price only to show the price of one " "tree and not three." msgstr "" "De totale prijs willen we exclusief de prijs voor de verwijdering van de " "dode boom en alleen de prijs van een boom en niet van drie bomen." #. type: Plain text #: kraft.adoc:531 msgid "Open again the tab btn:[documents]." msgstr "Open opnieuw de tab btn:[Documenten]." #. type: Plain text #: kraft.adoc:535 msgid "The window _Document Creation Wizard_ opens." msgstr "Het document-venster [creation wizard] opent." #. type: Plain text #: kraft.adoc:537 msgid "select in btn:[document type] > btn:[Offer]." msgstr "Selecteer in btn: [document type]>btn:[offer]." #. type: Plain text #: kraft.adoc:540 msgid "" "Fill in on the whiteboard content a short text about what the offer is, " "like: `plant one tree and removal of lifeless tree`" msgstr "" "Vul op het whiteboard een korte tekst over waarover de offerte gaat, zoals: " "`een boom planten en verwijding van dode boom` ." #. type: Plain text #: kraft.adoc:551 msgid "Now the window [edit document] opens." msgstr "Nu opent het venster [Document bewerken]." #. type: Plain text #: kraft.adoc:553 msgid "This window has 2 tabs and the 3 buttons on the top:" msgstr "Dit venster heeft bovenaan 2 tabs en 3 knoppen:" #. type: Plain text #: kraft.adoc:563 msgid "" "The right tab changes and show now the earlier made templates, we select in " "the group `Work`, the subgroup `Plant tree` and click then on the button " "with the to the left pointing arrow on the bottom side." msgstr "" "De rechter tab verandert en toont nu de eerder gemaakte sjablonen, we " "selecteren in de map 'Work', de submap 'Boom planten' en klikken op de knop " "met de naar links wijzende pijl aan de onderkant." #. type: Plain text #: kraft.adoc:568 msgid "" "Because we want to plant 1 tree, we go to the field [insert] and keep this " "on 1 pcs." msgstr "" "Omdat we 1 boom willen planten, gaan we naar het veld [invoegen] en houden " "dit op 1 pcs (in het Nederlands stk)." #. type: Plain text #: kraft.adoc:576 msgid "" "We click on the button btn:[Show templates] and this time we select in " "catalog Material" msgstr "" "We klikken op de knop btn:[Document tonen] en selecteren deze keer de " "catalogus Material." #. type: Plain text #: kraft.adoc:580 msgid "" "The material-catalog opens, and we can select in the chapter `trees` the " "subchapter `loaf trees` in which we select the `apple tree` which we made " "earlier." msgstr "" "De material-catalogus opent, en we kunnen in de map `Bomen` de submap " "`Bladbomen` selecteren waar we de `appelboom` selecteren die we eerder " "hebben gemaakt." #. type: Plain text #: kraft.adoc:582 msgid "" "Click on we btn:[OK] for saving the result or on btn:[cancel] for discarding " "the result." msgstr "" "Klik op btn:[OK] om het resultaat op te slaan of op btn:[Annuleren] om het " "resultaat te verwijderen." #. type: Plain text #: kraft.adoc:586 #, fuzzy #| msgid "We add now manually an item by clicking on the button `Add item…`." msgid "We add now manually an item by clicking on the button `Add item…`." msgstr "" "We voegen nu handmatig een item toe door te klikken op de knop `Item " "toevoegen...'." #. type: Plain text #: kraft.adoc:588 msgid "the window [create new item] opens." msgstr "Het venster [Nieuw item aanmaken] opent." #. type: Plain text #: kraft.adoc:590 msgid "" "We want that the client can make a choice from an apple, a pear tree and the " "liguster." msgstr "" "We willen dat de klant een keuze kan maken tussen een appelboom, een " "perenboom en de liguster." #. type: Plain text #: kraft.adoc:592 msgid "Therefor we are going to add also a pear tree manually." msgstr "Daarom gaan we een perenboom handmatig toevoegen." #. type: Plain text #: kraft.adoc:594 #, fuzzy #| msgid "" #| "We click on the button btn:[Add item…] and the window [create new item] " #| "opens." msgid "" "We click on the button btn:[Add item…] and the window [create new item] " "opens." msgstr "" "We klikken op de knop btn:[Item toevoegen…] waarna het venster [Item " "creëren] opent." #. type: Plain text #: kraft.adoc:598 msgid "" "We fill here in the name of the tree `Pear tree`, at the field insert we " "fill in the number of the special trees that we have delivered and the price " "of them." msgstr "" "We vullen hier de naam van de boom `Perenboom` in, en in veld invoegen " "vullen we het aantal van de speciale bomen in die we kunnen leveren en de " "prijs daarvan." #. type: Plain text #: kraft.adoc:601 msgid "" "We want add this to the material catalog for future use, therefor we select " "also [select this item as template for future documents] and we select in " "[save in chapter]`trees`." msgstr "" "We willen dit aan de materiaalcatalogus toevoegen voor toekomstig gebruik, " "daarom selecteren we ook [Dit item als sjabloon bewaren voor latere " "documenten] en selecteren we in btn:[opslaan in map] 'bomen'." #. type: Plain text #: kraft.adoc:606 msgid "We does this again but then for the liguster." msgstr "We doen dit ook voor de liguster." #. type: Plain text #: kraft.adoc:608 msgid "We have now 3 items with trees in the offer." msgstr "We hebben nu 3 items met bomen in de offerte." #. type: Plain text #: kraft.adoc:610 msgid "" "As last item we add an item with `remove tree` with 0,5 hour for 32 euro." msgstr "" "En tenslotte voegen we een item toe met 'boom verwijderen' met 0,5 uur voor " "32 euro." #. type: Plain text #: kraft.adoc:612 msgid "On the left side of an item we can see 2 buttons:" msgstr "Links van het item zien we 2 knoppen:" #. type: Plain text #: kraft.adoc:614 msgid "a button with a flag and a button with what looks like a page." msgstr "Een knop met een vlag en een knop met wat lijkt op een pagina." #. type: Plain text #: kraft.adoc:617 msgid "" "We select the upper button with the page after which opens a context-menu " "with the items:" msgstr "" "We selecteren de bovenste knop met de pagina waarna een contextmenu opent " "met de items:" #. type: Plain text #: kraft.adoc:619 msgid "image:context1.png[Context menu,float=\"right\"]" msgstr "image:context1.png[Context menu,float=\"right\"]" #. type: Plain text #: kraft.adoc:629 #, no-wrap msgid "" " [Item kind]->[Normal]\n" " [Item kind]>[Alternative]\n" " [Item kind]>[On demand]\n" " [Tax]\n" " [Move up]\n" " [Move down]\n" " [Lock item]\n" " [Unlock item]\n" " [Delete item]\n" msgstr "" " [ Soort item]->[Normaal]\n" " [Soort item]>[Alternatief]\n" " [Soort item]>[Op verzoek]\n" " [Belasting]\n" " [Omhoog verplaatsen]\n" " [Omlaag verplaatsen]\n" " [Item vastzetten]\n" " [Item ontgrendelen]\n" " [Verwijder item]\n" #. type: Plain text #: kraft.adoc:632 msgid "" "We choose here [Item kind] and change for `pear tree` from [normal] to " "[alternative]." msgstr "" "We selecteren hier [Soort item] en veranderen dit voor `perenboom` van " "[normaal] naar [alternatief]." #. type: Plain text #: kraft.adoc:635 msgid "" "We do this also for [liguster] and for [remove tree] we change this from " "[normal] to [on demand]." msgstr "" "We doen dit ook voor [liguster] en voor [Boom verwijderen] veranderen we dit " "van [normaal] naar [Op verzoek]." #. type: Plain text #: kraft.adoc:637 msgid "image:context2.png[Context menu,float=\"right\"]" msgstr "image:context2.png[Context menu,float=\"right\"]" #. type: Plain text #: kraft.adoc:643 msgid "" "We want to see the result and therefor we click on the button [show " "document]." msgstr "" "We willen het resultaat bekijken en daarom klikken we op de knop btn:" "[Document tonen]." #. type: Plain text #: kraft.adoc:649 msgid "" "We see now that the prize of the pear tree, the liguster and the removal of " "the tree is not used for the total prize. When we are happy with the result, " "we can click on the button btn:[close] after which we click on the button " "btn:[Print Document] for making a PDF what we can print out or send to the " "client." msgstr "" "We zien nu dat de prijs voor de perenboom, de liguster en het verwijderen " "van de boom niet is gebruikt voor de totale prijs. Als we tevreden zijn met " "het resultaat, dan klikken we op de knop btn:[OK] waarna we klikken op de " "knop btn:[Document afdrukken] voor het maken van een PDF die we kunnen " "uitprinten of naar de klant kunnen sturen." #. type: Plain text #: kraft.adoc:652 msgid "" "After your first invoice is now your first offer now also ready for sending." msgstr "" "Na uw eerste rekening is nu ook uw eerste offerte klaar voor verzending." #. type: Title === #: kraft.adoc:654 #, no-wrap msgid "Creating an Acceptance of Order" msgstr "Een Acceptance of order (opdrachtbevestiging) aanmaken" #. type: Plain text #: kraft.adoc:657 msgid "" "The document type \"Acceptance of Order\" is sent subsequently to an offer." msgstr "" "Het documenttype \"Acceptance of Order\" (opdrachtbevestiging) wordt " "verstuurd als vervolg op een offerte." #. type: Plain text #: kraft.adoc:659 msgid "image:acceptance_o_o_context.png[Numbercycles,float=\"right\"]" msgstr "image:acceptance_o_o_context.png[Numbercycles,float=\"right\"]" #. type: Plain text #: kraft.adoc:662 msgid "" "When a client has made a request, we will send an offer in wich we describe " "which items we will deliver. Hopefully the client will give an order for " "the work." msgstr "" "Als een klant een verzoek heeft gemaakt, dan zullen we een offer (offerte) " "sturen waarin we beschrijven welke items we zullen gaan leveren. Hopelijk " "zal de klant een order geven voor het werk." #. type: Plain text #: kraft.adoc:666 msgid "" "It is a good practice to respond on the order with an \"Acceptance of " "order\" in which we describe all the items we will deliver. We can make the " "\"Acceptance of order\" on the same way as we made the invoice or the offer " "by selecting each item and correcting the number of delivery. This takes " "time and we can make errors by forgetting items or filling an incorrect " "number." msgstr "" "Het is een goede gewoonte om op de order te reageren met een \"Acceptance of " "order\" (opdrachtbevestiging) waarin we alle items beschrijven die we zullen " "gaan leveren. We kunnen de \"Acceptance of order\" op dezelfde manier maken " "als waarmee we de invoice (rekening) of de offer (offerte)hebben gemaakt " "door elk item te selecteren en het aantal te leveren aan te passen. Dit kost " "tijd en we kunnen fouten maken door items te vergeten of een incorrect " "aantal in te vullen." #. type: Plain text #: kraft.adoc:668 msgid "" "It can be done quicker by selecting the offer in the list and selecting btn:" "[Create Followup Document] from either the context menu or the main menu." msgstr "" "U kunt dit sneller doen door de offer (offerte) in de lijst te selecteren en " "vervolgens btn:[Creëer opvolg document] in het context menu of in het " "hoofdmenu te selecteren." #. type: Plain text #: kraft.adoc:670 msgid "We have now in documenttype the choice from:" msgstr "We hebben nu als documenttype de keuze uit:" #. type: Plain text #: kraft.adoc:676 #, no-wrap msgid "" " [Acceptance of order]\n" " [Invoice]\n" " [Partial Invoice]\n" " [final Invoice]\n" " [Progress Payment Invoice]\n" msgstr "" " [Acceptance of order]\n" " [Invoice]\n" " [Partial Invoice]\n" " [final Invoice]\n" " [Progress Payment Invoice]\n" #. type: Plain text #: kraft.adoc:678 msgid "image:followup_1.png[Folloup document,float=\"right\"]" msgstr "image:followup_1.png[Folloup document,float=\"right\"]" #. type: Plain text #: kraft.adoc:682 msgid "" "We select here \"Acceptance of order\". We have now a copy from the offer " "as an Acceptance of order (do not forget to adapt Alternative Delivery items " "and on demand items.)" msgstr "" "We selecteren nu \"Acceptance of order\". We hebben nu een kopie van de " "offerte als een Acceptance of order (vergeet niet om de alternatief items en " "de op verzoek items aan te passen.)" #. type: Plain text #: kraft.adoc:684 msgid "image:followup_2.png[Folloup document,float=\"right\"]" msgstr "image:followup_2.png[Folloup document,float=\"right\"]" #. type: Plain text #: kraft.adoc:688 msgid "" "You can do this also for the creation of the invoice as a followup for " "Acceptance of order. Each document type has a specific list of follow up " "documents. It is a good practice to describe on the invoice precisely what " "was delivered." msgstr "" "U kunt dit ook doen voor de creatie van de invoice (rekening) als opvolging " "van de opdrachtbevestiging. Elk documenttype heeft een specifieke lijst met " "opvolg-documenten. Het is een goede gewoonte om op de rekening precies te " "omschrijven wat is geleverd." #. type: Title == #: kraft.adoc:690 #, no-wrap msgid "Customization" msgstr "Kraft naar wens aanpassen" #. type: Plain text #: kraft.adoc:694 msgid "" "Kraft can be customized in most of the graphical user interface and in " "particular in the output it generates." msgstr "" "Een groot gedeelte van de grafische interface van Kraft kan aangepast " "worden, met name de uitvoer die het genereert." #. type: Title === #: kraft.adoc:695 #, no-wrap msgid "Output Document Customization" msgstr "Documentuitvoer aanpassen" #. type: Plain text #: kraft.adoc:698 msgid "" "To create PDF output documents, the document data that was edited in the " "Kraft app is filled into a template. The template defines how the output " "document looks like, ie. by font settings, placing of elements and such." msgstr "" "Om PDF's te creëren, moet een sjabloon worden gevuld met de document data " "die in Kraft is gecreëerd. De sjabloon definieert hoe de het resulterende " "document eruit komt te zien, d.w.z de ingestelde lettertypes, de plaats van " "de elementen en dergelijke." #. type: Plain text #: kraft.adoc:700 msgid "" "The file that is assembled from data and the template is converted to PDF " "using a special document creation script. All that is started automatically " "by Kraft if a document should be printed." msgstr "" "Het bestand dat is samengesteld uit een combinatie van de data en de " "sjabloon wordt geconverteerd naar een PDF met een speciaal document creation " "script. Dit alles wordt automatisch door Kraft gestart als een document " "uitgeprint moet worden." #. type: Plain text #: kraft.adoc:702 msgid "" "Each document type in Kraft can have it's own template that is used to " "create a PDF. Which one can be set in the Settings dialog for document types." msgstr "" "In Kraft kan elk documenttype zijn eigen sjabloon hebben voor de creatie van " "een PDF. Welk wordt gebruikt kan u instellen in het instellingsvenster voor " "documenttypes." #. type: Title ==== #: kraft.adoc:703 #, no-wrap msgid "WeasyPrint Documents" msgstr "WeasyPrint Documenten" #. type: Plain text #: kraft.adoc:706 msgid "" "Kraft still ships with the old ReportLab based converter, but that will be " "deprecated the future. The WeasyPrint based system is the future. It is a " "recommended to port existing templates." msgstr "" #. type: Plain text #: kraft.adoc:708 msgid "" "With https://weasyprint.org[WeasyPrint] Kraft uses a very powerful generator " "that makes it very easy to create highly customized documents with great " "quality." msgstr "" #. type: Plain text #: kraft.adoc:710 msgid "" "WeasyPrint converts a html file to PDF. It is integrating a cascading " "stylesheet (CSS) file which has a huge impact on the PDF document's look." msgstr "" #. type: Plain text #: kraft.adoc:712 msgid "" "The html- and CSS input file for WeasyPrint is built from the Kraft template " "file." msgstr "" #. type: Plain text #: kraft.adoc:714 #, fuzzy #| msgid "" #| "To use a WeasyPrint based template for a document simply create a " #| "template file and save it with the extension *.gtmpl*. With that file " #| "extension Kraft automatically uses WeasyPrint and also the Grantlee " #| "templating for rendering." msgid "" "To enable the use of WeasyPrint for a document type in Kraft, simply create " "a weasyprint compatible template file and save it with the extension *." "gtmpl*. Based on the file extension Kraft automatically uses WeasyPrint and " "the Grantlee templating engine for rendering." msgstr "" "Om voor een document een op WeasyPrint gebaseerde sjabloon te gebruiken, " "creëert u eenvoudig een sjabloonbestand en slaat deze op met de extensie *." "gtmpl*. Met deze bestand-extensie gebruikt Kraft automatisch WeasyPrint met " "daarbij Grantlee sjablonen voor de rendering." #. type: Plain text #: kraft.adoc:716 #, fuzzy #| msgid "" #| "From version 0.95 on Kraft ships with an example document in the " #| "Grantlee- and WeasyPrint format. It can be found at `/usr/share/kraft/" #| "reports/invoice.gtmpl` or https://github.com/dragotin/kraft/blob/master/" #| "reports/invoice.gtmpl[online on Github]." msgid "" "From version 0.95 on Kraft ships with an example template in the Grantlee- " "and WeasyPrint format. It can be found at `/usr/share/kraft/reports/invoice." "gtmpl` or https://github.com/dragotin/kraft/blob/master/reports/invoice." "gtmpl[online on Github]. An example CSS file `kraft.css` (https://github.com/" "dragotin/kraft/blob/master/reports/kraft.css[on Github]) is shipped as a " "good starting point for adoption." msgstr "" "Vanaf versie 0.95 van Kraft vindt u een voorbeeld document in het Grantlee- " "en WeasyPrint formaat. U kunt het vinden in `/usr/share/kraft/reports/" "invoice.gtmpl` of https://github.com/dragotin/kraft/blob/master/reports/" "invoice.gtmpl[online op Github]." #. type: Title ==== #: kraft.adoc:717 #, no-wrap msgid "Template Variables" msgstr "Sjabloon variabelen" #. type: Plain text #: kraft.adoc:720 #, fuzzy #| msgid "" #| "To generate the PDF, Kraft has to transfer data from the document you " #| "have been working on in Kraft to the input document that is processed to " #| "an PDF utilising WeasyPrint. For that, Kraft uses a text template. In " #| "that, Kraft replaces variables with the actual values." msgid "" "To generate the PDF, Kraft has to transfer data from the document you have " "been working on to the input file that is processed to a PDF. For that, " "Kraft uses a text template in which Kraft replaces variables with the actual " "values." msgstr "" "Om de PDF te genereren, moet Kraft de data van het document waaraan u heeft " "gewerkt overbrengen naar het input-document dat wordt met de hulp van " "Weasyprint verwerkt tot een PDF. Daarvoor gebruikt Kraft een tekstsjabloon. " "Daarin vervangt Kraft variabelen door de daadwerkelijke waarden." #. type: Plain text #: kraft.adoc:722 msgid "" "For example, the tag `{{ doc.doctype }}` is replaced with the current " "document type during the generating process." msgstr "" #. type: Plain text #: kraft.adoc:724 msgid "" "The syntax is based on the Django syntax for templates described in the " "https://docs.djangoproject.com/en/3.1/topics/templates/[the docs]." msgstr "" "De syntax is gebaseerd op de Django syntax voor sjablonen zoals het " "beschreven wordt in https://docs.djangoproject.com/en/3.1/topics/templates/" "[de documentatie]." #. type: Title ==== #: kraft.adoc:725 #, no-wrap msgid "EPC QR Code" msgstr "" #. type: Plain text #: kraft.adoc:728 msgid "" "With Weasyprint based PDF generation Kraft supports the https://en.wikipedia." "org/wiki/EPC_QR_code[EPC QR Code] which implements a European standard for " "payments by computer and mobile devices." msgstr "" #. type: Plain text #: kraft.adoc:730 msgid "" "In Germany it is also known as _Giro Code_, in Belgium as _Bancontact QR_, " "in the Netherlands as _iDEAL QR-code_ and in Spain it is also known as " "_Bizum QR-code_." msgstr "" #. type: Plain text #: kraft.adoc:732 msgid "" "In Germany it is accepted by the _Giro Code_ and in Holland it is accepted " "by the official https://www.ideal.nl/consumenten/ideal-app/[_iDEAL QR-code_] " "app." msgstr "" #. type: Plain text #: kraft.adoc:734 msgid "" "In Belgium and Holland it is accepted by the apps of many banks, and in " "Austria and Finland it is accepted by the apps of all banks." msgstr "" #. type: Plain text #: kraft.adoc:736 msgid "" "To use the EPC QR code on the invoice printout, the bank account information " "has to be added to own identity settings dialog in Kraft. The giro code is " "current only generated for documents with the document type `Rechnung`." msgstr "" #. type: Plain text #: kraft.adoc:738 msgid "" "To include the generated EPC QR Code into the PDF document, the Weasyprint " "template needs to contain a snippet like this:" msgstr "" #. type: delimited block - #: kraft.adoc:747 #, no-wrap msgid "" " {%if doc.isInvoice and epcqrcode.valid %}\n" "

\n" " \"EPC\n" " Dieser QR Code ermöglicht einfaches, sicheres und schnelles Begleichen dieser Rechnung via GiroPay:\n" " Diesen Code mit dem Smartphone scannen und Überweisung per Banking App aufgeben.\n" "

\n" " {% endif %}\n" msgstr "" #. type: Title == #: kraft.adoc:751 #, no-wrap msgid "Menus and Shortcuts" msgstr "Menu's en sneltoetsen" #. type: Title === #: kraft.adoc:753 #, no-wrap msgid "Main Application Menu" msgstr "Hoofdvenster van het programma" #. type: Title ==== #: kraft.adoc:756 #, no-wrap msgid "The File Menu" msgstr "Het menu Bestand" #. type: Plain text #: kraft.adoc:761 #, no-wrap msgid "" " [File]>[Quit]\n" " [Ctrl]+[Q]\n" " Quits the application.\n" msgstr "" " [Bestand]>[Afsluiten]\n" " [Ctrl]+[Q]\n" " Sluit het programma af.\n" #. type: Title ==== #: kraft.adoc:763 #, no-wrap msgid "The Document Menu" msgstr "Het document-menu" #. type: Plain text #: kraft.adoc:769 #, no-wrap msgid "" " [Document]>[Show Document]\n" " [Ctrl]+[R]\n" " Opens a window with the selected document for showing it.\n" msgstr "" " [Document]>[Document tonen]\n" " [Ctrl]+[R]\n" " Opent een venster met het geselecteerde document om deze te tonen.\n" #. type: Plain text #: kraft.adoc:773 #, no-wrap msgid "" " [Document]>[Edit Document]\n" " [Ctrl+O]\n" " Opens a window with the selected document for editing it.\n" msgstr "" " [Document]>[Document bewerken]\n" " [Ctrl+O]\n" " Opent een venster met het geselecteerde document voor bewerking.\n" #. type: Plain text #: kraft.adoc:777 #, no-wrap msgid "" " [Document]>[Open Archived document]\n" " [Ctrl]+[A]\n" " Opens an archived document.\n" msgstr "" " [Document]>[Open gearchiveerd document]\n" " [Ctrl]+[A]\n" " Opent een gearchiveerd document.\n" #. type: Plain text #: kraft.adoc:780 #, no-wrap msgid "" " [Document]>[Create Document]\n" " Opens a window with a wizard for creating a new client-document.\n" msgstr "" " [Document]>[Nieuw document]\n" " Opent een venster met een wizard voor de creatie van een nieuw client-document.\n" #. type: Plain text #: kraft.adoc:784 #, no-wrap msgid "" " [Document]>[Copy Document]\n" " Makes a copy of the selected client-document to a new client-document\n" " which can belong to an other client or an other documenttype.\n" msgstr "" " [Document]>[Kopieer Document]\n" " Maakt een kopie van het geselecteerde client-document naar een nieuw client-document\n" " Deze kan bij een andere klant horen of zelfs een ander documenttype zijn.\n" #. type: Plain text #: kraft.adoc:787 #, no-wrap msgid "" " [Document]>[Follow Document]\n" " Opens the selected client-document for editing.\n" msgstr "" " [Document]>[Creëer een opvolg Document]\n" " Kopieert de inhoud van een offerte naar een order-acceptatie of een rekening.\n" #. type: Plain text #: kraft.adoc:791 #, no-wrap msgid "" " [Document]>[Print document]\n" " Makes a PDf from the selected client-document for to be mailed or\n" " printed.\n" msgstr "" " [Document]>[Document afdrukken]\n" " Creëert een PDF van het geselecteerde client-document zodat u deze kan emaillen of\n" " uitprinten.\n" #. type: Plain text #: kraft.adoc:795 #, no-wrap msgid "" " [Document]>[Mail document]\n" " [Ctrl]+[M]\n" " Mails a document.\n" msgstr "" " [Document]>[Verzend document]\n" " [Ctrl]+[M]\n" " Verzend een document per email.\n" #. type: Title ==== #: kraft.adoc:798 #, no-wrap msgid "The Settings menu" msgstr "Het instellingen-menu" #. type: Plain text #: kraft.adoc:804 #, no-wrap msgid "" " [Settings]>[Edit Tag Templates]\n" " [Ctrl]+[E]\n" " Opens a window where you add, edit or translate the tags (like work,\n" " material, plants or discounts).\n" msgstr "" " [Voorkeuren]>[Tag sjabloon bewerken]\n" " [Ctrl]+[E]\n" " Opent een venster waarin u tags (zoals work,material, plants of discounts)\n" " kunt toevoegen, bewerken of vertalen.\n" #. type: Plain text #: kraft.adoc:808 #, no-wrap msgid "" " [Settings]>[Redo initial setup]\n" " [Ctrl+R]\n" " Redoes the initial setup. After this, a restart of Kraft is required.\n" msgstr "" " [Voorkeuren]>[De initiële aanmaak opnieuw uitvoeren]\n" " [Ctrl+R]\n" " Voert de basisconfiguratie opnieuw uit. Hierna is een herstart van Kraft nodig.\n" #. type: Plain text #: kraft.adoc:812 #, no-wrap msgid "" " [Settings]>[Showed toolbars]\n" " Here you can decide if the `main toolbar` and the toolbar `Document Actions`\n" " are shown.\n" msgstr "" " [Voorkeuren]>[Werkbalken]\n" " Hier kunt u beslissen of de `hoofdwerkbalk` en de werkbalk `Document acties`\n" " worden getoond.\n" #. type: Plain text #: kraft.adoc:816 #, no-wrap msgid "" " [Settings]>[Configure Kraft]\n" " [Ctrl]+[Shft]+[,]\n" " Here you can configure Kraft.\n" msgstr "" " [Voorkeuren]>[Instellingen]\n" " [Ctrl]+[Shft]+[,]\n" " Hier kunt u Kraft instellen.\n" #. type: Title === #: kraft.adoc:817 #, no-wrap msgid "Document Edit Window" msgstr "Het document-bewerkingsvenster." #. type: Title ==== #: kraft.adoc:820 #, no-wrap msgid "The context Menu" msgstr "Het contextmenu" #. type: Plain text #: kraft.adoc:824 #, no-wrap msgid "" " [Context]>[Item kind]\n" " change the status from this item between\n" msgstr "" " [Context]>[Soort item]\n" " wijzigt de status van dit item tussen\n" #. type: Plain text #: kraft.adoc:825 #, no-wrap msgid "Normal\n" msgstr "Normaal\n" #. type: Plain text #: kraft.adoc:826 #, no-wrap msgid "Alternative\n" msgstr "Alternatief\n" #. type: Plain text #: kraft.adoc:827 #, no-wrap msgid "On demand\n" msgstr "Op verzoek\n" #. type: Plain text #: kraft.adoc:830 #, no-wrap msgid "" " [Context]>[Tax]\n" " Seems not working.\n" msgstr "" " [Context]>[Belasting]\n" "Lijkt niet te werken.\n" #. type: Plain text #: kraft.adoc:833 #, no-wrap msgid "" " [Context]>[Move up]\n" " Moves this item a place up in document.\n" msgstr "" " [Context]>[Omhoog verplaatsen]\n" " Verplaatst dit item een plaats omhoog in het document.\n" #. type: Plain text #: kraft.adoc:836 #, no-wrap msgid "" " [Context]>[Move down]\n" " Moves this item a place down in document.\n" msgstr "" " [Context]>[Omlaag verplaatsen]\n" " Verplaatst dit item een plaats omlaag in het document.\n" #. type: Plain text #: kraft.adoc:839 #, no-wrap msgid "" " [Context]>[Lock item]\n" " It is not clear what is does.\n" msgstr "" " [Context]>[Item vastzetten]\n" " Het is niet duidelijk wat het doet.\n" #. type: Plain text #: kraft.adoc:842 #, no-wrap msgid "" " [Context]>[Unlock item]\n" " It is not clear what is does.\n" msgstr "" " [Context]>[Item ontgrendelen]\n" " Het is niet duidelijk wat het doet.\n" #. type: Plain text #: kraft.adoc:845 #, no-wrap msgid "" " [Context]>[Delete item]\n" " Removes this item from document.\n" msgstr "" " [Context]>[Verwijder item]\n" " Verwijdert dit item uit het document.\n" #. type: Title == #: kraft.adoc:848 #, no-wrap msgid "Advanced Topics" msgstr "Geavanceerde onderwerpen" #. type: Plain text #: kraft.adoc:851 msgid "" "This chapter describes advanced topics around Kraft. Some Linux knowledge is " "required, and setups should be done by experienced Linux administrators and " "should be tested carefully." msgstr "" "Dit hoofdstuk beschrijft geavanceerde onderwerpen rond het gebruik van " "Kraft. Daarbij wordt enige kennis van Linux veronderstelt, en het is " "verstandig om de instellingen door ervaren Linux-beheerders uit te laten " "voeren en deze vervolgens zorgvuldig en uitgebreid te testen." #. type: Title === #: kraft.adoc:852 #, no-wrap msgid "Using Kraft Collaboratively" msgstr "Kraft gemeenschappelijk gebruiken." #. type: Plain text #: kraft.adoc:855 msgid "" "Kraft can be used collaborative in a distributed environment. That means " "that multiple users work on their desktops with their own Kraft instance on " "the same data." msgstr "" "Kraft kan gemeenschappelijk in een gedistribueerde omgeving gebruikt worden. " "Dat houd in dat meerdere gebruikers op hun eigen desktop met hun eigen Kraft " "instance met dezelfde data kunnen werken." #. type: Plain text #: kraft.adoc:857 msgid "" "This whole topic is a subject to change, as Kraft will evolve to use " "ownCloud as a private cloud solution to store the data." msgstr "" "De hele situatie is aan verandering onderhevig, omdat Kraft in de nabije " "toekomst ownCloud als privé Cloud voor de opslag van de data zal gebruiken." #. type: Title ==== #: kraft.adoc:858 #, no-wrap msgid "Sharing Database and Document Pool" msgstr "Database en Document-pool gezamenlijk gebruiken" #. type: Plain text #: kraft.adoc:861 msgid "" "The simplest case is that two or more Kraft instances use a database " "together and access the same pool of PDF documents on the harddisk. For " "simplicity this describes only two Kraft instances." msgstr "" "De eenvoudigste situatie is als twee of meer Kraft-gebruikers de database " "gemeenschappelijk gebruiken en toegang tot dezelfde pool van PDF-documenten " "op de harde schijf hebben. Om het eenvoudig te houden, worden hier de " "situatie met twee gebruikers beschreven." #. type: Plain text #: kraft.adoc:863 msgid "" "A typical use case would be: Two different Linux users want to use Kraft. " "They both have their own computer but only work in the same network. For " "example this would describe a situation with one main office machine that " "runs Kraft in normal mode, plus a notebook with Kraft in read only mode to " "view documents, check catalogs and such." msgstr "" "Een veelvoorkomende situatie kan als volgt zijn: twee verschillende Linux " "gebruikers willen Kraft gebruiken. Ze hebben beide hun eigen computer en " "werken in hetzelfde netwerk. Dit voorbeeld beschrijft een situatie met een " "hoofdkantoor die Kraft in de normale modus gebruiken, en een Notebook met " "Kraft, die in de read-only modus is om de documenten te bekijken, de " "catalogus te raadplegen en dergelijke." #. type: Plain text #: kraft.adoc:865 msgid "For that, the following prerequisites have to be met:" msgstr "Daarvoor is het volgende vereist:" #. type: Plain text #: kraft.adoc:867 msgid "MySQL or MariaDB is used as database backend. Sqlite is not supported." msgstr "" "Als Database-Backend wordt MySQL of MariaDB gebruikt. Sqlite is niet " "mogelijk." #. type: Plain text #: kraft.adoc:868 msgid "" "The database is accessible with a mysql user and from each machine for both " "users." msgstr "" "De Database is met de gebruiker MySQL vanuit beide computers bereikbaar." #. type: Plain text #: kraft.adoc:869 msgid "The document store directory has to be shared." msgstr "" "De map waarin de documenten worden opgeslagen, wordt voor beide computers " "bereikbaar zijn (shared)." #. type: delimited block _ #: kraft.adoc:873 msgid "" "WARNING: There is no protection against having both users editing the same " "document. Because that is dangerous and can lead to unpredictable results, " "it is recommended to run all instances of Kraft except the main one in read " "only mode. This is done by starting Kraft with the `-r` command line switch." msgstr "" "Pas op: Er is geen beveiliging tegen het feit dat beide gebruikers tegelijk " "hetzelfde document kunnen bewerken. Om dat dit gevaarlijk is en tot " "onvoorziene resultaten kan leiden, raden wij aan om Kraft buiten het kantoor " "alleen in de readonly-modus te gebruiken. Deze readonly-modus wordt met de " "parameter -r ingeschakeld." #. type: Plain text #: kraft.adoc:876 #, no-wrap msgid "**Sharing the Database**\n" msgstr "**De database gezamenlijk gebruiken**\n" #. type: Plain text #: kraft.adoc:878 msgid "" "The database server should be installed on the main machine or a dedicated " "device like a NAS. Networking speed influences the comfort to use obviously." msgstr "" "De Database-server moet op de hoofdmachine geïnstalleerd zijn, of het moet " "op een gespecialiseerd apparaat zoals een NAS geïnstalleerd zijn. De " "snelheid van het netwerk beïnvloed de bruikbaarheid natuurlijk enorm." #. type: Plain text #: kraft.adoc:880 msgid "Find howtos on the internet how to setup MySQL accordingly." msgstr "Howtos voor het gebruik van MySQL zijn op het internet te vinden." #. type: Plain text #: kraft.adoc:882 #, no-wrap msgid "**Sharing the Document Pool Directory**\n" msgstr "**De map met de document Pool delen (sharen)**\n" #. type: Plain text #: kraft.adoc:884 msgid "" "Kraft writes generated PDF documents into a local directory. Where that is " "can be configured in the Kraft Config file. The config file has to be " "adopted on all instances." msgstr "" "Kraft schrijft de gegenereerde PDF's in een lokale map. Welke dat is, kunt u " "instellen in het config-bestand van Kraft. Het config-bestand moet voor alle " "exemplaren van Kraft correct ingesteld zijn." #. type: Plain text #: kraft.adoc:886 msgid "" "That is located in each users home directory, in the path `.config/kraftrc`. " "It has to contain the following config value:" msgstr "" "U kunt deze vinden in de thuismap van de gebruiker met de relatieve pad `." "config/kraftrc`. Daarin moet de volgende tekst voorkomen:" #. type: delimited block - #: kraft.adoc:890 #, fuzzy, no-wrap #| msgid "PdfOutputDir=/data/space/kraftdoc/pdf" msgid "" "[reporting]\n" "PdfOutputDir=/data/space/kraftdoc/pdf\n" msgstr "PdfOutputDir=/data/space/kraftdoc/pdf" #. type: Plain text #: kraft.adoc:893 msgid "" "There are different ways how share that directory, ie. NFS or SMB storages. " "It is important that both users from both machines can list and access the " "files. The main user needs read and write access, read only users only need " "read access to the files." msgstr "" "Er zijn verschillende manieren om de map te delen (sharen), bijvoorbeeld een " "NFS of een SMB Server. Het is belangrijk dat gebruikers van beide machines " "toegang hebben tot deze bestanden. De hoofdgebruiker heeft lees- en " "schrijfrechten nodig, de read-only gebruiker heeft voor de bestanden alleen " "lees-rechten nodig." #. type: Plain text #: kraft.adoc:895 msgid "" "A recommended setup is a NFS share with autofs which is set up on the main " "machine. To manage file access a certain group should be set up on the " "machines with which access can be managed." msgstr "" "Een aanbevolen opstelling is een NFS Share met autofs, die op de " "hoofdmachine is ingesteld. Om de toegang tot de bestanden te beheren, raden " "wij aan om een gebruikersgroep te creëren waarin u de toegangsrechten kan " "beheren." #. type: Plain text #: kraft.adoc:897 #, no-wrap msgid "**Starting Kraft in read-only mode**\n" msgstr "**Kraft in read-only modus**\n" #. type: Plain text #: kraft.adoc:899 msgid "" "To start Kraft in read-only mode, start the binary with the `-r` command " "line switch." msgstr "" "Om Kraft in de read-only modus te starten, moet het programma met de " "volgende parameter `-r` gestart worden." #. type: Title === #: kraft.adoc:900 #, no-wrap msgid "XRechnung Support" msgstr "Gebruik van XRechnung" #. type: Plain text #: kraft.adoc:903 msgid "" "Kraft supports the XRechnung standard. That is a digital format for " "electronic invoicing, and it passed as law in Germany and follows a EU " "directive. The XRechnung is a XML file format designed for that purpose." msgstr "" "Kraft ondersteund het gebruik van de XRechnung standaard. Dat is een " "digitaal formaat voor electronische rekeningen, en als wet ingevoerd in " "Duitsland wat een EU richtlijn volgt. De XRechnung is een XML-" "bestandsformaat ontworpen voor dat doel." #. type: Plain text #: kraft.adoc:905 msgid "" "To use the XRechnung Export productivly, a little manual work is still " "needed in Kraft. Kraft creates the XML file based on a template, very " "similar to the normal PDF documents. That means that it loads a template " "that contains static elements (ie. the company address) that do not change " "between different invoices. The dynamic elements (customer data, items etc.) " "are filled into the template during the generation step." msgstr "" "Om de XRechnung Export productief te gebruiken, is nog een beetje handwerk " "in Kraft nodig. Kraft creëert het XML-bestand aan de hand van een sjabloon, " "vergelijkbaar met de normale PDF documenten. Dit houdt in dat het een " "sjabloon laadt wat statische elementen bevat (b.v. het adres van het " "bedrijf) die niet veranderen tussen de verschillende rekeningen. De " "dynamische elementen (data over de klant, items enz.) worden in het sjabloon " "geplaatst tijdens de stap van het generen." #. type: Plain text #: kraft.adoc:907 msgid "" "In order to generate correct XRechnung files for the specific company, the " "user has to adopt the template file manually to the companies needs. Note " "that this has only to be done once and should be easy for a person with a " "bit computer experience (Basic knowledge about XML appreciated!)." msgstr "" "Om correcte XRechnung-bestanden te generen voor het desbetreffende bedrijf, " "moet de gebruiker het sjabloonbestand handmatig aanpassen aan de eisen van " "het bedrijf. Merk op dat u dat maar eenmalig hoeft te doen en dat het niet " "moeilijk is voor iemand met een beetje computerervaring (Basiskennis van XML " "is gewenst)." #. type: Plain text #: kraft.adoc:909 msgid "" "To adapt the file to the needs of the company, it is best to start with the " "https://raw.githubusercontent.com/dragotin/kraft/master/reports/xrechnung." "xrtmpl[example XRechnung file]. It has to be downloaded and saved into a " "location that the user can edit. Open it in a normal text editor, such as " "https://kate-editor.org/[Kate]." msgstr "" "Om het bestand aan te passen aan de eisen van het bedrijf, kunt u het beste " "beginnen met het https://raw.githubusercontent.com/dragotin/kraft/master/" "reports/xrechnung.xrtmpl[voorbeeld XRechnung-bestand]. U moet het downloaden " "en vervolgens opslaan op een plek waar u het kan bewerken. Open het in een " "normale tekstverwerker, zoals https://kate-editor.org/[Kate]." #. type: Plain text #: kraft.adoc:911 msgid "" "Read carefully through the file without being scared off by the XML format. " "All user strings (ie. company name, address and such) are user specific and " "should be replaced accordingly. Find https://www.xoev.de/" "xrechnung-16828[details about the format] here to better understand the " "meaning of the fields." msgstr "" "Bestudeer nauwkeurig het bestand zonder dat u afgeschrikt wordt door het XML-" "opmaak. Alle user strings (d.w.z. bedrijfsnaam, adres en dergelijke) zijn " "specifiek voor de gebruiker en moeten daarom overeenkomstig vervangen " "worden. Zoek https://www.xoev.de/xrechnung-16828[de details over de opmaak] " "hier op voor een beter begrip van de betekenis van de velden." #. type: Plain text #: kraft.adoc:913 msgid "" "Make sure to not disturb the proper XML format and do not change places " "where the template format `{{ template_name }}` is used." msgstr "" "Zorg ervoor dat u de correcte XML-opmaak niet verstoort en wijzig niet de " "locatie van waar `{{ template_name }}` is gebruikt." #. type: Plain text #: kraft.adoc:915 msgid "" "Once the file is adopted to the needs, open the Settings dialog of Kraft and " "insert the filename into the entry field for the XRechnung Template File on " "the Document Defaults page." msgstr "" "Nadat het bestand is aangepast aan de wensen, opent u het dialoogvenster " "voor de instellingen van Kraft en voer de bestandsnaam in het invoerveld " "voor het XRechnung Sjabloonbestand in de pagina voor document-standaarden." #. type: Plain text #: kraft.adoc:917 msgid "" "After that step, the btn:[Export XRechung] menu item will open a dialog to " "pick a filename where to save the XRechnung invoice to." msgstr "" "Na deze stap zal het menu item btn:[Export XRechung] een dialoogvenster " "openen voor het ingeven van het bestandsnaam waarmee de XRechnung rekening " "wordt opgeslagen." #. type: Plain text #: kraft.adoc:919 msgid "This file can now be transfered to the receiver of the invoice." msgstr "Dit bestand kan nu verzonden worden naar de ontvanger van de rekening." #. type: Plain text #: kraft.adoc:921 msgid "" "There are validators for invoices in XRechnung format out there in the " "internet. It is useful to verify the format of the Kraft exported XRechnung." msgstr "" "Er zijn validators voor rekeningen in het XRechnung formaat op het internet " "te vinden. Het is verstandig om het bestandsformaat van de XRechnung dat uit " "Kraft is geëxporteerd te laten valideren." #. type: Title === #: kraft.adoc:922 #, no-wrap msgid "Changing the Locale" msgstr "" #. type: Plain text #: kraft.adoc:925 msgid "" "If it is needed that Kraft runs under a different locale than the actual " "desktop environment, this can be achieved by setting the desired locale in " "the start file of Kraft." msgstr "" #. type: Plain text #: kraft.adoc:927 msgid "" "On the linux desktop, apps are usually started through a so called https://" "specifications.freedesktop.org/desktop-entry-spec/latest/[desktop file]. It " "contains the information how the Kraft binary is started if user clicks on " "the icon on the desktop or in the start menu." msgstr "" #. type: Plain text #: kraft.adoc:929 msgid "" "The desktop file can usually be found in `/usr/share/applications/de.volle-" "kraft-voraus.kraft.desktop`." msgstr "" #. type: Plain text #: kraft.adoc:931 msgid "It contains the line" msgstr "" #. type: delimited block - #: kraft.adoc:934 #, no-wrap msgid "Exec=kraft %u\n" msgstr "" #. type: Plain text #: kraft.adoc:937 msgid "which starts the application with the default locale." msgstr "" #. type: Plain text #: kraft.adoc:939 msgid "Changing it to" msgstr "" #. type: delimited block - #: kraft.adoc:942 #, no-wrap msgid "Exec=env LANG=de_DE.UTF-8 kraft %u\n" msgstr "" #. type: Plain text #: kraft.adoc:945 msgid "" "would change that to run in the German locale for example, independent from " "the desktop environment location." msgstr "" #. type: Title == #: kraft.adoc:948 #, no-wrap msgid "Credits and License" msgstr "Dankbetuigingen en licentie" #. type: Plain text #: kraft.adoc:951 #, fuzzy #| msgid "Program and documentation copyright 2004–2022 Klaas Freitag" msgid "Program and documentation copyright 2004–2023 Klaas Freitag" msgstr "Auteursrecht software en documentatie 2004-2022 Klaas Freitag" #. type: Plain text #: kraft.adoc:952 #, fuzzy #| msgid "Documentation copyright 2020 Ronald Stroethoff" msgid "Documentation copyright 2020-2023 Ronald Stroethoff" msgstr "Documentatie auteursrecht 2020 Ronald Stroethoff" #~ msgid "```" #~ msgstr "```" #~ msgid "" #~ "With https://weasyprint.org[WeasyPrint] Kraft uses a very powerful HTML " #~ "and CSS based generator that makes it very easy to create highly " #~ "customized documents which fit the users expectations. The general idea " #~ "is that Weasyprint loads html output that is processed to PDF. Usually it " #~ "is considering a Cascading Stylesheet file which has a huge impact on how " #~ "the PDF document looks in the end." #~ msgstr "" #~ "Door https://weasyprint.org[WeasyPrint] te gebruiken heeft Kraft een zeer " #~ "krachtige op HTML en CSS gebaseerde generator die het zeer eenvoudig " #~ "maakt om aangepaste documenten te creëren die voldoen aan de " #~ "verwachtingen van gebruikers. Het algemene idee is dat Weasyprint de " #~ "gecreëerde html laad om die te verwerken naar een PDF. Normaal gesproken " #~ "gebruikt het een bestand met een Cascading Stylesheet om te bepalen hoe " #~ "het PDF document er aan het eind eruit komt te zien." #~ msgid "" #~ "An example for a WeasyPrint document can be found in the Kraft package in " #~ "the reports directory and is called invoice.gtmpl." #~ msgstr "" #~ "Een voorbeeld van een WeasyPrint document kunt u vinden in het Kraft " #~ "pakket in de map reports en draagt de naam invoice.gtmpl." #~ msgid "" #~ "To use a WeasyPrint template with one of the Kraft document types just " #~ "select the template file name (with the right extension `*.gtml`) in the " #~ "Kraft Settings Dialog." #~ msgstr "" #~ "Om bij een van de Kraft-documenten een Weasyprint-sjabloon te gebruiken, " #~ "selecteert u gewoon het bestandsnaam (met de juiste extensie: *.gtml) in " #~ "het instellingsvenster van Kraft." #~ msgid "" #~ "To effectively change the look of the document `kraft.css` (https://" #~ "github.com/dragotin/kraft/blob/master/reports/kraft.css[on Github]) needs " #~ "to be considered. It defines most of the look." #~ msgstr "" #~ "Om daadwerkelijk het uiterlijk van de documenten te veranderen is `kraft." #~ "css` (https://github.com/dragotin/kraft/blob/master/reports/kraft.css[op " #~ "Github]) heel belangrijk. Deze definieert het meeste van het uiterlijk." #~ msgid "" #~ "Kraft is designed to use the data entries from the KDE address book which " #~ "is a module of the https://community.kde.org/KDE_PIM[KDE PIM], an " #~ "information management application. All addresses are collected in the " #~ "https://userbase.kde.org/KAddressBook[KAdressBook]." #~ msgstr "" #~ "Kraft werkt met de adresgegevens uit het KDE adresboek, wat een onderdeel " #~ "is van https://community.kde.org/KDE_PIM[KDE PIM], wat een informatie-" #~ "beheers-programma is. Alle adressen worden in het programma https://" #~ "userbase.kde.org/KAddressBook[KAdressBook] verzameld." #~ msgid "" #~ "image:numbercycles.png[Numbercycles,float=\"right\"] Numbercycles are " #~ "used to define the *document number* which is printed on every document. " #~ "The document number is an important unique identifier of the document and " #~ "often must follow regulations." #~ msgstr "" #~ "image:numbercycles.png[Numbercycles,float=\"right\"] Volgnummersystemen " #~ "worden gebruikt voor de definitie van het *Documentnummer*, die op elk " #~ "document wordt afgedrukt. Het documentnummer is een belangrijk uniek " #~ "identificatie van het document die vaak aan bepaalde regels moet voldoen." #~ msgid "" #~ "Different document types can use the same number cycle to generate ids " #~ "from. Number cycles are identified by their name. User can create new " #~ "number cycles and edit them clicking on the button btn:[Edit Number " #~ "Cycles...]" #~ msgstr "" #~ "Verschillende documenttypes kunnen hetzelfde volgnummersysteem gebruiken " #~ "om ID's te generen. Volgnummersystemen zijn door hun naam te herkennen . " #~ "Gebruikers kunnen nieuwe volgnummersystemen creëren en ze aanpassen door " #~ "te klikken op de knop btn:[Volgnummersysteem instellen...] ." #~ msgid "We go first to catalogs." #~ msgstr "We gaan eerst naar de catalogi." #, no-wrap #~ msgid "Catalog" #~ msgstr "Catalogus" #~ msgid "Here we fill in:" #~ msgstr "Hier vullen we in:" kraft-1.1/manual/po/kraft.pot000066400000000000000000001646611450127457600162410ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE # Copyright (C) YEAR Free Software Foundation, Inc. # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2023-09-12 13:09+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. type: Title = #: kraft.adoc:1 #, no-wrap msgid "The Kraft Handbook" msgstr "" #. type: Plain text #: kraft.adoc:3 msgid "Ronald Stroethoff, Klaas Freitag" msgstr "" #. type: Title == #: kraft.adoc:16 #, no-wrap msgid "Introduction" msgstr "" #. type: Plain text #: kraft.adoc:19 msgid "" "Kraft is a Qt and KDE application to organize office documents like quotes " "and invoices in a small business. It eases the creation of documents and " "helps with repeating tasks." msgstr "" #. type: Plain text #: kraft.adoc:21 msgid "" "Using Kraft, there is no need for fiddling with a text processor any " "more. Documents are created by a few clicks, edited, generated and archived " "automatically. Kraft generates high quality PDF output for printing, mailing " "and archiving." msgstr "" #. type: Labeled list #: kraft.adoc:22 #, no-wrap msgid "Feature Overview" msgstr "" #. type: Plain text #: kraft.adoc:25 msgid "Simple creation of offers, invoices and similar documents." msgstr "" #. type: Plain text #: kraft.adoc:26 msgid "Customer management, deeply integrated with the mature KDE KAddressbook." msgstr "" #. type: Plain text #: kraft.adoc:27 msgid "Maintenance of document relations, ie. Partial invoices vs. invoices." msgstr "" #. type: Plain text #: kraft.adoc:28 msgid "Templates for document header- and footertexts and for document items." msgstr "" #. type: Plain text #: kraft.adoc:29 msgid "Pre calculation of item prices." msgstr "" #. type: Plain text #: kraft.adoc:30 msgid "Material management." msgstr "" #. type: Plain text #: kraft.adoc:31 msgid "Configurable document creation in PDF format for print and email." msgstr "" #. type: Plain text #: kraft.adoc:33 msgid "" "The code of Kraft is open source and is released under the " "https://en.wikipedia.org/wiki/GNU_General_Public_License[GNU General Public " "License]." msgstr "" #. type: Plain text #: kraft.adoc:38 #, no-wrap msgid "" "Kraft is driven by community of users, coders, artists and others by " "voluntary work. +\n" "Also this manual needs contributions! +\n" " +\n" " Learn more on " "https://github.com/dragotin/kraft/blob/master/manual/Readme.md[how to " "contribute]!\n" msgstr "" #. type: Title == #: kraft.adoc:40 #, no-wrap msgid "First Use and Basic Configuration" msgstr "" #. type: Plain text #: kraft.adoc:43 msgid "" "When Kraft is started for the first time, it automatically enters the " "initial setup process." msgstr "" #. type: Plain text #: kraft.adoc:45 msgid "" "During the initial setup you are asked to select a database to use and give " "the name and address of your company." msgstr "" #. type: Plain text #: kraft.adoc:47 msgid "" "You can fill in your company address (that appears on the printed documents) " "in two ways: in the setup procedure use the first tab *Select from " "Addressbook* for to select your on address in KAddressBook (if you have " "filled your own address in KaddressBook) or use the second tab *Manual " "entry* for to fill in the information of the address from your company " "manually. This step is necessary for the correct generation of your " "documents as the address is automatically used in the document generation " "step." msgstr "" #. type: Plain text #: kraft.adoc:49 msgid "image:company_adress1.png[Company adress,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:52 msgid "" "After the initial setup, select menu:Preferences[Settings]. That allows to " "prepare Kraft correctly so it can be used in a proper way." msgstr "" #. type: Plain text #: kraft.adoc:54 msgid "In the Preferences dialog we have the tabs:" msgstr "" #. type: Plain text #: kraft.adoc:61 #, no-wrap msgid "" " *Document Defaults\n" " *Taxes\n" " *Documunt Types\n" " *Wages\n" " *Units\n" " *Own identity\n" msgstr "" #. type: Plain text #: kraft.adoc:63 msgid "Each of the tabs allows to enter useful values for the specific use case." msgstr "" #. type: Title === #: kraft.adoc:64 #, no-wrap msgid "Document Types" msgstr "" #. type: Plain text #: kraft.adoc:67 msgid "At the first use you find a list of different document types, such as:" msgstr "" #. type: Plain text #: kraft.adoc:69 msgid "Acceptance of order" msgstr "" #. type: Plain text #: kraft.adoc:70 msgid "Delivery receipt" msgstr "" #. type: Plain text #: kraft.adoc:71 msgid "Invoice" msgstr "" #. type: Plain text #: kraft.adoc:72 msgid "Offer" msgstr "" #. type: Plain text #: kraft.adoc:74 msgid "image:documentype.png[Document type,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:77 msgid "" "Translate this types to your own language. You can also add new ones and " "remove document types you wont use." msgstr "" #. type: Title ==== #: kraft.adoc:78 #, no-wrap msgid "Numbercycles" msgstr "" #. type: Plain text #: kraft.adoc:82 msgid "" "image:numbercycles.png[Numbercycles,float=\"right\"] Each document has to " "have an unique identifier that identifies the document. There must not be " "two documents in Kraft with the same identifier." msgstr "" #. type: Plain text #: kraft.adoc:85 msgid "" "The format of the identifier is configuratable in Kraft. For that, Kraft has " "a concept of so called number cycles. Number cycles are used to define the " "form of the *document number* which is printed on every document." msgstr "" #. type: Plain text #: kraft.adoc:89 msgid "" "All documents of a certain type have identifiers taken out of one number " "cycle. Each document type has a number cycle assigned. Different document " "types can use the same number cycle to generate ids from. That way, for " "example the document types Invoice and Final Invoice can use numbers from " "the same number cycle, even thought they are different document types in " "Kraft. Number cycles are identified by their name. User can create new " "number cycles and edit them clicking on the button btn:[Edit Number " "Cycles...]" msgstr "" #. type: Plain text #: kraft.adoc:91 msgid "" "The format of the document numbers are defined by a template that can " "contain normal, fixed characters and also some variables that are replaced " "by the respective values when the document is created." msgstr "" #. type: Plain text #: kraft.adoc:94 msgid "" "Each identifier needs to be unique, and thus has to contain a counter. Kraft " "supports two types of counter: One (variable `%i`) is incremented globally " "for every new document. The other (variable `%n`) is reset every day and " "starts at 1 again on every new day. In addition to the counter, more " "information can be added to the template form an useful number. Examples are " "a constant text or parts of the date." msgstr "" #. type: Plain text #: kraft.adoc:96 msgid "" "The default numbercycle delivered with Kraft contains the year, the month " "and a serialnumber. That way you can compare offers or orders from last year " "with this year or the month April of last year with the month April of this " "year and get on this way an impression from the results of your business." msgstr "" #. type: Plain text #: kraft.adoc:98 msgid "See the following table for available variables which can be used:" msgstr "" #. type: Table #: kraft.adoc:115 #, no-wrap msgid "" "| `%y` or `%yyyy` | the year of the document date.\n" "| `%yy` | the year of the document (two digits).\n" "| `%w` | the week number of the document date.\n" "| `%ww` | the week number of the document date with leading " "zero.\n" "| `%d` | the day number of the document date.\n" "| `%dd` | the day number of the document date with leading " "zero.\n" "| `%m` or `%M` | the month number of the document date.\n" "| `%MM` | the month number with leading zero.\n" "| `%c` | the customer id from kaddressbook\n" "| `%type` | the localised doc type (offer, invoice etc.)\n" "| `%uid` | the contact id of the client.\n" "| `%i` .. `%iiiiii`| the unique counter\n" "| `%n` .. `%nnnnnn`| the unique day counter (combine with date)\n" "\n" msgstr "" #. type: Plain text #: kraft.adoc:118 msgid "" "A number cycle template needs to contain either `%i` or `%n`, if not, `%i` " "is appended automatically." msgstr "" #. type: Plain text #: kraft.adoc:120 msgid "" "Both `%i` and `%n` are numeric values. They can also be padded with with " "leading zeros. The length is defined by the number of i's or n's put into " "the template. For example, if a daily counter with length of three and " "leading zeros is desired, `%nnn` has to be put into the template. This works " "up to a length of six characters." msgstr "" #. type: delimited block _ #: kraft.adoc:123 msgid "" "NOTE: The \"design\" of the numbercycles and document numbers is very " "important. With the flexible system of templating Kraft can not prevent " "invalid number cycles. It is in the responsibility of the user." msgstr "" #. type: Title ==== #: kraft.adoc:125 #, no-wrap msgid "PDF Template" msgstr "" #. type: Plain text #: kraft.adoc:128 msgid "" "In the entry field Template File: the user can select a custom template for " "this specific document type." msgstr "" #. type: Plain text #: kraft.adoc:130 msgid "" "If the file extension of the template file is `.trml`, the ReportLab based " "document converter is used. If the file extension is `.gtmpl`, Kraft " "automatically uses the Weasyprint based converter." msgstr "" #. type: delimited block _ #: kraft.adoc:133 msgid "" "NOTE: The ReportLab system for PDF creation is deprecated in Kraft. Please, " "for new templates, always use Grantlee- and Weasyprint based templates." msgstr "" #. type: Title ==== #: kraft.adoc:135 #, no-wrap msgid "PDF Postprocessing" msgstr "" #. type: Plain text #: kraft.adoc:138 msgid "" "After Kraft has created the PDF document it is possible to merge the created " "PDF with static, customized PDFs created by the user. With that, it is easy " "to add a custom stationery with a logo to the resulting PDF (\"Watermark\")." msgstr "" #. type: Plain text #: kraft.adoc:140 msgid "" "The static PDFs should have the same page size as the generated " "documents. Keep in mind to use optimized images for logos etc. to not blow " "up the size of the result document." msgstr "" #. type: Plain text #: kraft.adoc:142 msgid "image:pdfpostproc.png[PDF Postprocessing,float?\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:144 msgid "The watermark options are:" msgstr "" #. type: Plain text #: kraft.adoc:146 #, no-wrap msgid "*No Watermark*: No watermark is created\n" msgstr "" #. type: Plain text #: kraft.adoc:147 #, no-wrap msgid "" "*On first page*: The first page of the watermark.pdf is merged with the " "first page of the result document\n" msgstr "" #. type: Plain text #: kraft.adoc:148 #, no-wrap msgid "" "*Watermark on all pages*: Merges the first page of the watermark PDF to all " "pages of the result document\n" msgstr "" #. type: Plain text #: kraft.adoc:149 #, no-wrap msgid "" "*alternating*: For this, the watermark PDF needs to have three pages. The " "first page is merged to the first page of the result document, the second " "and third page are alternated merge to subsequent pages.\n" msgstr "" #. type: Plain text #: kraft.adoc:150 #, no-wrap msgid "" "*different first and last page*: the PDF needs to have three pages. The " "first page is merged to the first page of the result document, the third " "page to the last, and the second to all page between first and last page.\n" msgstr "" #. type: Plain text #: kraft.adoc:152 msgid "" "If there is another static PDF document put into the entry field \"Append " "PDF:\", it is appended to the generated PDF. With that, Kraft will " "automatically add for example terms and conditions documents to the final " "document." msgstr "" #. type: Title === #: kraft.adoc:153 #, no-wrap msgid "Taxes" msgstr "" #. type: Plain text #: kraft.adoc:157 msgid "" "image:taxes.png[Taxes,float=\"right\"] In many countries there are two kinds " "of VAT-taxes for sold products." msgstr "" #. type: Plain text #: kraft.adoc:160 msgid "A high level and a low level." msgstr "" #. type: Plain text #: kraft.adoc:163 msgid "" "Fill here the appropriate amounts in for the high level and the low level. " "If the tax-level is changing, then you add here the start date with the new " "tax-levels." msgstr "" #. type: Title === #: kraft.adoc:164 #, no-wrap msgid "Wages" msgstr "" #. type: Plain text #: kraft.adoc:169 msgid "" "image:wages.png[Wages,float=\"right\"] A list of wage costs is maintained in " "Kraft. The items are used in templates and during calculation." msgstr "" #. type: Plain text #: kraft.adoc:172 msgid "" "All data can be edited, customized and new items can be added in the Kraft " "Configuration Dialog reachable through the Settings menu." msgstr "" #. type: Plain text #: kraft.adoc:176 msgid "" "Remember that these units are later used in the documents, it is therefor " "important that you translate them to your own language and to fill in the " "correct prices." msgstr "" #. type: Title === #: kraft.adoc:177 #, no-wrap msgid "Units of measurement" msgstr "" #. type: Plain text #: kraft.adoc:182 msgid "" "image:unity.png[Units of measurement,float=\"right\"] A list of units of " "measurement is maintained in Kraft. In Kraft Configuration Dialog reachable " "through the Settings menu can you edit and customize items already in the " "list, and also can you add new items to the list." msgstr "" #. type: Plain text #: kraft.adoc:185 msgid "" "Remember that these units are later used in the documents, it is therefor " "important that you translate them to your own language." msgstr "" #. type: Title === #: kraft.adoc:186 #, no-wrap msgid "Own identity" msgstr "" #. type: Plain text #: kraft.adoc:190 msgid "" "Check here if the information that you have given during the initial setup " "is correct for the use in the documents." msgstr "" #. type: delimited block _ #: kraft.adoc:195 msgid "" "WARNING: If you made the choice to use the information from KaddressBook " "then is the information from a later manual entry ignored." msgstr "" #. type: Plain text #: kraft.adoc:199 msgid "" "After we have made some corrections to the configuration, we go back to the " "main window.Here we see three tabs:" msgstr "" #. type: Plain text #: kraft.adoc:201 msgid "Documents" msgstr "" #. type: Plain text #: kraft.adoc:202 msgid "Timeline" msgstr "" #. type: Title == #: kraft.adoc:203 kraft.adoc:205 #, no-wrap msgid "Catalogs" msgstr "" #. type: Plain text #: kraft.adoc:208 msgid "" "Kraft supports so called Catalogs in which templates for document items are " "kept. With the catalogs creating documents can be significantly accellerated " "in the day to day business. When creating new documents, the items templates " "from the catalogs can easily selected and moved over to the document." msgstr "" #. type: Plain text #: kraft.adoc:210 msgid "" "Since templates are organized in chapters entire documents can be prepared " "in different chapters to be used as template documents." msgstr "" #. type: Plain text #: kraft.adoc:212 msgid "" "Of course the items in the documents can be edited after they got picked " "from a catalog." msgstr "" #. type: Plain text #: kraft.adoc:214 msgid "By default Kraft comes with two different catalogs:" msgstr "" #. type: Plain text #: kraft.adoc:216 msgid "`Material`" msgstr "" #. type: Plain text #: kraft.adoc:219 msgid "" "A catalog of material that are sold, with their purchase prices, the profit " "and the sell-price." msgstr "" #. type: Plain text #: kraft.adoc:221 msgid "and `Standard Templates`" msgstr "" #. type: Plain text #: kraft.adoc:223 msgid "A catalog of standard recipes of work like planting trees." msgstr "" #. type: Plain text #: kraft.adoc:226 msgid "" "Both catalogs can have chapters and sub-chapters for to organize your " "templates. First we are going to fill in the" msgstr "" #. type: Title === #: kraft.adoc:227 #, no-wrap msgid "Material Catalog" msgstr "" #. type: Plain text #: kraft.adoc:232 msgid "" "A catalog of material that are sold, with their purchase prices, the profit " "and the sell-price. First we are going to add new chapters and subchapters." msgstr "" #. type: Title ==== #: kraft.adoc:233 #, no-wrap msgid "New chapters" msgstr "" #. type: Plain text #: kraft.adoc:237 msgid "" "Select with the mouse the column-name `material`, select now in the " "context-menu [Add a sub chapter]" msgstr "" #. type: Plain text #: kraft.adoc:239 msgid "and add an extra chapter like `Trees`" msgstr "" #. type: Title ==== #: kraft.adoc:240 #, no-wrap msgid "New sub chapters" msgstr "" #. type: Plain text #: kraft.adoc:248 msgid "" "We are going to ad sub chapters in the map `Trees`. Select with the mouse " "the name of the chapter where you like to add a subchapter, select now in " "the context-menu [Add a sub chapter] and ad an extra subchapters like `Loaf " "trees` and `needle trees`. After adding the extra chapters and subchapters " "for dividing the material, we are going to add the material themself." msgstr "" #. type: Title ==== #: kraft.adoc:249 #, no-wrap msgid "New template" msgstr "" #. type: Plain text #: kraft.adoc:254 msgid "" "Select with the mouse the name of the sub-chapter or chapter where you like " "to add a material. Select the sub map Loaf trees and select now in the " "context-menu" msgstr "" #. type: Plain text #: kraft.adoc:257 msgid "Add the extra materials `coconut tree`, `apple tree` and `pine-apple tree`." msgstr "" #. type: Plain text #: kraft.adoc:259 msgid "Fill in the price that we have paid." msgstr "" #. type: Plain text #: kraft.adoc:261 msgid "Fill in the profit that we want to have on the material" msgstr "" #. type: Plain text #: kraft.adoc:263 msgid "And fill in how much is in a packet." msgstr "" #. type: Plain text #: kraft.adoc:266 msgid "" "image:catalog_material.png[Material catalog,float=\"right\"] After this we " "add also in the map 'Wood' a item for a 'support pole' for later use with " "its price." msgstr "" #. type: Plain text #: kraft.adoc:268 msgid "Now we are going to:" msgstr "" #. type: Title === #: kraft.adoc:269 #, no-wrap msgid "Standard Templates" msgstr "" #. type: Plain text #: kraft.adoc:272 msgid "This is a catalog of standard recipes of work like:" msgstr "" #. type: Plain text #: kraft.adoc:274 msgid "planting trees" msgstr "" #. type: Plain text #: kraft.adoc:275 msgid "cutting grass" msgstr "" #. type: Plain text #: kraft.adoc:276 msgid "transport costs" msgstr "" #. type: Plain text #: kraft.adoc:277 msgid "planting grass" msgstr "" #. type: Plain text #: kraft.adoc:278 msgid "sowing grass-seed" msgstr "" #. type: Plain text #: kraft.adoc:280 msgid "We add here the standard work of planting a tree." msgstr "" #. type: Plain text #: kraft.adoc:283 msgid "" "Select with the mouse the name of the chapter [Work] where you like to add " "the new template," msgstr "" #. type: Plain text #: kraft.adoc:285 msgid "select now the context-menu [New template]" msgstr "" #. type: Plain text #: kraft.adoc:287 msgid "and the extra templates `Plant tree` and `cut grass`." msgstr "" #. type: Plain text #: kraft.adoc:289 msgid "After we made the new template, a window opens with 4 tabs:" msgstr "" #. type: Title ==== #: kraft.adoc:291 kraft.adoc:297 #, no-wrap msgid "Template" msgstr "" #. type: Title ==== #: kraft.adoc:292 kraft.adoc:309 #, no-wrap msgid "Time calculation" msgstr "" #. type: Plain text #: kraft.adoc:293 msgid "Fix costs" msgstr "" #. type: Title ==== #: kraft.adoc:294 kraft.adoc:346 #, no-wrap msgid "Material" msgstr "" #. type: Plain text #: kraft.adoc:296 msgid "First we go to the tab:" msgstr "" #. type: Plain text #: kraft.adoc:301 msgid "" "We give here the name of the new standard template like `Plant tree` " "image:catalog_standard.png[Standard catalog,float=\"right\"]" msgstr "" #. type: delimited block _ #: kraft.adoc:304 msgid "WARNING: be careful, this name is later used in the invoice" msgstr "" #. type: Plain text #: kraft.adoc:308 msgid "" "we select that this is per piece and that the margin is 8% and that the full " "VAT is applicable." msgstr "" #. type: Plain text #: kraft.adoc:312 msgid "We fill here in a number of work with the time:" msgstr "" #. type: Block title #: kraft.adoc:313 #, no-wrap msgid "Spent time" msgstr "" #. type: Table #: kraft.adoc:320 #, no-wrap msgid "" "|Dig hole |32 min. |worker\n" "|Place tree |12 min. |worker\n" "|Fill hole |17 min. |worker\n" "|give water |5 min. |worker\n" msgstr "" #. type: Plain text #: kraft.adoc:324 msgid "" "The cost for worker which we have earlier filled in is now used. " "image:catalog_standard_work.png[Time calculation,float=\"right\"]" msgstr "" #. type: delimited block _ #: kraft.adoc:328 msgid "" "NOTE: in the invoice we see later only Plant tree, we will not see the parts " "dig hole,place tree,fill hole,give water" msgstr "" #. type: Plain text #: kraft.adoc:331 msgid "Now we go to the tab" msgstr "" #. type: Title ==== #: kraft.adoc:332 #, no-wrap msgid "Fixed costs" msgstr "" #. type: Plain text #: kraft.adoc:335 msgid "and fill in:" msgstr "" #. type: Block title #: kraft.adoc:336 #, no-wrap msgid "Fixed item" msgstr "" #. type: Table #: kraft.adoc:340 #, no-wrap msgid "|Transportcost |35 euro |1 pcs.\n" msgstr "" #. type: Plain text #: kraft.adoc:343 msgid "image:catalog_standard_fixed_cost.png[Fixed cost,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:345 msgid "After this we go to the tab:" msgstr "" #. type: Plain text #: kraft.adoc:350 msgid "" "Here we select btn:[next], after which the window [Add Material to " "Calculation] opens for a selection of material. We navigate to the map " "'wood' where we select the 'support pole'." msgstr "" #. type: Block title #: kraft.adoc:351 #, no-wrap msgid "Used materials" msgstr "" #. type: Table #: kraft.adoc:355 #, no-wrap msgid "|1 |support pole |3,5 euro\n" msgstr "" #. type: Plain text #: kraft.adoc:358 msgid "image:catalog_standard_material.png[Material,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:360 msgid "We go now back to the first tab template" msgstr "" #. type: Plain text #: kraft.adoc:363 msgid "On the first tab [template], we can now see the overall cost per one unit" msgstr "" #. type: Plain text #: kraft.adoc:366 msgid "" "Click on [OK] for saving the result or on [cancel] for discarding the " "result." msgstr "" #. type: Plain text #: kraft.adoc:368 msgid "We make a second template `cut grass`" msgstr "" #. type: Plain text #: kraft.adoc:371 msgid "" "we fill in `cut grass`, as unit we choose sm (square meter), on the second " "tab we fill in that we need 3 min per square meter." msgstr "" #. type: Plain text #: kraft.adoc:374 msgid "" "Click on [OK] for saving the result or on [Cancel] for discarding the " "result." msgstr "" #. type: Plain text #: kraft.adoc:376 msgid "'''" msgstr "" #. type: Title === #: kraft.adoc:377 #, no-wrap msgid "Header- and Footer Text Templates" msgstr "" #. type: Plain text #: kraft.adoc:380 msgid "" "Kraft supports text templates also for the header- and footer-text of " "documents. Each document type has it's own set of text templates. To access " "them, open a document of a certain document type in edit mode and use the " "btn:[show templates] to make the templates visible. In both the header- and " "footer-section the stored templates become visible." msgstr "" #. type: Plain text #: kraft.adoc:382 msgid "" "Directly under the navigation pane on the right side of the window is a list " "of the names of the available templates. Clicking on one of the names in the " "list displays the text in the pane below." msgstr "" #. type: Plain text #: kraft.adoc:384 msgid "" "Underneath there are buttons located with the following functions from left " "to right:" msgstr "" #. type: Plain text #: kraft.adoc:386 msgid "" "Add the template to the document: This button replaces the text of the " "document with the selected template." msgstr "" #. type: Plain text #: kraft.adoc:387 msgid "" "Insert the template to the document: The selected template is inserted to " "the current place of the cursor in the document." msgstr "" #. type: Plain text #: kraft.adoc:388 msgid "" "Create a new template: Opens a dialog to enter a complete new template for " "the current doc type." msgstr "" #. type: Plain text #: kraft.adoc:389 msgid "" "Edit the current template: Opens the dialog to edit the currently selected " "template." msgstr "" #. type: Plain text #: kraft.adoc:390 msgid "" "Delete the current template: Removes the template permanently from the list " "of available templates." msgstr "" #. type: Plain text #: kraft.adoc:392 msgid "" "Templates with the name _Standard_ are the default templates for the " "document type. They are inserted automatically if a document of this type is " "created." msgstr "" #. type: Title ==== #: kraft.adoc:394 #, no-wrap msgid "Macros" msgstr "" #. type: Plain text #: kraft.adoc:397 msgid "" "Both the header- and footer-templates can contain so called macros which are " "replaced with calculated values once the document is rendered to the final " "output format." msgstr "" #. type: Plain text #: kraft.adoc:399 msgid "The following list of macros are supported:" msgstr "" #. type: Plain text #: kraft.adoc:401 msgid "" "`DATE_ADD_DAYS()`: Returns the date of the of document plus the " "number of days specified as parameter to the macro." msgstr "" #. type: Plain text #: kraft.adoc:402 msgid "" "`ITEM_COUNT_WITH_TAG()`: Returns the amount of items tagged with the " "tag." msgstr "" #. type: Plain text #: kraft.adoc:403 msgid "" "`NETTO_SUM_PER_TAG()`: Returns the netto sum of all items that are " "tagged with the named tag." msgstr "" #. type: Plain text #: kraft.adoc:404 msgid "" "`BRUTTO_SUM_PER_TAG()`: Returns the brutto sum of all items that are " "tagged with the named tag." msgstr "" #. type: Plain text #: kraft.adoc:405 msgid "" "`VAT_SUM_PER_TAG()`: Returns the pure tax of all items that are tagged " "with the named tag." msgstr "" #. type: Plain text #: kraft.adoc:406 msgid "" "`IF_ANY_HAS_TAG()` and `END_HAS_TAG`: Includes the text between the two " "macros only if there is at least one item that is tagged with the tag." msgstr "" #. type: Plain text #: kraft.adoc:408 msgid "" "As an example, this footer text template can be used to automatically " "generate useful texts:" msgstr "" #. type: Plain text #: kraft.adoc:411 msgid "" "``` Please pay this invoice until three weeks after the date of the " "document, which is the DATE_ADD_DAYS(21)." msgstr "" #. type: Plain text #: kraft.adoc:417 msgid "" "IF_ANY_HAS_TAG(Material) This invoice lists material in " "ITEM_COUNT_WITH_TAG(Material) items. The net value is " "NETTO_SUM_PER_TAG(Material), plus VAT_SUM_PER_TAG(Material) = " "BRUTTO_SUM_PER_TAG(Material). END_HAS_TAG ```" msgstr "" #. type: Plain text #: kraft.adoc:419 msgid "We are now ready for the first invoice." msgstr "" #. type: Title == #: kraft.adoc:421 #, no-wrap msgid "Creating Documents" msgstr "" #. type: Title === #: kraft.adoc:423 #, no-wrap msgid "The first Invoice" msgstr "" #. type: Plain text #: kraft.adoc:426 msgid "Open the tab btn:[documents]" msgstr "" #. type: Plain text #: kraft.adoc:428 kraft.adoc:533 msgid "Click on btn:[create document]" msgstr "" #. type: Plain text #: kraft.adoc:430 msgid "The window document [creation wizard opens]." msgstr "" #. type: Plain text #: kraft.adoc:432 msgid "Select in document type `invoice`." msgstr "" #. type: Plain text #: kraft.adoc:435 msgid "" "Fill in on the whiteboard content a short text about what the invoice is, " "like: `cut grass and planted tree for mister Jonson`" msgstr "" #. type: Plain text #: kraft.adoc:437 kraft.adoc:542 msgid "Click on btn:[next]" msgstr "" #. type: Plain text #: kraft.adoc:439 kraft.adoc:544 msgid "Select on the new window the name and address from the client." msgstr "" #. type: Plain text #: kraft.adoc:442 kraft.adoc:547 msgid "" "(if the name and address is not there, click then on btn:[new contact] or on " "btn:[edit contact] if you want to edit the contact)" msgstr "" #. type: Plain text #: kraft.adoc:444 kraft.adoc:549 msgid "Click on btn:[OK]." msgstr "" #. type: Plain text #: kraft.adoc:446 msgid "Now opens the window document [items]." msgstr "" #. type: Plain text #: kraft.adoc:448 msgid "this window has 2 tabs and the 3 buttons on the top:" msgstr "" #. type: Plain text #: kraft.adoc:450 kraft.adoc:555 msgid "btn:[Add item...]," msgstr "" #. type: Plain text #: kraft.adoc:451 kraft.adoc:556 msgid "btn:[Add discount item]," msgstr "" #. type: Plain text #: kraft.adoc:452 kraft.adoc:557 msgid "btn:[Show templates]." msgstr "" #. type: Plain text #: kraft.adoc:456 msgid "" "In the left tab you can see all the items that we want to place on the " "invoice, on the right tab we see the text from the header, the total price " "and the footer." msgstr "" #. type: Plain text #: kraft.adoc:460 msgid "" "If you click on the text of the header or the footer on the right side then " "the window changes in such a way that you can edit the header or the footer." msgstr "" #. type: Plain text #: kraft.adoc:463 msgid "" "Adapt the header and the footer to your situation, on the footer you can " "place a text: `We make your garden-dream come to reality.`." msgstr "" #. type: Plain text #: kraft.adoc:465 kraft.adoc:559 msgid "Click on the button btn:[Show templates]." msgstr "" #. type: Plain text #: kraft.adoc:469 msgid "" "The right tab changes and show now the earlier made templates, we select in " "the group Work, the subgroup Plant tree and click then on the button with " "the to the left pointing arrow on the bottom side." msgstr "" #. type: Plain text #: kraft.adoc:471 kraft.adoc:565 msgid "A new window [Create Item from Template] opens." msgstr "" #. type: Plain text #: kraft.adoc:474 msgid "" "Because we have planted 2 trees, we go to the field [insert] and change this " "to 2 pcs." msgstr "" #. type: Plain text #: kraft.adoc:477 msgid "" "Click on btn:[OK] for saving the result or on btn:[cancel] for discarding " "the result." msgstr "" #. type: Plain text #: kraft.adoc:479 kraft.adoc:573 kraft.adoc:584 msgid "The window close and we go back to the main window." msgstr "" #. type: Plain text #: kraft.adoc:483 msgid "" "We click again on btn:[Show templates] and select this time `cut grass`, we " "click again on the button with the arrow, in the opened window we select " "that the grass-field was 24 square meter." msgstr "" #. type: Plain text #: kraft.adoc:486 kraft.adoc:571 kraft.adoc:604 kraft.adoc:640 msgid "" "Click on btn:[OK] for saving the result or on btn:[Cancel] for discarding " "the result." msgstr "" #. type: Plain text #: kraft.adoc:488 msgid "" "We add now manually an item by clicking on the button btn:[Add item…] and " "the window [create new item] opens." msgstr "" #. type: Plain text #: kraft.adoc:492 msgid "" "Because we have delivered a special tree, we fill here in the name of the " "special tree `liguster`, at the field insert we fill in the number of the " "special trees that we have delivered and the price of them." msgstr "" #. type: delimited block _ #: kraft.adoc:498 msgid "" "WARNING: Remind that in the catalog we can add a profit on the price of the " "material, in the invoice and in the offer we can not add a profit on the " "price of the material." msgstr "" #. type: Plain text #: kraft.adoc:501 msgid "We have now an invoice with 3 items." msgstr "" #. type: Plain text #: kraft.adoc:504 msgid "" "Click on btn:[OK] for saving the invoice or on btn:[Cancel] for discarding " "the invoice." msgstr "" #. type: Plain text #: kraft.adoc:506 msgid "We click on btn:[OK] and save the result." msgstr "" #. type: Plain text #: kraft.adoc:508 msgid "Your first invoice is now ready for sending." msgstr "" #. type: Plain text #: kraft.adoc:511 msgid "" "In the window documents we see our first invoice, notice that this document " "has a document number which we can see on the left side." msgstr "" #. type: Plain text #: kraft.adoc:514 msgid "" "On top of the window with all the invoices we see the button [Print " "Document], on which we click." msgstr "" #. type: Plain text #: kraft.adoc:517 msgid "" "From the invoice will now a PDF be made which we can print on paper or send " "by email to the client." msgstr "" #. type: Plain text #: kraft.adoc:519 msgid "After this we are going to create a offer for some work in a garden." msgstr "" #. type: Title === #: kraft.adoc:521 #, no-wrap msgid "Creating an Offer" msgstr "" #. type: Plain text #: kraft.adoc:524 msgid "" "The client has asked to plant a tree, we will offer 3 different trees which " "we can plant." msgstr "" #. type: Plain text #: kraft.adoc:527 msgid "" "Beside this, we have seen that there is a lifeless three, which we will " "offer to remove as extra work. " "image:create_new_doc.png[Numbercycles,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:529 msgid "" "For the total price we do not want to show the price of the removal of the " "lifeless tree and we want for the total price only to show the price of one " "tree and not three." msgstr "" #. type: Plain text #: kraft.adoc:531 msgid "Open again the tab btn:[documents]." msgstr "" #. type: Plain text #: kraft.adoc:535 msgid "The window _Document Creation Wizard_ opens." msgstr "" #. type: Plain text #: kraft.adoc:537 msgid "select in btn:[document type] > btn:[Offer]." msgstr "" #. type: Plain text #: kraft.adoc:540 msgid "" "Fill in on the whiteboard content a short text about what the offer is, " "like: `plant one tree and removal of lifeless tree`" msgstr "" #. type: Plain text #: kraft.adoc:551 msgid "Now the window [edit document] opens." msgstr "" #. type: Plain text #: kraft.adoc:553 msgid "This window has 2 tabs and the 3 buttons on the top:" msgstr "" #. type: Plain text #: kraft.adoc:563 msgid "" "The right tab changes and show now the earlier made templates, we select in " "the group `Work`, the subgroup `Plant tree` and click then on the button " "with the to the left pointing arrow on the bottom side." msgstr "" #. type: Plain text #: kraft.adoc:568 msgid "" "Because we want to plant 1 tree, we go to the field [insert] and keep this " "on 1 pcs." msgstr "" #. type: Plain text #: kraft.adoc:576 msgid "" "We click on the button btn:[Show templates] and this time we select in " "catalog Material" msgstr "" #. type: Plain text #: kraft.adoc:580 msgid "" "The material-catalog opens, and we can select in the chapter `trees` the " "subchapter `loaf trees` in which we select the `apple tree` which we made " "earlier." msgstr "" #. type: Plain text #: kraft.adoc:582 msgid "" "Click on we btn:[OK] for saving the result or on btn:[cancel] for discarding " "the result." msgstr "" #. type: Plain text #: kraft.adoc:586 msgid "We add now manually an item by clicking on the button `Add item…`." msgstr "" #. type: Plain text #: kraft.adoc:588 msgid "the window [create new item] opens." msgstr "" #. type: Plain text #: kraft.adoc:590 msgid "" "We want that the client can make a choice from an apple, a pear tree and the " "liguster." msgstr "" #. type: Plain text #: kraft.adoc:592 msgid "Therefor we are going to add also a pear tree manually." msgstr "" #. type: Plain text #: kraft.adoc:594 msgid "" "We click on the button btn:[Add item…] and the window [create new item] " "opens." msgstr "" #. type: Plain text #: kraft.adoc:598 msgid "" "We fill here in the name of the tree `Pear tree`, at the field insert we " "fill in the number of the special trees that we have delivered and the price " "of them." msgstr "" #. type: Plain text #: kraft.adoc:601 msgid "" "We want add this to the material catalog for future use, therefor we select " "also [select this item as template for future documents] and we select in " "[save in chapter]`trees`." msgstr "" #. type: Plain text #: kraft.adoc:606 msgid "We does this again but then for the liguster." msgstr "" #. type: Plain text #: kraft.adoc:608 msgid "We have now 3 items with trees in the offer." msgstr "" #. type: Plain text #: kraft.adoc:610 msgid "As last item we add an item with `remove tree` with 0,5 hour for 32 euro." msgstr "" #. type: Plain text #: kraft.adoc:612 msgid "On the left side of an item we can see 2 buttons:" msgstr "" #. type: Plain text #: kraft.adoc:614 msgid "a button with a flag and a button with what looks like a page." msgstr "" #. type: Plain text #: kraft.adoc:617 msgid "" "We select the upper button with the page after which opens a context-menu " "with the items:" msgstr "" #. type: Plain text #: kraft.adoc:619 msgid "image:context1.png[Context menu,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:629 #, no-wrap msgid "" " [Item kind]->[Normal]\n" " [Item kind]>[Alternative]\n" " [Item kind]>[On demand]\n" " [Tax]\n" " [Move up]\n" " [Move down]\n" " [Lock item]\n" " [Unlock item]\n" " [Delete item]\n" msgstr "" #. type: Plain text #: kraft.adoc:632 msgid "" "We choose here [Item kind] and change for `pear tree` from [normal] to " "[alternative]." msgstr "" #. type: Plain text #: kraft.adoc:635 msgid "" "We do this also for [liguster] and for [remove tree] we change this from " "[normal] to [on demand]." msgstr "" #. type: Plain text #: kraft.adoc:637 msgid "image:context2.png[Context menu,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:643 msgid "" "We want to see the result and therefor we click on the button [show " "document]." msgstr "" #. type: Plain text #: kraft.adoc:649 msgid "" "We see now that the prize of the pear tree, the liguster and the removal of " "the tree is not used for the total prize. When we are happy with the result, " "we can click on the button btn:[close] after which we click on the button " "btn:[Print Document] for making a PDF what we can print out or send to the " "client." msgstr "" #. type: Plain text #: kraft.adoc:652 msgid "After your first invoice is now your first offer now also ready for sending." msgstr "" #. type: Title === #: kraft.adoc:654 #, no-wrap msgid "Creating an Acceptance of Order" msgstr "" #. type: Plain text #: kraft.adoc:657 msgid "The document type \"Acceptance of Order\" is sent subsequently to an offer." msgstr "" #. type: Plain text #: kraft.adoc:659 msgid "image:acceptance_o_o_context.png[Numbercycles,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:662 msgid "" "When a client has made a request, we will send an offer in wich we describe " "which items we will deliver. Hopefully the client will give an order for " "the work." msgstr "" #. type: Plain text #: kraft.adoc:666 msgid "" "It is a good practice to respond on the order with an \"Acceptance of " "order\" in which we describe all the items we will deliver. We can make the " "\"Acceptance of order\" on the same way as we made the invoice or the offer " "by selecting each item and correcting the number of delivery. This takes " "time and we can make errors by forgetting items or filling an incorrect " "number." msgstr "" #. type: Plain text #: kraft.adoc:668 msgid "" "It can be done quicker by selecting the offer in the list and selecting " "btn:[Create Followup Document] from either the context menu or the main " "menu." msgstr "" #. type: Plain text #: kraft.adoc:670 msgid "We have now in documenttype the choice from:" msgstr "" #. type: Plain text #: kraft.adoc:676 #, no-wrap msgid "" " [Acceptance of order]\n" " [Invoice]\n" " [Partial Invoice]\n" " [final Invoice]\n" " [Progress Payment Invoice]\n" msgstr "" #. type: Plain text #: kraft.adoc:678 msgid "image:followup_1.png[Folloup document,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:682 msgid "" "We select here \"Acceptance of order\". We have now a copy from the offer " "as an Acceptance of order (do not forget to adapt Alternative Delivery items " "and on demand items.)" msgstr "" #. type: Plain text #: kraft.adoc:684 msgid "image:followup_2.png[Folloup document,float=\"right\"]" msgstr "" #. type: Plain text #: kraft.adoc:688 msgid "" "You can do this also for the creation of the invoice as a followup for " "Acceptance of order. Each document type has a specific list of follow up " "documents. It is a good practice to describe on the invoice precisely what " "was delivered." msgstr "" #. type: Title == #: kraft.adoc:690 #, no-wrap msgid "Customization" msgstr "" #. type: Plain text #: kraft.adoc:694 msgid "" "Kraft can be customized in most of the graphical user interface and in " "particular in the output it generates." msgstr "" #. type: Title === #: kraft.adoc:695 #, no-wrap msgid "Output Document Customization" msgstr "" #. type: Plain text #: kraft.adoc:698 msgid "" "To create PDF output documents, the document data that was edited in the " "Kraft app is filled into a template. The template defines how the output " "document looks like, ie. by font settings, placing of elements and such." msgstr "" #. type: Plain text #: kraft.adoc:700 msgid "" "The file that is assembled from data and the template is converted to PDF " "using a special document creation script. All that is started automatically " "by Kraft if a document should be printed." msgstr "" #. type: Plain text #: kraft.adoc:702 msgid "" "Each document type in Kraft can have it's own template that is used to " "create a PDF. Which one can be set in the Settings dialog for document " "types." msgstr "" #. type: Title ==== #: kraft.adoc:703 #, no-wrap msgid "WeasyPrint Documents" msgstr "" #. type: Plain text #: kraft.adoc:706 msgid "" "Kraft still ships with the old ReportLab based converter, but that will be " "deprecated the future. The WeasyPrint based system is the future. It is a " "recommended to port existing templates." msgstr "" #. type: Plain text #: kraft.adoc:708 msgid "" "With https://weasyprint.org[WeasyPrint] Kraft uses a very powerful generator " "that makes it very easy to create highly customized documents with great " "quality." msgstr "" #. type: Plain text #: kraft.adoc:710 msgid "" "WeasyPrint converts a html file to PDF. It is integrating a cascading " "stylesheet (CSS) file which has a huge impact on the PDF document's look." msgstr "" #. type: Plain text #: kraft.adoc:712 msgid "" "The html- and CSS input file for WeasyPrint is built from the Kraft template " "file." msgstr "" #. type: Plain text #: kraft.adoc:714 msgid "" "To enable the use of WeasyPrint for a document type in Kraft, simply create " "a weasyprint compatible template file and save it with the extension " "*.gtmpl*. Based on the file extension Kraft automatically uses WeasyPrint " "and the Grantlee templating engine for rendering." msgstr "" #. type: Plain text #: kraft.adoc:716 msgid "" "From version 0.95 on Kraft ships with an example template in the Grantlee- " "and WeasyPrint format. It can be found at " "`/usr/share/kraft/reports/invoice.gtmpl` or " "https://github.com/dragotin/kraft/blob/master/reports/invoice.gtmpl[online " "on Github]. An example CSS file `kraft.css` " "(https://github.com/dragotin/kraft/blob/master/reports/kraft.css[on Github]) " "is shipped as a good starting point for adoption." msgstr "" #. type: Title ==== #: kraft.adoc:717 #, no-wrap msgid "Template Variables" msgstr "" #. type: Plain text #: kraft.adoc:720 msgid "" "To generate the PDF, Kraft has to transfer data from the document you have " "been working on to the input file that is processed to a PDF. For that, " "Kraft uses a text template in which Kraft replaces variables with the actual " "values." msgstr "" #. type: Plain text #: kraft.adoc:722 msgid "" "For example, the tag `{{ doc.doctype }}` is replaced with the current " "document type during the generating process." msgstr "" #. type: Plain text #: kraft.adoc:724 msgid "" "The syntax is based on the Django syntax for templates described in the " "https://docs.djangoproject.com/en/3.1/topics/templates/[the docs]." msgstr "" #. type: Title ==== #: kraft.adoc:725 #, no-wrap msgid "EPC QR Code" msgstr "" #. type: Plain text #: kraft.adoc:728 msgid "" "With Weasyprint based PDF generation Kraft supports the " "https://en.wikipedia.org/wiki/EPC_QR_code[EPC QR Code] which implements a " "European standard for payments by computer and mobile devices." msgstr "" #. type: Plain text #: kraft.adoc:730 msgid "" "In Germany it is also known as _Giro Code_, in Belgium as _Bancontact QR_, " "in the Netherlands as _iDEAL QR-code_ and in Spain it is also known as " "_Bizum QR-code_." msgstr "" #. type: Plain text #: kraft.adoc:732 msgid "" "In Germany it is accepted by the _Giro Code_ and in Holland it is accepted " "by the official https://www.ideal.nl/consumenten/ideal-app/[_iDEAL QR-code_] " "app." msgstr "" #. type: Plain text #: kraft.adoc:734 msgid "" "In Belgium and Holland it is accepted by the apps of many banks, and in " "Austria and Finland it is accepted by the apps of all banks." msgstr "" #. type: Plain text #: kraft.adoc:736 msgid "" "To use the EPC QR code on the invoice printout, the bank account information " "has to be added to own identity settings dialog in Kraft. The giro code is " "current only generated for documents with the document type `Rechnung`." msgstr "" #. type: Plain text #: kraft.adoc:738 msgid "" "To include the generated EPC QR Code into the PDF document, the Weasyprint " "template needs to contain a snippet like this:" msgstr "" #. type: Plain text #: kraft.adoc:748 #, no-wrap msgid "" "```\n" " {%if doc.isInvoice and epcqrcode.valid %}\n" "

\n" " \n" " Dieser QR Code ermöglicht einfaches, sicheres und schnelles " "Begleichen dieser Rechnung via GiroPay:\n" " Diesen Code mit dem Smartphone scannen und Überweisung per Banking " "App aufgeben.\n" "

\n" " {% endif %}\n" "```\n" msgstr "" #. type: Title == #: kraft.adoc:751 #, no-wrap msgid "Menus and Shortcuts" msgstr "" #. type: Title === #: kraft.adoc:753 #, no-wrap msgid "Main Application Menu" msgstr "" #. type: Title ==== #: kraft.adoc:756 #, no-wrap msgid "The File Menu" msgstr "" #. type: Plain text #: kraft.adoc:761 #, no-wrap msgid "" " [File]>[Quit]\n" " [Ctrl]+[Q]\n" " Quits the application.\n" msgstr "" #. type: Title ==== #: kraft.adoc:763 #, no-wrap msgid "The Document Menu" msgstr "" #. type: Plain text #: kraft.adoc:769 #, no-wrap msgid "" " [Document]>[Show Document]\n" " [Ctrl]+[R]\n" " Opens a window with the selected document for showing it.\n" msgstr "" #. type: Plain text #: kraft.adoc:773 #, no-wrap msgid "" " [Document]>[Edit Document]\n" " [Ctrl+O]\n" " Opens a window with the selected document for editing it.\n" msgstr "" #. type: Plain text #: kraft.adoc:777 #, no-wrap msgid "" " [Document]>[Open Archived document]\n" " [Ctrl]+[A]\n" " Opens an archived document.\n" msgstr "" #. type: Plain text #: kraft.adoc:780 #, no-wrap msgid "" " [Document]>[Create Document]\n" " Opens a window with a wizard for creating a new client-document.\n" msgstr "" #. type: Plain text #: kraft.adoc:784 #, no-wrap msgid "" " [Document]>[Copy Document]\n" " Makes a copy of the selected client-document to a new client-document\n" " which can belong to an other client or an other documenttype.\n" msgstr "" #. type: Plain text #: kraft.adoc:787 #, no-wrap msgid "" " [Document]>[Follow Document]\n" " Opens the selected client-document for editing.\n" msgstr "" #. type: Plain text #: kraft.adoc:791 #, no-wrap msgid "" " [Document]>[Print document]\n" " Makes a PDf from the selected client-document for to be mailed or\n" " printed.\n" msgstr "" #. type: Plain text #: kraft.adoc:795 #, no-wrap msgid "" " [Document]>[Mail document]\n" " [Ctrl]+[M]\n" " Mails a document.\n" msgstr "" #. type: Title ==== #: kraft.adoc:798 #, no-wrap msgid "The Settings menu" msgstr "" #. type: Plain text #: kraft.adoc:804 #, no-wrap msgid "" " [Settings]>[Edit Tag Templates]\n" " [Ctrl]+[E]\n" " Opens a window where you add, edit or translate the tags (like work,\n" " material, plants or discounts).\n" msgstr "" #. type: Plain text #: kraft.adoc:808 #, no-wrap msgid "" " [Settings]>[Redo initial setup]\n" " [Ctrl+R]\n" " Redoes the initial setup. After this, a restart of Kraft is required.\n" msgstr "" #. type: Plain text #: kraft.adoc:812 #, no-wrap msgid "" " [Settings]>[Showed toolbars]\n" " Here you can decide if the `main toolbar` and the toolbar `Document " "Actions`\n" " are shown.\n" msgstr "" #. type: Plain text #: kraft.adoc:816 #, no-wrap msgid "" " [Settings]>[Configure Kraft]\n" " [Ctrl]+[Shft]+[,]\n" " Here you can configure Kraft.\n" msgstr "" #. type: Title === #: kraft.adoc:817 #, no-wrap msgid "Document Edit Window" msgstr "" #. type: Title ==== #: kraft.adoc:820 #, no-wrap msgid "The context Menu" msgstr "" #. type: Plain text #: kraft.adoc:824 #, no-wrap msgid "" " [Context]>[Item kind]\n" " change the status from this item between\n" msgstr "" #. type: Plain text #: kraft.adoc:825 #, no-wrap msgid "Normal\n" msgstr "" #. type: Plain text #: kraft.adoc:826 #, no-wrap msgid "Alternative\n" msgstr "" #. type: Plain text #: kraft.adoc:827 #, no-wrap msgid "On demand\n" msgstr "" #. type: Plain text #: kraft.adoc:830 #, no-wrap msgid "" " [Context]>[Tax]\n" " Seems not working.\n" msgstr "" #. type: Plain text #: kraft.adoc:833 #, no-wrap msgid "" " [Context]>[Move up]\n" " Moves this item a place up in document.\n" msgstr "" #. type: Plain text #: kraft.adoc:836 #, no-wrap msgid "" " [Context]>[Move down]\n" " Moves this item a place down in document.\n" msgstr "" #. type: Plain text #: kraft.adoc:839 #, no-wrap msgid "" " [Context]>[Lock item]\n" " It is not clear what is does.\n" msgstr "" #. type: Plain text #: kraft.adoc:842 #, no-wrap msgid "" " [Context]>[Unlock item]\n" " It is not clear what is does.\n" msgstr "" #. type: Plain text #: kraft.adoc:845 #, no-wrap msgid "" " [Context]>[Delete item]\n" " Removes this item from document.\n" msgstr "" #. type: Title == #: kraft.adoc:848 #, no-wrap msgid "Advanced Topics" msgstr "" #. type: Plain text #: kraft.adoc:851 msgid "" "This chapter describes advanced topics around Kraft. Some Linux knowledge is " "required, and setups should be done by experienced Linux administrators and " "should be tested carefully." msgstr "" #. type: Title === #: kraft.adoc:852 #, no-wrap msgid "Using Kraft Collaboratively" msgstr "" #. type: Plain text #: kraft.adoc:855 msgid "" "Kraft can be used collaborative in a distributed environment. That means " "that multiple users work on their desktops with their own Kraft instance on " "the same data." msgstr "" #. type: Plain text #: kraft.adoc:857 msgid "" "This whole topic is a subject to change, as Kraft will evolve to use " "ownCloud as a private cloud solution to store the data." msgstr "" #. type: Title ==== #: kraft.adoc:858 #, no-wrap msgid "Sharing Database and Document Pool" msgstr "" #. type: Plain text #: kraft.adoc:861 msgid "" "The simplest case is that two or more Kraft instances use a database " "together and access the same pool of PDF documents on the harddisk. For " "simplicity this describes only two Kraft instances." msgstr "" #. type: Plain text #: kraft.adoc:863 msgid "" "A typical use case would be: Two different Linux users want to use " "Kraft. They both have their own computer but only work in the same " "network. For example this would describe a situation with one main office " "machine that runs Kraft in normal mode, plus a notebook with Kraft in read " "only mode to view documents, check catalogs and such." msgstr "" #. type: Plain text #: kraft.adoc:865 msgid "For that, the following prerequisites have to be met:" msgstr "" #. type: Plain text #: kraft.adoc:867 msgid "MySQL or MariaDB is used as database backend. Sqlite is not supported." msgstr "" #. type: Plain text #: kraft.adoc:868 msgid "" "The database is accessible with a mysql user and from each machine for both " "users." msgstr "" #. type: Plain text #: kraft.adoc:869 msgid "The document store directory has to be shared." msgstr "" #. type: delimited block _ #: kraft.adoc:873 msgid "" "WARNING: There is no protection against having both users editing the same " "document. Because that is dangerous and can lead to unpredictable results, " "it is recommended to run all instances of Kraft except the main one in read " "only mode. This is done by starting Kraft with the `-r` command line switch." msgstr "" #. type: Plain text #: kraft.adoc:876 #, no-wrap msgid "**Sharing the Database**\n" msgstr "" #. type: Plain text #: kraft.adoc:878 msgid "" "The database server should be installed on the main machine or a dedicated " "device like a NAS. Networking speed influences the comfort to use obviously." msgstr "" #. type: Plain text #: kraft.adoc:880 msgid "Find howtos on the internet how to setup MySQL accordingly." msgstr "" #. type: Plain text #: kraft.adoc:882 #, no-wrap msgid "**Sharing the Document Pool Directory**\n" msgstr "" #. type: Plain text #: kraft.adoc:884 msgid "" "Kraft writes generated PDF documents into a local directory. Where that is " "can be configured in the Kraft Config file. The config file has to be " "adopted on all instances." msgstr "" #. type: Plain text #: kraft.adoc:886 msgid "" "That is located in each users home directory, in the path " "`.config/kraftrc`. It has to contain the following config value:" msgstr "" #. type: Plain text #: kraft.adoc:888 kraft.adoc:892 msgid "```" msgstr "" #. type: Plain text #: kraft.adoc:890 msgid "PdfOutputDir=/data/space/kraftdoc/pdf" msgstr "" #. type: Plain text #: kraft.adoc:894 msgid "" "There are different ways how share that directory, ie. NFS or SMB " "storages. It is important that both users from both machines can list and " "access the files. The main user needs read and write access, read only users " "only need read access to the files." msgstr "" #. type: Plain text #: kraft.adoc:896 msgid "" "A recommended setup is a NFS share with autofs which is set up on the main " "machine. To manage file access a certain group should be set up on the " "machines with which access can be managed." msgstr "" #. type: Plain text #: kraft.adoc:898 #, no-wrap msgid "**Starting Kraft in read-only mode**\n" msgstr "" #. type: Plain text #: kraft.adoc:900 msgid "" "To start Kraft in read-only mode, start the binary with the `-r` command " "line switch." msgstr "" #. type: Title === #: kraft.adoc:901 #, no-wrap msgid "XRechnung Support" msgstr "" #. type: Plain text #: kraft.adoc:904 msgid "" "Kraft supports the XRechnung standard. That is a digital format for " "electronic invoicing, and it passed as law in Germany and follows a EU " "directive. The XRechnung is a XML file format designed for that purpose." msgstr "" #. type: Plain text #: kraft.adoc:906 msgid "" "To use the XRechnung Export productivly, a little manual work is still " "needed in Kraft. Kraft creates the XML file based on a template, very " "similar to the normal PDF documents. That means that it loads a template " "that contains static elements (ie. the company address) that do not change " "between different invoices. The dynamic elements (customer data, items etc.) " "are filled into the template during the generation step." msgstr "" #. type: Plain text #: kraft.adoc:908 msgid "" "In order to generate correct XRechnung files for the specific company, the " "user has to adopt the template file manually to the companies needs. Note " "that this has only to be done once and should be easy for a person with a " "bit computer experience (Basic knowledge about XML appreciated!)." msgstr "" #. type: Plain text #: kraft.adoc:910 msgid "" "To adapt the file to the needs of the company, it is best to start with the " "https://raw.githubusercontent.com/dragotin/kraft/master/reports/xrechnung.xrtmpl[example " "XRechnung file]. It has to be downloaded and saved into a location that the " "user can edit. Open it in a normal text editor, such as " "https://kate-editor.org/[Kate]." msgstr "" #. type: Plain text #: kraft.adoc:912 msgid "" "Read carefully through the file without being scared off by the XML " "format. All user strings (ie. company name, address and such) are user " "specific and should be replaced accordingly. Find " "https://www.xoev.de/xrechnung-16828[details about the format] here to better " "understand the meaning of the fields." msgstr "" #. type: Plain text #: kraft.adoc:914 msgid "" "Make sure to not disturb the proper XML format and do not change places " "where the template format `{{ template_name }}` is used." msgstr "" #. type: Plain text #: kraft.adoc:916 msgid "" "Once the file is adopted to the needs, open the Settings dialog of Kraft and " "insert the filename into the entry field for the XRechnung Template File on " "the Document Defaults page." msgstr "" #. type: Plain text #: kraft.adoc:918 msgid "" "After that step, the btn:[Export XRechung] menu item will open a dialog to " "pick a filename where to save the XRechnung invoice to." msgstr "" #. type: Plain text #: kraft.adoc:920 msgid "This file can now be transfered to the receiver of the invoice." msgstr "" #. type: Plain text #: kraft.adoc:922 msgid "" "There are validators for invoices in XRechnung format out there in the " "internet. It is useful to verify the format of the Kraft exported XRechnung." msgstr "" #. type: Title === #: kraft.adoc:923 #, no-wrap msgid "Changing the Locale" msgstr "" #. type: Plain text #: kraft.adoc:926 msgid "" "If it is needed that Kraft runs under a different locale than the actual " "desktop environment, this can be achieved by setting the desired locale in " "the start file of Kraft." msgstr "" #. type: Plain text #: kraft.adoc:928 msgid "" "On the linux desktop, apps are usually started through a so called " "https://specifications.freedesktop.org/desktop-entry-spec/latest/[desktop " "file]. It contains the information how the Kraft binary is started if user " "clicks on the icon on the desktop or in the start menu." msgstr "" #. type: Plain text #: kraft.adoc:930 msgid "" "The desktop file can usually be found in " "`/usr/share/applications/de.volle-kraft-voraus.kraft.desktop`." msgstr "" #. type: Plain text #: kraft.adoc:936 msgid "" "It contains the line ``` Exec=kraft %u ``` which starts the application with " "the default locale." msgstr "" #. type: Plain text #: kraft.adoc:942 msgid "" "Changing it to ``` Exec=env LANG=de_DE.UTF-8 kraft %u ``` would change that " "to run in the German locale for example, independent from the desktop " "environment location." msgstr "" #. type: Title == #: kraft.adoc:945 #, no-wrap msgid "Credits and License" msgstr "" #. type: Plain text #: kraft.adoc:948 msgid "Program and documentation copyright 2004–2023 Klaas Freitag" msgstr "" #. type: Plain text #: kraft.adoc:949 msgid "Documentation copyright 2020-2023 Ronald Stroethoff" msgstr "" kraft-1.1/meta/000077500000000000000000000000001450127457600134235ustar00rootroot00000000000000kraft-1.1/meta/CMakeLists.txt000066400000000000000000000004201450127457600161570ustar00rootroot00000000000000########### install files ############### install(FILES kraft.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} RENAME de.volle_kraft_voraus.kraft.desktop) install(FILES kraft.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR} RENAME de.volle_kraft_voraus.kraft.appdata.xml) kraft-1.1/meta/kraft.appdata.xml000066400000000000000000000034771450127457600167000ustar00rootroot00000000000000 de.volle_kraft_voraus.kraft.desktop GPL-2.0+ CC0-1.0 Kraft Kraft helps to handle documents in small business

Kraft is free software to help to handle documents like quotes and invoices in your small business. It is a Qt/KF5 based desktop software with a strong focus on ease of use and the just enough feature set for the use case. With Kraft, creating documents will run smooth and free time for more enjoyable things than office work.

Kraft runs on any Linux desktop. There is no cloud involved, your data around your products and customers stays under your control.

With Kraft, writing documents like quotes and invoices is very easy and fast. Repeating tasks are supported, documents can be generated semi automatically, ie. invoices from offers sent out before.

For efficient work, Kraft supports catalogs to organize materials and template texts. It focuses on high quality printouts because paper is still the main communication media in the small business world. However, it also sends documents via email.

https://volle-kraft-voraus.de/images/appmeta1.png Main window of Kraft https://volle-kraft-voraus.de/images/appmeta2.png Document edit window, header section https://volle-kraft-voraus.de/ kraft_AT_volle-kraft-voraus.de kraft
kraft-1.1/meta/kraft.desktop000066400000000000000000000010111450127457600161160ustar00rootroot00000000000000[Desktop Entry] Type=Application Exec=kraft %u Icon=kraft X-DocPath=kraft/index.html Terminal=false Name=Kraft Name[ast]=Kraft Name[bs]=Kraft Name[cs]=Kraft Name[da]=Kraft Name[de]=Kraft Name[es]=Kraft Name[et]=Kraft Name[fi]=Kraft Name[fr]=Kraft Name[ga]=Kraft Name[gl]=Kraft Name[hu]=Kraft Name[mr]=क्राफ्ट Name[nl]=Kraft Name[pl]=Kraft Name[pt]=Kraft Name[pt_BR]=Kraft Name[sk]=Kraft Name[sv]=Kraft Name[tr]=Kraft Name[ug]=Kraft Name[uk]=Kraft Name[x-test]=xxKraftxx Categories=Office;Finance;Database; kraft-1.1/po/000077500000000000000000000000001450127457600131135ustar00rootroot00000000000000kraft-1.1/po/de/000077500000000000000000000000001450127457600135035ustar00rootroot00000000000000kraft-1.1/po/de/kraft.po000066400000000000000000003455641450127457600151730ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # # Translators: # Klaas Freitag , 2023 # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-09-10 18:34+0200\n" "PO-Revision-Date: 2018-10-31 21:56+0000\n" "Last-Translator: Klaas Freitag , 2023\n" "Language-Team: German (https://app.transifex.com/kraftproject/teams/93132/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" #: models/docbasemodel.cpp:32 docdigestdetailview.cpp:413 #, kde-format msgid "Date" msgstr "Datum" #: models/docbasemodel.cpp:33 #, kde-format msgid "Doc. Number" msgstr "Dokumentennummer" #: models/docbasemodel.cpp:34 #, kde-format msgid "Doc. Type" msgstr "Dokumenttyp" #: models/docbasemodel.cpp:35 docdigestdetailview.cpp:418 #, kde-format msgid "Whiteboard" msgstr "Notizen" #: models/docbasemodel.cpp:36 #, kde-format msgid "Client Id" msgstr "Kundenkennung" #: models/docbasemodel.cpp:37 #, kde-format msgid "Last modified" msgstr "Zuletzt geändert" #: models/docbasemodel.cpp:38 #, kde-format msgid "Creation date" msgstr "Erstellungsdatum" #: models/docbasemodel.cpp:39 docdigestdetailview.cpp:423 #, kde-format msgid "Project" msgstr "Projekt" #: models/docbasemodel.cpp:40 #, kde-format msgid "Client Address" msgstr "Kundenadresse" #: models/docbasemodel.cpp:41 #, kde-format msgid "Client" msgstr "Kunde" #: models/docbasemodel.cpp:109 #, kde-format msgid "Looking up address" msgstr "Adresse wird gesucht" #: models/docbasemodel.cpp:111 #, kde-format msgid "Lookup started" msgstr "Suche gestartet" #: documentman.cpp:93 #, kde-format msgctxt "" "Text to be inserted into a doc, if the sum of another doc needs to be " "substracted ie. in a final invoice if there was a partial invoice before%1 " "is substited by the doc type, %2 by the id of the predecessor doc." msgid "Substract sum from %1 %2" msgstr "Subtrahiere Summe von %1 %2" #: katalog.cpp:137 #, kde-format msgid "not found" msgstr "nicht gefunden" #: addeditchapterdialog.cpp:35 #, kde-format msgid "Add/Edit Catalog Chapter" msgstr "Katalog-Kategorien hinzufügen/bearbeiten" #: addeditchapterdialog.cpp:41 #, kde-format msgid "Create a new Catalog Chapter" msgstr "Neues Katalogkapitel erstellen" #: addeditchapterdialog.cpp:45 #, kde-format msgid "Chapter Name:" msgstr "Kapitelname:" #: addeditchapterdialog.cpp:49 #, kde-format msgid "Chapter Description:" msgstr "Kapitelbeschreibung:" #: addeditchapterdialog.cpp:76 #, kde-format msgid "Create new Catalog Chapter below chapter %1" msgstr "Neues Katalogkapitel unter Kapitel %1 erstellen" #: addeditchapterdialog.cpp:83 #, kde-format msgid "Edit name and description of chapter %1" msgstr "Name und Beschreibung von Kapitel %1 bearbeiten" #: kraftdoc.cpp:160 #, kde-format msgctxt "First argument is the doctype, like Invoice, followed by the ID" msgid "%1 (Id %2)" msgstr "%1 (Id %2)" #: kraftdoc.cpp:308 #, kde-format msgctxt "Document part header" msgid "Header" msgstr "Kopfbereich" #: kraftdoc.cpp:310 #, kde-format msgctxt "Document part footer" msgid "Footer" msgstr "Fußbereich" #: kraftdoc.cpp:312 #, kde-format msgctxt "Document part containing the items" msgid "Items" msgstr "Posten" #: kraftdoc.cpp:314 #, kde-format msgid "Unknown document part" msgstr "Unbekannter Dokumententeil" #: defaultprovider.cpp:63 doctext.cpp:80 positionviewwidget.cpp:418 #, kde-format msgid "Unknown" msgstr "Unbekannt" #: docassistant.cpp:52 #, kde-format msgid "Show &Templates" msgstr "Vorlagen anzeigen" #: docassistant.cpp:57 #, kde-format msgid "Show mask to create or select templates to be used in the document" msgstr "" "Den Dialog zum Erstellen oder Auswählen von Dokumentvorlagen anzeigen." #: docassistant.cpp:121 #, kde-format msgid "Add a template to the document" msgstr "Vorlage zum Dokument hinzufügen" #: docassistant.cpp:128 #, kde-format msgid "Insert the template to the document" msgstr "Vorlage an Cursor-Position in das Dokument einfügen" #: docassistant.cpp:136 #, kde-format msgid "Create a new template" msgstr "Eine neue Vorlage erstellen" #: docassistant.cpp:143 #, kde-format msgid "Edit the current template" msgstr "Aktuelle Vorlage bearbeiten" #: docassistant.cpp:150 #, kde-format msgid "Delete the current template" msgstr "Aktuelle Vorlage löschen" #: docassistant.cpp:319 #, kde-format msgid "" "Do you really want to delete the template permanently?\n" "It can not be recovered." msgstr "" "Möchten Sie die ausgewählte Vorlage wirklich löschen? Dieser Vorgang kann " "nicht rückgängig gemacht werden." #: addressselectorwidget.cpp:219 #, kde-format msgid "Name" msgstr "Name" #: addressselectorwidget.cpp:221 #, kde-format msgid "Address" msgstr "Kundenadresse" #: addressselectorwidget.cpp:288 filterheader.cpp:40 #, kde-format msgid "&Search:" msgstr "&Suchen: " #: addressselectorwidget.cpp:325 #, kde-format msgid "Edit Contact..." msgstr "Kontakt bearbeiten ..." #: addressselectorwidget.cpp:326 #, kde-format msgid "Edit the currently selected contact" msgstr "Bearbeitet den aktuell ausgewählten Kontakt" #: addressselectorwidget.cpp:329 #, kde-format msgid "New Contact..." msgstr "Neuer Kontakt ..." #: addressselectorwidget.cpp:330 #, kde-format msgid "Create a new Contact" msgstr "Neuen Kontakt erstellen" #: docpostcard.cpp:33 #, kde-format msgid "Document Overview" msgstr "Dokumenten-Übersicht" #: docpostcard.cpp:125 #, kde-format msgid "Netto:" msgstr "Netto:" #: docpostcard.cpp:136 docpostcard.cpp:143 #, kde-format msgid "+ %1% Tax:" msgstr "+ %1 % Steuer:" #: docpostcard.cpp:149 #, kde-format msgid "Sum Tax:" msgstr "Steuersumme:" #: docpostcard.cpp:154 #, kde-format msgid "Total:" msgstr "Gesamt:" #: docpostcard.cpp:246 #, kde-format msgid "%1 Items" msgstr "%1 Posten" #: docpostcard.cpp:248 #, kde-format msgid "%1 Items, netto %2" msgstr "%1 Posten, Netto %2" #: archdoc.cpp:65 #, kde-format msgid "%1 for %2 (Id %3)" msgstr "%1 bis %2 (Nummer %3)" #: doctext.cpp:61 #, kde-format msgid "Standard" msgstr "Standard" #: doctext.cpp:76 #, kde-format msgid "Header Text" msgstr "Kopftext" #: doctext.cpp:77 #, kde-format msgid "Footer Text" msgstr "Fußtext" #: doctext.cpp:78 #, kde-format msgid "Items" msgstr "Posten" #: alldocsview.cpp:64 #, kde-format msgid "All documents" msgstr "Alle Dokumente" #: alldocsview.cpp:65 #, kde-format msgid "Documents of last week" msgstr "Dokumente der letzten Woche" #: alldocsview.cpp:66 #, kde-format msgid "Documents of last month" msgstr "Dokumente im letzten Monat" #: alldocsview.cpp:72 #, kde-format msgid "&Show: " msgstr "&Anzeigen" #: alldocsview.cpp:79 #, kde-format msgid "&Search: " msgstr "&Suchen: " #: alldocsview.cpp:134 portal.cpp:305 portal.cpp:306 rc.cpp:634 rc.cpp:1328 #: rc.cpp:2196 rc.cpp:3091 rc.cpp:4172 rc.cpp:5079 #, kde-format msgid "Document Actions" msgstr "Dokument-Aktionen" #: documenttemplate.cpp:113 #, kde-format msgctxt "Sequence number printed on the document" msgid "No." msgstr "Nr." #: documenttemplate.cpp:114 #, kde-format msgctxt "Document item printed on the document" msgid "Item" msgstr "Posten" #: documenttemplate.cpp:115 #, kde-format msgctxt "Abbrev. of Quantity printed on the document" msgid "Qty." msgstr "Menge" #: documenttemplate.cpp:116 #, kde-format msgctxt "Unit printed on the document" msgid "Unit" msgstr "Einh." #: documenttemplate.cpp:117 #, kde-format msgctxt "Price of an item printed on the document" msgid "Price" msgstr "Preis" #: documenttemplate.cpp:118 #, kde-format msgctxt "Printed on the document" msgid "Sum" msgstr "Summe" #: documenttemplate.cpp:119 #, kde-format msgctxt "printed on the document" msgid "Net" msgstr "Netto" #: documenttemplate.cpp:120 #, kde-format msgctxt "Printed on the document" msgid "VAT" msgstr "MwSt." #: documenttemplate.cpp:121 #, kde-format msgctxt "Document type, printed on the document" msgid "Type" msgstr "Typ" #: documenttemplate.cpp:123 #, kde-format msgctxt "Printed on the document" msgid "Phone" msgstr "Telefon" #: documenttemplate.cpp:124 #, kde-format msgctxt "Printed on the document" msgid "FAX" msgstr "Fax" #: documenttemplate.cpp:125 #, kde-format msgctxt "Printed on the document" msgid "Mobile" msgstr "Mobil" #: documenttemplate.cpp:126 #, kde-format msgctxt "Printed on the document" msgid "Email" msgstr "Email" #: documenttemplate.cpp:127 #, kde-format msgctxt "Printed on the document" msgid "Website" msgstr "Webseite" #: documenttemplate.cpp:129 #, kde-format msgctxt "Printed on the document" msgid "Page" msgstr "Seite" #: documenttemplate.cpp:130 #, kde-format msgctxt "Label of Predecessor document number" msgid "Predecessor-Doc" msgstr "Vorgänger-Dokument" #: documenttemplate.cpp:131 #, kde-format msgctxt "the 'of' in page X of Y" msgid "of" msgstr "von" #: documenttemplate.cpp:132 #, kde-format msgctxt "Document number on document" msgid "Document No." msgstr "Dokument Nr." #: documenttemplate.cpp:133 #, kde-format msgctxt "Date on document" msgid "Date" msgstr "Datum" #: documenttemplate.cpp:134 #, kde-format msgctxt "Project label" msgid "Project" msgstr "Projekt" #: documenttemplate.cpp:135 #, kde-format msgctxt "Customer ID on document" msgid "Customer Id" msgstr "Kundennr." #: documenttemplate.cpp:200 #, kde-format msgctxt "" "Credit Transfer reason string, 1=DocType, 2=DocIdent, 3=Date, ie. Invoice " "2022-183 dated 2022-03-22" msgid "%1 %2 dated %3" msgstr "%1 %2 datiert auf %3" #: documenttemplate.cpp:321 #, kde-format msgid "" "Please note: This offer contains %1 alternative or demand positions, printed" " in italic font. These do not add to the overall sum." msgstr "" "Bitte beachten: Dieses Angebot enthält %1 Alternativ- oder " "Bedarfspositionen, die kursiv gedruckt sind. Diese addieren sich nicht zur " "Endsumme." #: documenttemplate.cpp:332 #, kde-format msgid "tax free items (%1 pcs.)" msgstr "Steuerfreie Posten (%1 Stck.)" #: documenttemplate.cpp:338 #, kde-format msgid "items with reduced tax of %1% (%2 pcs.)" msgstr "Posten mit reduzierter Steuer %1% (%2 Stck.)" #: documenttemplate.cpp:347 #, kde-format msgid "No label: items with full tax of %1% (%2 pcs.)" msgstr "Nicht gekennzeichnet: Posten mit vollem Steuersatz von %1% (%2 Stck.)" #: documenttemplate.cpp:377 kraftview_ro.cpp:225 #, kde-format msgid "reduced VAT" msgstr "Reduzierte Umsatzsteuer" #: documenttemplate.cpp:385 kraftview_ro.cpp:197 kraftview_ro.cpp:234 #: rc.cpp:21 rc.cpp:931 rc.cpp:1769 rc.cpp:2652 rc.cpp:3703 rc.cpp:4607 #, kde-format msgid "VAT" msgstr "Umsatzsteuer" #: documenttemplate.cpp:439 #, kde-format msgid "Template to convert is not existing!" msgstr "Vorlage existiert nicht!" #: documenttemplate.cpp:442 #, kde-format msgid "Can not read template file!" msgstr "Vorlangendatei kann nicht gelesen werden!" #: flostempldialog.cpp:71 #, kde-format msgid "Create or Edit Template Items" msgstr "Posten der Vorlage erstellen oder bearbeiten" #: flostempldialog.cpp:213 flostempldialog.cpp:604 #, kde-format msgid "No" msgstr "Nein" #: flostempldialog.cpp:214 flostempldialog.cpp:604 #, kde-format msgid "Yes" msgstr "Ja" #: flostempldialog.cpp:251 #, kde-format msgid "Calculated Price: " msgstr "Kalkulierter Preis: " #: flostempldialog.cpp:255 #, kde-format msgid "Manual Price: " msgstr "Manueller Preis: " #: flostempldialog.cpp:260 #, kde-format msgid "(+%1%)" msgstr "(+ %1 %)" #: flostempldialog.cpp:264 #, kde-format msgid "%1%" msgstr "%1 %" #: flostempldialog.cpp:266 #, kde-format msgid ": " msgstr ": " #: flostempldialog.cpp:388 #, kde-format msgid "Template Error" msgstr "Vorlagenfehler" #: flostempldialog.cpp:388 #, kde-format msgid "Saving of this template failed, sorry" msgstr "Das Speichern der Vorlage ist fehlgeschlagen." #: flostempldialog.cpp:416 #, kde-format msgid "The template has been modified." msgstr "Vorlage geändert" #: flostempldialog.cpp:417 #, kde-format msgid "Do you want to discard your changes?" msgstr "" "Die Vorlage ist bearbeitet worden. Möchten Sie wirklich alle Änderungen " "verwerfen?" #: flostempldialog.cpp:446 #, kde-format msgid "" "The catalog chapter was changed for this template.\n" "Do you really want to move the template to the new chapter?" msgstr "" "Die Kategorie des Katalogs für diese Vorlage ist geändert worden.\n" "Möchten Sie diese Vorlage wirklich in die neue Kategorie verschieben?" #: flostempldialog.cpp:448 #, kde-format msgid "Chapter Change" msgstr "Kapitelveränderung" #: flostempldialog.h:104 #, kde-format msgid "Calculated material" msgstr "Kalkuliertes Material" #: calcpart.cpp:98 #, kde-format msgid "Base" msgstr "Basis" #: catalogselection.cpp:50 #, kde-format msgid "Selected &Catalog: " msgstr "&Katalogauswahl: " #: catalogselection.cpp:159 #, kde-format msgid "Append to Document" msgstr "An Dokument anfügen" #: fixcalcdialog.cpp:36 #, kde-format msgid "Calculation Fix Item" msgstr "Zeitkostenanteil" #: catalogtemplate.cpp:52 #, kde-format msgid "Manual Price" msgstr "Manueller Preis" #: catalogtemplate.cpp:54 #, kde-format msgid "Calculated" msgstr "Kalkuliert" #: catalogtemplate.cpp:56 #, kde-format msgid "AutoCalc" msgstr "Automatische Kalkulation" #: catalogtemplate.cpp:57 #, kde-format msgid "Err: Unknown type %d" msgstr "Fehler: Unbekannter Typ %d" #: main.cpp:58 #, kde-format msgid "Open document with arch doc number " msgstr "Dokument mit Archiv-Nummer %1 öffnen" #: main.cpp:59 #, kde-format msgid "Open Kraft in read only mode - document changes prohibited" msgstr "" "Kraft im Nur-Lesen Modus öffnen - Dokument Änderungen sind nicht möglich" #: templtopositiondialogbase.cpp:35 rc.cpp:460 rc.cpp:1331 rc.cpp:2220 #: rc.cpp:3115 rc.cpp:3989 rc.cpp:4893 #, kde-format msgid "Create Item from Template" msgstr "Posten aus Vorlage erstellen" #: templtopositiondialogbase.cpp:51 #, kde-format msgid "the Header of the Document as first item" msgstr "als ersten Posten" #: templtopositiondialogbase.cpp:58 importitemdialog.cpp:125 #, kde-format msgid "..." msgstr "..." #: portal.cpp:105 #, kde-format msgid "&Quit" msgstr "&Beenden" #: portal.cpp:110 #, kde-format msgid "&Cut" msgstr "&Ausschneiden" #: portal.cpp:115 #, kde-format msgid "C&opy" msgstr "K&opieren" #: portal.cpp:120 #, kde-format msgid "&Paste" msgstr "&Einfügen" #: portal.cpp:125 #, kde-format msgid "&Settings" msgstr "&Einstellungen" #: portal.cpp:130 #, kde-format msgid "&Create Document" msgstr "Dokument &anlegen" #: portal.cpp:135 #, kde-format msgid "&Copy Document" msgstr "Dokument &kopieren" #: portal.cpp:140 #, kde-format msgid "Create &Followup Document" msgstr "&Nachfolgedokument erzeugen" #: portal.cpp:145 #, kde-format msgid "Print Document" msgstr "Dokument drucken" #: portal.cpp:150 #, kde-format msgid "Show Document" msgstr "Dokument anzeigen" #: portal.cpp:155 #, kde-format msgid "Edit Document" msgstr "Dokument bearbeiten" #: portal.cpp:160 #, kde-format msgid "Open Archived Document" msgstr "Archiviertes Dokument öffnen" #: portal.cpp:165 #, kde-format msgid "Mail Document" msgstr "Dokument mailen" #: portal.cpp:170 #, kde-format msgid "Export XRechnung" msgstr "XRechnung Export" #: portal.cpp:175 tagtemplatesdialog.cpp:135 tagtemplatesdialog.cpp:140 #, kde-format msgid "Edit Tag Templates" msgstr "Stichwort-Vorlagen bearbeiten" #: portal.cpp:180 #, kde-format msgid "Redo Initial Setup..." msgstr "Wiederhole initiales Setup..." #: portal.cpp:185 #, kde-format msgid "Kraft Handbook..." msgstr "Kraft Handbuch..." #: portal.cpp:190 #, kde-format msgid "About Qt..." msgstr "Über Qt..." #: portal.cpp:195 #, kde-format msgid "About Kraft..." msgstr "Über Kraft...." #: portal.cpp:199 #, kde-format msgid "Quits the application" msgstr "Anwendung beenden" #: portal.cpp:201 #, kde-format msgid "Cuts the selected section and puts it to the clipboard" msgstr "" "Schneidet den ausgewählten Abschnitt aus und kopiert ihn in die " "Zwischenablage." #: portal.cpp:202 #, kde-format msgid "Copies the selected section to the clipboard" msgstr "Kopiert den ausgewählten Abschnitt in die Zwischenablage." #: portal.cpp:203 #, kde-format msgid "Pastes the clipboard contents to current position" msgstr "Fügt den Inhalt der Zwischenablage an der aktuellen Position ein." #: portal.cpp:205 #, kde-format msgid "Creates a new Document" msgstr "Erstellt ein neues Dokument." #: portal.cpp:206 #, kde-format msgid "Print and archive this Document" msgstr "Das Dokument drucken und archivieren" #: portal.cpp:207 #, kde-format msgid "Creates a new document which is a copy of the selected document" msgstr "Erstellt ein neues Dokument, das eine Kopie des ausgewählten ist." #: portal.cpp:208 #, kde-format msgid "Create a followup document for the current document" msgstr "Ein Folgedokument für das aktuell ausgewählte erstellen" #: portal.cpp:209 #, kde-format msgid "Opens the document for editing" msgstr "Öffnet das Dokument zum Bearbeiten." #: portal.cpp:210 #, kde-format msgid "Opens a read only view on the document." msgstr "Öffnet das Dokument schreibgeschützt." #: portal.cpp:211 #, kde-format msgid "Send document per mail" msgstr "Das Dokument per E-Mail versenden" #: portal.cpp:212 #, kde-format msgid "Export invoice in XRechnung XML format." msgstr "Exportiere Rechnung in XRechnung XML Format." #: portal.cpp:213 #, kde-format msgid "" "Edit the available tag templates which can be assigned to document items." msgstr "" "Markierungs-Vorlagen hinzufügen, ändern oder entfernen, die den Posten der " "Dokumente zugeordnet werden können." #: portal.cpp:214 #, kde-format msgid "Configure the Database Kraft is working on." msgstr "Die Datenbank einrichten, mit der Kraft arbeitet." #: portal.cpp:215 #, kde-format msgid "Open a viewer on an archived document" msgstr "Das archivierte Dokument zur Ansicht öffnen" #: portal.cpp:229 rc.cpp:484 rc.cpp:1355 rc.cpp:2244 rc.cpp:3139 rc.cpp:4013 #: rc.cpp:4917 #, kde-format msgid "&File" msgstr "&Datei" #: portal.cpp:233 #, kde-format msgid "&Edit" msgstr "&Bearbeiten" #: portal.cpp:238 rc.cpp:628 rc.cpp:1322 rc.cpp:2190 rc.cpp:3085 rc.cpp:4166 #: rc.cpp:5073 #, kde-format msgid "&Document" msgstr "&Dokument" #: portal.cpp:253 #, kde-format msgid "Kraft" msgstr "Kraft" #: portal.cpp:256 #, kde-format msgid "&Preferences" msgstr "&Einstellungen" #: portal.cpp:260 #, kde-format msgid "Toolbars" msgstr "Werkzeugleisten" #: portal.cpp:266 #, kde-format msgid "&Help" msgstr "&Hilfe" #: portal.cpp:354 #, kde-format msgid "Database not running" msgstr "Datenbank nicht erreichbar" #: portal.cpp:355 #, kde-format msgid "" "Kraft was started in readonly mode, but the configured database can not be connected.\n" "\n" "Kraft will abort." msgstr "" "Kraft wurde im Nur-Lesen Modus gestartet, aber die konfigurierte Datenbank kann nicht erreicht werden.\n" "\n" "Kraft wird beendet." #: portal.cpp:371 #, kde-format msgid "" "Kraft can not connect to the specified MySQL server. Please check the Kraft " "database settings, check if the server is running and verify if a database " "with the name %1 exits!" msgstr "" "Kraft kann keine Verbindung zum angegebenen MySQL-Server herstellen. Bitte " "überprüfen Sie die Datenbank-Einstellungen von Kraft, ob der Datenbank-" "Server läuft und ob eine Datenbank namens %1 vorhanden ist." #: portal.cpp:375 #, kde-format msgid "" "The database with the name %1 does not exist on the database server. Please " "make sure the database exists and is accessible by the user running Kraft." msgstr "" "Die Datenbank namens %1 ist auf dem Datenbank-Server nicht verfügbar. Bitte " "stellen Sie sicher, dass die Datenbank vorhanden ist und vom Benutzer, unter" " welchem Kraft läuft, darauf zugegriffen werden kann." #: portal.cpp:379 #, kde-format msgid "" "The Qt database driver could not be loaded. That probably means, that they " "are not installed. Please make sure the Qt database packages are installed " "and try again." msgstr "" "Der Qt-Datenbank-Treiber lässt sich nicht laden. Das bedeutet eventuell, " "dass er nicht installiert ist. Bitte stellen Sie sicher, dass die Qt-" "Datenbank-Pakete installiert sind und versuchen es dann erneut." #: portal.cpp:383 #, kde-format msgid "There is a database problem: %1" msgstr "Es ist ein Problem mit der Datenbank aufgetreten: %1" #: portal.cpp:401 #, kde-format msgid "Database Problem." msgstr "Datenbank-Problem" #: portal.cpp:413 #, kde-format msgid "Check commandline actions" msgstr "Befehlszeilenaktionen prüfen" #: portal.cpp:503 #, kde-format msgid "Welcome to Kraft, %1" msgstr "Willkommen zu Kraft, %1" #: portal.cpp:532 #, kde-format msgid "Creating new document..." msgstr "Neues Dokument erstellen ..." #: portal.cpp:558 #, kde-format msgctxt "" "Dialog title of the followup doc dialog, followed by the id of the source " "doc" msgid "Create follow up document for %1" msgstr "Folgedokument für %1 anlegen" #: portal.cpp:603 #, kde-format msgctxt "Title of the new doc dialog, %1 is the source doc id" msgid "Create new Document as Copy of %1" msgstr "Neues Dokument als Kopie von %1 erzeugen" #: portal.cpp:638 #, kde-format msgid "Opening document to view..." msgstr "Dokument zur Ansicht öffnen ..." #: portal.cpp:665 #, kde-format msgid "" "XRechnung Template file not set. Please check the application settings!" msgstr "" "Das XRechnung Template ist nicht gesetzt. Bitte die Einstellungen " "überprüfen!" #: portal.cpp:669 #, kde-format msgid "The XRechnung template file can not be read!" msgstr "Das XRechnung Template kann nicht gelesen werden." #: portal.cpp:674 #, kde-format msgid "XRechnung Export" msgstr "XRechnung Export" #: portal.cpp:694 #, kde-format msgid "Save XRechnung" msgstr "Speichere XRechnung" #: portal.cpp:696 #, kde-format msgid "Saved XRechnung to %1" msgstr "XRechnung Datei in %1 gespeichert" #: portal.cpp:730 #, kde-format msgid "Generating PDF..." msgstr "PDF wird erstellt ..." #: portal.cpp:744 portal.cpp:767 portal.cpp:1093 katalogview.cpp:236 #: katalogview.cpp:302 katalogview.cpp:316 katalogview.cpp:325 #: katalogview.cpp:334 #, kde-format msgid "Ready." msgstr "Fertig." #: portal.cpp:753 #, kde-format msgid "Generating PDF for EMail" msgstr "Generiere PDF für EMail" #: portal.cpp:772 #, kde-format msgid "Doc Generation Error" msgstr "Dokument Generierungs-Fehler" #: portal.cpp:828 #, kde-format msgid "Printing archived document..." msgstr "Archiviertes Dokument drucken ..." #: portal.cpp:880 #, kde-format msgid "Opening document %1" msgstr "Dokument %1 öffnen" #: portal.cpp:1037 katalogview.cpp:241 #, kde-format msgid "Exiting..." msgstr "Beenden ..." #: portal.cpp:1064 #, kde-format msgid "Cutting selection..." msgstr "Auswahl ausschneiden ..." #: portal.cpp:1071 #, kde-format msgid "Copying selection to clipboard..." msgstr "Auswahl in die Zwischenablage kopieren ..." #: portal.cpp:1078 #, kde-format msgid "Inserting clipboard contents..." msgstr "Inhalt der Zwischenablage einfügen ..." #: portal.cpp:1091 #, kde-format msgid "" "Ready. Kraft is running in read only mode. Document editing is prohibited." msgstr "" "Bereit. Kraft läuft im Nur-Lesen Modus. Dokumente können nicht editiert " "werden." #: doctypeedit.cpp:49 #, kde-format msgid "" msgstr "" #: doctypeedit.cpp:50 #, kde-format msgid "
" msgstr "" #: doctypeedit.cpp:85 #, kde-format msgid "Select template file from harddisk" msgstr "Dokument-Template auf der Festplatte auswählen" #: doctypeedit.cpp:86 #, kde-format msgid "Select watermark file from harddisk" msgstr "Wasserzeichen-Datei auf der Festplatte auswählen" #: doctypeedit.cpp:87 #, kde-format msgid "Select PDF file to append to documents from harddisk" msgstr "PDF Datei von der Festplatte zum Anhängen an das Dokument auswählen" #: doctypeedit.cpp:91 prefsdialog.cpp:409 #, kde-format msgid "Find Template File" msgstr "Dokument Vorlage finden" #: doctypeedit.cpp:92 #, kde-format msgid "Kraft Templates (*.trml *.gtmpl)" msgstr "Kraft Dokument Vorlagen (*.trml *.gtmpl)" #: doctypeedit.cpp:100 #, kde-format msgid "Find Watermark File" msgstr "Wasserzeichen Datei finden" #: doctypeedit.cpp:101 doctypeedit.cpp:111 #, kde-format msgid "PDF file (*.pdf)" msgstr "PDF Datei (*.pdf)" #: doctypeedit.cpp:110 #, kde-format msgid "Find Append PDF File" msgstr "PDF Anhang auswählen" #: doctypeedit.cpp:171 doctypeedit.cpp:197 #, kde-format msgid "Add Document Type" msgstr "Dokumentenart hinzufügen" #: doctypeedit.cpp:172 #, kde-format msgid "Enter the name of a new document type" msgstr "Bitte geben Sie den Namen der neuen Dokumentenart ein." #: doctypeedit.cpp:198 #, kde-format msgid "Edit the name of a document type" msgstr "Den Namen einer Dokumentenart ändern." #: docdigestdetailview.cpp:230 rc.cpp:78 rc.cpp:120 rc.cpp:988 rc.cpp:1030 #: rc.cpp:1826 rc.cpp:1868 rc.cpp:2709 rc.cpp:2751 rc.cpp:3760 rc.cpp:3802 #: rc.cpp:4664 rc.cpp:4706 #, kde-format msgid "Amount" msgstr "Menge" #: docdigestdetailview.cpp:231 #, kde-format msgid "Type" msgstr "Art" #: docdigestdetailview.cpp:232 #, kde-format msgid "Sum" msgstr "Summe" #: docdigestdetailview.cpp:261 #, kde-format msgid "Results in %1 %2" msgstr "Resultate in %1 %2" #: docdigestdetailview.cpp:262 docdigestdetailview.cpp:295 #, kde-format msgid "Year" msgstr "Jahr" #: docdigestdetailview.cpp:264 #, kde-format msgid "Month" msgstr "Monat" #: docdigestdetailview.cpp:297 #, kde-format msgid "Results in Year %1" msgstr "Resultate im Jahr %1" #: docdigestdetailview.cpp:316 docdigestdetailview.cpp:325 #, kde-format msgid "Customer" msgstr "Kunde:" #: docdigestdetailview.cpp:320 #, kde-format msgid "not set" msgstr "nicht ausgewählt" #: docdigestdetailview.cpp:336 #, kde-format msgid "The address is not listed in an address book." msgstr "Die Adresse ist in keinem Adressbuch enthalten." #: docdigestdetailview.cpp:338 #, kde-format msgid "" "The client has the address book id %1 but can not found in our address " "books." msgstr "" "Der Kunde hat die Adressbuch-Kennung %1, wurde aber nicht in unseren " "Adressbüchern gefunden." #: docdigestdetailview.cpp:341 #, kde-format msgid "The client can be found in our address books." msgstr "Der Kunde wurde in unseren Adressbüchern gefunden." #: docdigestdetailview.cpp:352 prefsdialog.cpp:744 #, kde-format msgid "preferred address" msgstr "Bevorzugte Adresse" #: docdigestdetailview.cpp:356 prefsdialog.cpp:748 #, kde-format msgid "home address" msgstr "Privatanschrift" #: docdigestdetailview.cpp:360 prefsdialog.cpp:752 #, kde-format msgid "work address" msgstr "Arbeitsplatzadresse" #: docdigestdetailview.cpp:364 prefsdialog.cpp:756 #, kde-format msgid "postal address" msgstr "Postanschrift" #: docdigestdetailview.cpp:368 prefsdialog.cpp:760 #, kde-format msgid "international address" msgstr "Internationale Adresse" #: docdigestdetailview.cpp:372 prefsdialog.cpp:764 #, kde-format msgid "domestic address" msgstr "Privatanschrift" #: docdigestdetailview.cpp:376 prefsdialog.cpp:768 #, kde-format msgid "unknown" msgstr "Unbekannt" #: docdigestdetailview.cpp:433 #, kde-format msgid "This document was never printed." msgstr "Das Dokuments wurde nie gedruckt." #: docdigestdetailview.cpp:440 #, kde-format msgid "Last printed" msgstr "Zuletzt gedruckt" #: docdigestdetailview.cpp:441 #, kde-format msgid "Opens last created PDF document" msgstr "Öffnet das letzte erstellte PDF Dokument" #: docdigestdetailview.cpp:442 #, kde-format msgid "open" msgstr "offen" #: docdigestdetailview.cpp:447 #, kde-format msgid "One older print" msgstr "Ein älterer Ausdruck" #: docdigestdetailview.cpp:449 #, kde-format msgid "%1 older prints" msgstr "%1 alte Ausdrucke" #: docdigestdetailview.cpp:453 #, kde-format msgid "Archived documents can not be found. Check PDF Output dir." msgstr "" "Archivierte Dokumente können nicht gefunden werden. Überprüfen Sie das PDF " "Ausgabe Verzeichnis." #: docdigestdetailview.cpp:457 #, kde-format msgid "Export the invoice in XRechnung file format" msgstr "Rechnung in XRechnung Format exportieren" #: docdigestdetailview.cpp:458 #, kde-format msgid "XRechnung" msgstr "XRechnung" #: importfilter.cpp:50 #, kde-format msgid "Unable to find filter called %1" msgstr "Der Filter mit dem Namen „%1“ kann nicht gefunden werden." #: importfilter.cpp:58 #, kde-format msgid "Could not open the definition file!" msgstr "Definitionsdatei kann nicht geöffnet werden!" #: importfilter.cpp:143 #, kde-format msgid "Unknown tags: " msgstr "Unbekannte Markierungen:" #: importfilter.cpp:184 #, kde-format msgid "Could not recode input file!" msgstr "Umcodieren der Eingabedatei fehlgeschlagen!" #: importfilter.cpp:192 #, kde-format msgid "Unable to open temp file " msgstr "Die temporäre Datei kann nicht geöffnet werden " #: importfilter.cpp:198 #, kde-format msgid "Could not open the import source file!" msgstr "Die zu importierende Datei kann nicht geöffnet werden." #: importitemdialog.cpp:47 #, kde-format msgid "Import Items From File" msgstr "Posten aus Datei importieren" #: importitemdialog.cpp:116 #, kde-format msgid "the Header of the Document" msgstr "Der Kopfbereich des Dokuments." #: inserttempldialog.cpp:105 #, kde-format msgid "Create a new Item" msgstr "Neuen Posten anlegen" #: inserttempldialog.cpp:107 #, kde-format msgid "Create a new Item from Template" msgstr "Posten aus Vorlage erstellen" #: itemtagdialog.cpp:82 #, kde-format msgid "Edit Item Tags" msgstr "Posten-Markierungen bearbeiten" #: itemtagdialog.cpp:89 #, kde-format msgid "Item Tags" msgstr "Posten-Markierungen" #: itemtagdialog.cpp:90 #, kde-format msgid "Select all tags for the item should be tagged with." msgstr "Wählen Sie alle Markierungen für den Posten aus." #: itemtagdialog.cpp:105 tagtemplatesdialog.cpp:150 #, kde-format msgid "Tag" msgstr "Markierung" #: itemtagdialog.cpp:106 tagtemplatesdialog.cpp:151 #, kde-format msgid "Color" msgstr "Farbe" #: itemtagdialog.cpp:107 tagtemplatesdialog.cpp:152 #, kde-format msgid "Description" msgstr "Beschreibung" #: kataloglistview.cpp:355 #, kde-format msgid "A catalog chapter can not be deleted as long it has children." msgstr "" "Ein Kapitel im Katalog kann nicht gelöscht werden, wenn es noch Unterkapitel" " gibt." #: kataloglistview.cpp:356 #, kde-format msgid "Chapter can not be deleted" msgstr "Das Kapitel kann nicht gelöscht werden" #: katalogview.cpp:164 #, kde-format msgid "Edit Sub chapter" msgstr "Unterkapitel bearbeiten" #: katalogview.cpp:166 #, kde-format msgid "Edit a catalog sub chapter" msgstr "Katalog-Unterkapitel bearbeiten" #: katalogview.cpp:170 #, kde-format msgid "Add a sub chapter" msgstr "Unterkapitel hinzufügen" #: katalogview.cpp:172 #, kde-format msgid "Add a sub chapter below the selected one" msgstr "Ein Unterkapitel unter dem ausgewählten hinzufügen" #: katalogview.cpp:176 katalogview.cpp:178 #, kde-format msgid "Remove a sub chapter" msgstr "Unterkapitel entfernen" #: katalogview.cpp:182 rc.cpp:3 rc.cpp:913 rc.cpp:1751 rc.cpp:2634 rc.cpp:3685 #: rc.cpp:4589 #, kde-format msgid "Edit Template" msgstr "Vorlage bearbeiten" #: katalogview.cpp:184 #, kde-format msgid "Opens the editor window for templates to edit the selected one" msgstr "Öffnet das Fenster zum Ändern der ausgewählten Vorlage." #: katalogview.cpp:189 #, kde-format msgid "New template" msgstr "Neue Vorlage" #: katalogview.cpp:191 #, kde-format msgid "Opens the editor window for templates to enter a new template" msgstr "Öffnet das Fenster zum Anlegen einer neuen Vorlage." #: katalogview.cpp:196 #, kde-format msgid "Delete template" msgstr "Vorlage löschen" #: katalogview.cpp:198 #, kde-format msgid "Deletes the template" msgstr "Löscht die Vorlage" #: katalogview.cpp:203 #, kde-format msgid "Export catalog" msgstr "Katalog exportieren" #: katalogview.cpp:205 #, kde-format msgid "Export the whole catalog as XML encoded file" msgstr "Den gesamten Katalog als XML-Datei exportieren." #: katalogview.cpp:210 #, kde-format msgid "Import catalog" msgstr "Katalog importieren" #: katalogview.cpp:212 #, kde-format msgid "Import a catalog from a XML file" msgstr "Katalog aus einer XML Datei einlesen " #: katalogview.cpp:216 rc.cpp:487 rc.cpp:1358 rc.cpp:2247 rc.cpp:3142 #: rc.cpp:4016 rc.cpp:4920 #, kde-format msgid "&Catalog" msgstr "&Katalog" #: katalogview.cpp:234 #, kde-format msgid "Opening file..." msgstr "Datei wird geöffnet ..." #: katalogview.cpp:298 #, kde-format msgid "Exporting file..." msgstr "Datei wird exportiert ..." #: katalogview.cpp:307 #, kde-format msgid "Importfile... (not yet implemented)" msgstr "Datei importieren (noch nicht implementiert)" #: katalogview.cpp:312 #, kde-format msgid "Creating a new sub chapter..." msgstr "Neues Unterkapitel wird erstellt ..." #: katalogview.cpp:321 #, kde-format msgid "Editing a sub chapter..." msgstr "Unterkapitel wird bearbeitet ..." #: katalogview.cpp:330 #, kde-format msgid "Removing a sub chapter..." msgstr "Unterkapitel wird entfernt ..." #: katalogview.cpp:363 #, kde-format msgid "Created at %1 " msgstr "Angelegt am %1" #: katalogview.cpp:367 #, kde-format msgid ", last modified at %1" msgstr ", zuletzt angepasst am %1" #: katalogview.cpp:373 #, kde-format msgid "%1 times used, last at %2" msgstr "%1 mal verwendet, zuletzt am %2" #: kraftdocheaderedit.cpp:57 #, kde-format msgid "Document Header" msgstr "Dokumentkopf" #: kraftdocheaderedit.cpp:65 #, kde-format msgid "Manually set in address field." msgstr "Manuell im Adressfeld gesetzt." #: kraftview.cpp:89 kraftview_ro.cpp:60 #, kde-format msgid "Document" msgstr "Dokument" #: kraftview.cpp:257 #, kde-format msgid "Successor of %1" msgstr "Nachfolger von %1" #: kraftview.cpp:395 kraftview.cpp:847 #, kde-format msgid "" "The address label is not empty and different from the selected one.
Do " "you really want to replace it with the text shown below?
%1
" msgstr "" "Die Adress-Beschriftung ist nicht leer und unterscheidet sich von der " "ausgewählten Adresse
Möchten Sie sie wirklich mit diesem angezeigten " "Text ersetzen?
%1
" #: kraftview.cpp:442 #, kde-format msgid "" "

The Document Items List is still empty, but Items can be added " "now.

To add items to the document either
  • Press the 'Add item' " "button above.
  • Open the template catalog by clicking on the 'show " "Template' button on the right and pick one of the available " "templates.
" msgstr "" "

Die Postenliste ist noch leer, aber jetzt können Posten hinzugefügt werden.

\n" "Um Posten hinzuzufügen\n" "
    \n" "
  • Drücken Sie den 'Posten hinzufügen' Knopf
  • Öffnen Sie den Vorlagenkatalog durch einen Klick auf den 'Vorlagen anzeigen' Knopf rechts und übertragen Sie eine der vorhandenen Vorlagen.
  • \n" "
\n" " " #: kraftview.cpp:634 prefsdialog.cpp:329 #, kde-format msgid "Display no tax at all" msgstr "Keine Steuer auswerfen" #: kraftview.cpp:635 prefsdialog.cpp:330 #, kde-format msgid "Calculate reduced tax for all items" msgstr "Reduzierte Steuer für alle Posten" #: kraftview.cpp:636 prefsdialog.cpp:331 #, kde-format msgid "Calculate full tax for all items" msgstr "Allgemeine Steuer für alle Posten" #: kraftview.cpp:637 #, kde-format msgid "Calculate individual tax for each item" msgstr "Einzelne Steuern für jeden Posten berechnen" #: kraftview.cpp:694 #, kde-format msgid "Tax Settings Overwrite" msgstr "Steuer-Einstellungen überschreiben" #: kraftview.cpp:695 #, kde-format msgid "Really overwrite all individual tax settings of the items?" msgstr "" "Möchten Sie wirklich alle individuellen Steuer-Einstellungen für diesen " "Eintrag überschreiben?" #: kraftview.cpp:846 #, kde-format msgid "Address Overwrite" msgstr "Adresse überschreiben" #: kraftview.cpp:1111 #, kde-format msgid "Discount" msgstr "Rabatt" #: kraftview.cpp:1351 #, kde-format msgid "The document has been modified." msgstr "Das Dokuments wurde verändert." #: kraftview.cpp:1352 #, kde-format msgid "Do you want to save your changes?" msgstr "Sollen die Änderungen gesichert werden?" #: kraftdocfooteredit.cpp:52 #, kde-format msgid "Document Footer" msgstr "Dokumentfuß" #: kraftdocpositionsedit.cpp:94 #, kde-format msgid "Add Item..." msgstr "Posten hinzufügen ..." #: kraftdocpositionsedit.cpp:96 #, kde-format msgid "Add a normal item to the document manually." msgstr "Zum manuellen Hinzufügen eines Postens." #: kraftdocpositionsedit.cpp:100 #, kde-format msgid "Add Discount Item" msgstr "Rabattposten hinzufügen" #: kraftdocpositionsedit.cpp:103 #, kde-format msgid "" "Adds an item to the document that allows discounts on other items in the " "document" msgstr "" "Fügt einen Posten zum Dokument hinzu, mit dem Rabatte für andere Posten " "innerhalb des Dokuments gewährt werden können." #: kraftdocpositionsedit.cpp:106 #, kde-format msgid "Import Items..." msgstr "Posten importieren ..." #: kraftdocpositionsedit.cpp:109 #, kde-format msgid "Opens a dialog where multiple items can be imported from a text file." msgstr "" "Öffnet einen Dialog zum Importieren mehrerer Posten aus einer Textdatei." #: kraftdocpositionsedit.cpp:118 #, kde-format msgid "Document Items" msgstr "Dokumentposten" #: kraftview_ro.cpp:198 #, kde-format msgid "Reduced TAX" msgstr "Reduzierte Steuer" #: materialkataloglistview.cpp:40 rc.cpp:108 rc.cpp:643 rc.cpp:1018 #: rc.cpp:1675 rc.cpp:1856 rc.cpp:2567 rc.cpp:2739 rc.cpp:3471 rc.cpp:3790 #: rc.cpp:4181 rc.cpp:4694 rc.cpp:5088 #, kde-format msgid "Material" msgstr "Material" #: materialkataloglistview.cpp:41 #, kde-format msgid "Pack" msgstr "Gebinde" #: materialkataloglistview.cpp:42 rc.cpp:123 rc.cpp:1033 rc.cpp:1871 #: rc.cpp:2754 rc.cpp:3805 rc.cpp:4709 #, kde-format msgid "Unit" msgstr "Einheit" #: materialkataloglistview.cpp:43 #, kde-format msgid "Purchase" msgstr "Einkauf" #: materialkataloglistview.cpp:44 #, kde-format msgid "Sale" msgstr "Verkauf" #: materialkataloglistview.cpp:45 #, kde-format msgid "Last Modified" msgstr "Zuletzt geändert" #: materialkataloglistview.cpp:51 #, kde-format msgid "Material Catalog" msgstr "Material-Katalog" #: materialkatalogview.cpp:106 #, kde-format msgid "" msgstr "" #: materialkatalogview.cpp:136 templkatalogview.cpp:139 #, kde-format msgid "Do you really want to delete the template from the catalog?" msgstr "Möchten Sie die ausgewählte Vorlage wirklich aus dem Katalog löschen?" #: prefsdialog.cpp:64 #, kde-format msgid "Configure Kraft" msgstr "Kraft einrichten" #: prefsdialog.cpp:98 #, kde-format msgid "Document Defaults" msgstr "Dokumentenstandards" #: prefsdialog.cpp:99 #, kde-format msgid "Taxes" msgstr "Steuersätze" #: prefsdialog.cpp:100 #, kde-format msgid "Document Types" msgstr "Dokumentenart" #: prefsdialog.cpp:102 #, kde-format msgid "Wages" msgstr "Löhne" #: prefsdialog.cpp:104 #, kde-format msgid "Units" msgstr "Maßeinheiten" #: prefsdialog.cpp:105 #, kde-format msgid "Own Identity" msgstr "Eigene Identität" #: prefsdialog.cpp:152 #, kde-format msgid "Tax rates beginning at date:" msgstr "Steuersätze nach Datum:" #: prefsdialog.cpp:160 prefswages.cpp:51 prefsunits.cpp:53 #, kde-format msgid "ID" msgstr "ID" #: prefsdialog.cpp:161 #, kde-format msgid "Full Tax [%]" msgstr "Allgemeiner Steuersatz" #: prefsdialog.cpp:162 #, kde-format msgid "Reduced Tax [%]" msgstr "Reduzierter Steuersatz" #: prefsdialog.cpp:163 #, kde-format msgid "Start Date" msgstr "Anfangsdatum:" #: prefsdialog.cpp:182 prefswages.cpp:90 prefsunits.cpp:80 rc.cpp:307 #: rc.cpp:1160 rc.cpp:2064 rc.cpp:2947 rc.cpp:3517 rc.cpp:4421 #, kde-format msgid "Add" msgstr "Hinzufügen" #: prefsdialog.cpp:186 prefswages.cpp:99 prefsunits.cpp:89 rc.cpp:319 #: rc.cpp:1172 rc.cpp:2076 rc.cpp:2959 rc.cpp:3529 rc.cpp:4433 #, kde-format msgid "Remove" msgstr "Entfernen" #: prefsdialog.cpp:203 #, kde-format msgid "" "Select the identity of the sending entity of documents. That's your " "companies address." msgstr "" "Wählen Sie die Identität für den Versand von Dokumenten. Das ist Ihre " "Firmenadresse." #: prefsdialog.cpp:219 #, kde-format msgid "Select Identity..." msgstr "Identität auswählen ..." #: prefsdialog.cpp:225 #, kde-format msgid "From AddressBook" msgstr "aus dem Adressbuch" #: prefsdialog.cpp:230 setupassistant.cpp:342 #, kde-format msgid "Manual Entry" msgstr "Manueller Eintrag" #: prefsdialog.cpp:242 #, kde-format msgid "Manual Address" msgstr "Manuelle Adresse" #: prefsdialog.cpp:245 #, kde-format msgid "Bank Account Information" msgstr "Bankverbindung" #: prefsdialog.cpp:309 #, kde-format msgid "&Default document type on creation:" msgstr "&Standard-Dokumenttyp bei Erstellung:" #: prefsdialog.cpp:314 #, kde-format msgid "New documents default to the selected type." msgstr "Neue Dokumente sind standardmäßig von diesem Typ." #: prefsdialog.cpp:323 #, kde-format msgid "Default &Tax for Documents:" msgstr "Standardmäßiger &Steuersatz:" #: prefsdialog.cpp:328 #, kde-format msgid "The default tax setting for all documents." msgstr "" "Die standardmäßigen Einstellungen des Steuersatzes für alle Dokumente." #: prefsdialog.cpp:340 #, kde-format msgid "Document Date Format:" msgstr "Datumsformat im Dokument:" #: prefsdialog.cpp:346 #, kde-format msgid "The default date format for documents." msgstr "Das voreingestellte Datumsformat für Dokumente." #: prefsdialog.cpp:348 #, kde-format msgid "ISO-Format: %1" msgstr "ISO-Format: %1" #: prefsdialog.cpp:350 #, kde-format msgid "Short-Date: %1" msgstr "Datum in Kurzform: %1" #: prefsdialog.cpp:352 #, kde-format msgid "Long-Date: %1" msgstr "Datum in Langform: %1" #: prefsdialog.cpp:354 #, kde-format msgid "RFC 2822-Format: %1" msgstr "RFC 2822-Format: %1" #: prefsdialog.cpp:356 #, kde-format msgid "\"German Format\": %1" msgstr "\"Deutsches Format\": %1" #: prefsdialog.cpp:357 #, kde-format msgid "Custom Setting in Settingsfile" msgstr "Benutzerdefiniert aus dem Settingsfile" #: prefsdialog.cpp:366 #, kde-format msgid "Prefix text for Demand items:" msgstr "Vorangestellter Text für Bedarfspositionen:" #: prefsdialog.cpp:371 #, kde-format msgid "This text is automatically prepended to new 'on demand' items." msgstr "Dieser Text wird automatisch neuen Bedarfspositionen vorangestellt." #: prefsdialog.cpp:375 #, kde-format msgid "Prefix text for Alternative items:" msgstr "Vorangestellter Text für Alternativpositionen:" #: prefsdialog.cpp:380 #, kde-format msgid "This text is automatically prepended to new 'alternative' items." msgstr "" "Dieser Text wird automatisch neuen Alternativpositionen vorangestellt." #: prefsdialog.cpp:391 #, kde-format msgid "XRechnung Template File:" msgstr "XRechnung Template Datei:" #: prefsdialog.cpp:397 #, kde-format msgid "Select..." msgstr "Auswählen..." #: prefsdialog.cpp:405 #, kde-format msgid "Select template file for XRechnung" msgstr "Template Datei für XRechnung auswählen" #: prefsdialog.cpp:410 #, kde-format msgid "XRechnung Templates (*.xrtmpl)" msgstr "XRechnung Templates (*.xrtmpl)" #: prefsdialog.cpp:450 #, kde-format msgid "" "The old default doc type for new documents was just deleted.Please check the" " setting in the Document Defaults in the Kraft preferences Dialog." msgstr "" "Der alte Standard-Dokumenttyp für neue Dokumente wurde gelöscht. Bitte " "überprüfen Sie die Einstellung der Dokumentenstandards im Dialog " "Einstellungen von Kraft." #: prefsdialog.cpp:453 #, kde-format msgid "Document Default Change" msgstr "Änderung des Standard-Dokumenttyps" #: prefsdialog.cpp:701 #, kde-format msgid "The identity can not be found." msgstr "Die Identität ist in keinem Adressbuch enthalten." #: prefsdialog.cpp:703 #, kde-format msgid "" "

Kraft Addressbook Integration down.

The address book backend" " is not up and running.

Please check your addressbook integration " "setup.

" msgstr "" "

Die Kraft Adressbuch-Integration funktioniert nicht

Das " "Adressbuch-Backend läuft nicht.

Bitte Adressbuch-Setup überprüfen

" #: prefsdialog.cpp:709 #, kde-format msgid "The identity is not listed in an address book." msgstr "Die Identität ist in keinem Adressbuch enthalten." #: prefsdialog.cpp:711 #, kde-format msgid "" "

Kraft does not know your identity.

Please pick one from the " "address books by clicking on the Button below.

Not having an identity " "selected can make your documents look incomplete.

" msgstr "" "

Ihre Identität ist nicht eingestellt.

Bitte wählen Sie eine " "Identität aus dem Adressbuch, indem Sie auf den Knopf unten " "klicken..

Haben Sie keine Identität ausgewählt, dann werden Ihre " "Dokumente unvollständig aussehen.

" #: prefsdialog.cpp:728 #, kde-format msgid "Your identity can be found in the address books." msgstr "Ihre Identität wurde in den Adressbüchern gefunden." #: prefsdialog.cpp:739 #, kde-format msgid "Work Phone" msgstr "Telefon (Arbeit)" #: prefsdialog.cpp:740 #, kde-format msgid "Fax" msgstr "Fax" #: prefsdialog.cpp:741 #, kde-format msgid "Cell Phone" msgstr "Mobiltelefon" #: materialselectdialog.cpp:39 #, kde-format msgid "Add Material to Calculation" msgstr "Material zur Kalkulation hinzufügen" #: materialselectdialog.cpp:44 #, kde-format msgid "

Add Material to Calculation

" msgstr "

Material zur Kalkulation hinzufügen

" #: newdocassistant.cpp:52 newdocassistant.cpp:96 #, kde-format msgid "New Document Settings" msgstr "Einstellungen für neues Dokument" #: newdocassistant.cpp:55 #, kde-format msgid "" "Please select a customer as addressee for the document. If there is no entry" " for the customer in the addressbook yet, it can be opened by clicking on " "the button below." msgstr "" "Bitte wählen Sie einen Kunden als Adressaten für das Dokument aus. Wenn es " "noch keinen Eintrag für den Kunden im Adressbuch gibt, kann es hier geöffnet" " und ein neuer Kunde angelegt werden." #: newdocassistant.cpp:100 #, kde-format msgid "" "Select a document type and a date. A comment on the whiteboard helps to " "classify the document." msgstr "" "Wählen Sie einen Dokumenttyp und das Datum aus. Eine Notiz hilft, das " "Dokument besser zu klassifizieren." #: newdocassistant.cpp:107 #, kde-format msgid "Customer: Not yet selected!" msgstr "Kunde: Es ist noch kein Kunde ausgewählt." #: newdocassistant.cpp:116 #, kde-format msgid "Document &Type:" msgstr "&Dokumenttyp:" #: newdocassistant.cpp:120 #, kde-format msgid "Document Date: " msgstr "Dokumentdatum:" #: newdocassistant.cpp:123 #, kde-format msgid "Whiteboard Content:" msgstr "Notizen:" #: newdocassistant.cpp:127 #, kde-format msgid "Copy document items from predecessor document" msgstr "Kopiere Posten vom Vorgängerdokument" #: newdocassistant.cpp:175 #, kde-format msgid "Create a new Kraft Document" msgstr "Erzeuge ein neues Kraft-Dokument" #: newdocassistant.cpp:265 #, kde-format msgid "Followup Document for %1" msgstr "Folgedokument für %1" #: numbercycledialog.cpp:52 #, kde-format msgid "Edit Number Cycles" msgstr "Nummernbestimmung ändern" #: numbercycledialog.cpp:67 #, kde-format msgid "" "The template may contain the following tags:
  • %y or %yyyy - the year " "of the documents date.
  • %yy - the year of the document (two " "digits).
  • %w - the week number of the documents date.
  • %ww - " "the week number of the documents date with leading zero.
  • %d - the " "day number of the documents date.
  • %dd - the day number of the " "documents date with leading zero.
  • %m or %M - the month number of the" " documents date.
  • %MM - the month number with leading " "zero.
  • %c - the customer id from kaddressbook
  • %i - the unique" " counter
  • %ii .. %iiiiii - the counter padded with leading 0, ie. " "012
  • %n - a day based counter, resets every day. Combined with date, " "it makes the number unique.
  • %nn .. %nnnnnn - the day based counter " "padded with leading 0.
  • %type - the localised doc type (offer, " "invoice etc.)
  • %uid - the contact id of the client.
%i or %n" " need to be part of the template." msgstr "" "Die Vorlage kann die folgenden Platzhalter beinhalten:
  • %y or %yyyy - " "das Jahr des Dokumentdatums.
  • %yy - Jahr des Dokument Datums " "(zweistellig).
  • %w - Woche des Dokument Datums.
  • %ww - Woche " "des Dokument Datums mit führender Null.
  • %d - Nummer des Tages des " "Dokument Datums.
  • %dd - Tag des Dokumentdatums mit führender " "Null
  • %m or %M - Monatsnummer des Dokumentdatums.
  • %MM - " "Monatsnummer mit führender Null.
  • %c - Adressnummer aus " "Adressbuch
  • %i - der eindeutige Zähler
  • %ii .. %iiiiii - " "Zähler mit führender Null, zb. 0012
  • %n - Ein tagesbasierter Zähler, " "der jeden Tag zurückgestellt wird. Zusammen mit dem Datum " "eindeutig.
  • %nn .. %nnnnnn - tagesbasierter Zähler mit führender " "Null.
  • %type - Dokumenttyp, zb. Angebot oder Rechnung
  • %uid - " "Kontakt-ID des Kunden.
%i oder %n müssen Teil der Vorlage sein." #: numbercycledialog.cpp:141 #, kde-format msgid "Doc-Type" msgstr "Dokumenttyp" #: numbercycledialog.cpp:154 #, kde-format msgctxt "do not translate %i, it is a template variable." msgid "(%i added)" msgstr "(%i hinzugefügt)" #: numbercycledialog.cpp:227 #, kde-format msgid "Add Number Cycle" msgstr "Nummernbestimmung hinzufügen" #: numbercycledialog.cpp:228 #, kde-format msgid "Enter the name of a new number cycle." msgstr "Geben Sie den Namen für die neue Nummernbestimmung an." #: numbercycledialog.cpp:286 #, kde-format msgid "The numbercycle %1 is still assigned to a document type." msgstr "Der Nummernkreis %1 ist noch einem Dokumenttyp zugeordnet." #: numbercycledialog.cpp:287 #, kde-format msgid "" "The number cycle can not be deleted as long as it is assigned to a document " "type." msgstr "" "Der Nummernkreis ist noch einer oder mehreren Dokumentenarten zugeordnet und" " kann erst nach Aufhebung aller Zuordnungen gelöscht werden." #: numbercycledialog.cpp:346 #, kde-format msgid "Dangerous Counter Change" msgstr "Gefährlicher neuer Anfangswert" #: numbercycledialog.cpp:347 #, kde-format msgid "The new counter is lower than the old one. " msgstr "Der neue Zähler ist kleiner als der alte." #: numbercycledialog.cpp:348 #, kde-format msgid "" "That has potential to create duplicate document numbers. Do you really want " "to decrease it?" msgstr "" "Der neue Anfangswert ist niedriger als der vorherige. Dadurch besteht die " "Möglichkeit, dass Dokumentennummern doppelt vergeben werden. Möchten Sie den" " neuen Anfangswert wirklich übernehmen?" #: portalview.cpp:68 #, kde-format msgid "About Kraft" msgstr "Über Kraft" #: portalview.cpp:98 #, kde-format msgid "Documents" msgstr "Dokumente" #: portalview.cpp:105 #, kde-format msgid "Timeline" msgstr "Zeitverlauf" #: portalview.cpp:113 #, kde-format msgid "Catalogs" msgstr "Kataloge" #: portalview.cpp:152 #, kde-format msgid "Kraft Document Overview" msgstr "Kraft-Dokument-Übersicht" #: portalview.cpp:159 portalview.cpp:178 #, kde-format msgid "Available Catalogs" msgstr "Verfügbare Kataloge" #: portalview.cpp:161 #, kde-format msgid "No catalogs available." msgstr "Keine Kataloge installiert" #: portalview.cpp:210 #, kde-format msgid "Open" msgstr "Öffnen" #: portalview.cpp:221 #, kde-format msgid "No templates yet." msgstr "Noch keine Vorlage angelegt." #: portalview.cpp:225 #, kde-format msgid "%1 templates in %2 chapters
last modified at %3" msgstr "%1 Vorlagen in %2 Kapiteln
Zuletzt angepasst am %3" #: portalview.cpp:276 #, kde-format msgid "Kraft Website" msgstr "Kraft Webseite" #: portalview.cpp:279 #, kde-format msgctxt "The string is followed by a link to the GPL2 text" msgid "Kraft is free software licensed under the" msgstr "Kraft ist freie Software lizensiert unter" #: portalview.cpp:280 #, kde-format msgctxt "The string is followed by the link to github" msgid "Kraft is maintained on " msgstr "Kraft wird entwickelt auf " #: portalview.cpp:281 #, kde-format msgid "Authors" msgstr "Autoren" #: portalview.cpp:282 #, kde-format msgid "Developer and Maintainer" msgstr "Entwickler und Maintainer" #: portalview.cpp:283 #, kde-format msgid "Developer" msgstr "Entwickler" #: portalview.cpp:284 #, kde-format msgctxt "The person who provided the logo graphics" msgid "Logo design" msgstr "Logo Entwurf" #: portalview.cpp:285 #, kde-format msgctxt "The person who provided the user manual" msgid "User Manual" msgstr "Bentzerhandbuch" #: portalview.cpp:287 #, kde-format msgid "" "Kraft helps you to handle documents like quotes and invoices in your small " "business." msgstr "" "Kraft ist freie Software zur schnellen, flexiblen und professionellen " "Angebots- und Rechnungsbearbeitung." #: portalview.cpp:288 #, kde-format msgid "Welcome to Kraft" msgstr "Willkommen zu Kraft" #: portalview.cpp:289 #, kde-format msgid "Kraft Version" msgstr "Kraft-Version" #: portalview.cpp:291 #, kde-format msgid "Codename" msgstr "Codename" #: portalview.cpp:300 #, kde-format msgid "Git Information" msgstr "Git Information" #: portalview.cpp:308 #, kde-format msgid "Country Setting" msgstr "Ländereinstellung" #: portalview.cpp:311 #, kde-format msgid "Language Setting" msgstr "Spracheinstellung" #: portalview.cpp:315 #, kde-format msgid "Kraft Initialisation Problem" msgstr "Kraft Initialisierungsproblem" #: portalview.cpp:316 #, kde-format msgid "" "There is a initialisation error on your system. Kraft will not work that " "way." msgstr "" "Bei der Initialisierung ist ein Fehler aufgetreten. Kraft wird so nicht " "funktionieren." #: portalview.cpp:323 #, kde-format msgid "Database Information" msgstr "Datenbank-Informationen" #: portalview.cpp:324 #, kde-format msgid "Kraft database name" msgstr "Kraft-Datenbankname" #: portalview.cpp:329 #, kde-format msgid "Required Version" msgstr "Nötige Version" #: portalview.cpp:332 #, kde-format msgid "Database schema version" msgstr "Datenbankschema-Version" #: portalview.cpp:334 #, kde-format msgid "Qt database driver" msgstr "Qt-Datenbank-Treiber" #: portalview.cpp:338 #, kde-format msgid "established" msgstr "Verbunden" #: portalview.cpp:338 #, kde-format msgid "NOT AVAILABLE!" msgstr "NICHT VERFÜGBAR" #: portalview.cpp:339 #, kde-format msgid "Database connection" msgstr "Datenbankverbindung" #: portalview.cpp:348 #, kde-format msgid "Database Version" msgstr "Datenbankversion" #: portalview.cpp:356 #, kde-format msgid "Addressbook Backend" msgstr "Adressbuch-Backend" #: portalview.cpp:357 #, kde-format msgid "Backend type" msgstr "Backendtyp" #: portalview.cpp:359 #, kde-format msgid "running" msgstr "läuft" #: portalview.cpp:359 #, kde-format msgid "not running" msgstr "nicht funktionsfähig" #: portalview.cpp:363 #, kde-format msgid "External Tools" msgstr "Externe Werkzeuge" #: portalview.cpp:365 #, kde-format msgid "RML to PDF conversion tool" msgstr "Umwandlungsprogramm (RML zu PDF):" #: portalview.cpp:367 #, kde-format msgid "not found!" msgstr "nicht gefunden." #: portalview.cpp:370 #, kde-format msgid "iconv tool for text import" msgstr "„iconv“-Werkzeug zum Textimport" #: portalview.cpp:373 #, kde-format msgid "weasyprint for PDF generation" msgstr "weasyprint zur PDF Generierung" #: portalview.cpp:377 #, kde-format msgid "not available" msgstr "nicht gefunden" #: portalview.cpp:382 #, kde-format msgid "Some Icons are made by" msgstr "Einige Icons sind erstellt von" #: portalview.cpp:383 #, kde-format msgid "Acknowledgements" msgstr "Danksagung" #: positionviewwidget.cpp:90 #, kde-format msgid "Item Actions" msgstr "Postenaktionen" #: positionviewwidget.cpp:93 #, kde-format msgid "Item Kind" msgstr "Postenart" #: positionviewwidget.cpp:94 positionviewwidget.cpp:687 #, kde-format msgid "Normal" msgstr "Normal" #: positionviewwidget.cpp:96 positionviewwidget.cpp:695 #, kde-format msgid "Alternative" msgstr "Alternative" #: positionviewwidget.cpp:98 #, kde-format msgid "On Demand" msgstr "Bei Bedarf" #: positionviewwidget.cpp:103 rc.cpp:265 rc.cpp:874 rc.cpp:1745 rc.cpp:2628 #: rc.cpp:3926 rc.cpp:4830 #, kde-format msgid "Tax" msgstr "Steuer" #: positionviewwidget.cpp:106 #, kde-format msgid "Taxfree Item" msgstr "Steuerfreier Posten" #: positionviewwidget.cpp:112 #, kde-format msgid "Reduced Tax" msgstr "Reduzierter Steuersatz" #: positionviewwidget.cpp:118 #, kde-format msgid "Full Tax" msgstr "Allgemeiner Steuersatz" #: positionviewwidget.cpp:127 #, kde-format msgid "Move Up" msgstr "Nach oben" #: positionviewwidget.cpp:129 #, kde-format msgid "Move Down" msgstr "Nach unten" #: positionviewwidget.cpp:131 #, kde-format msgid "Lock Item" msgstr "Posten sperren" #: positionviewwidget.cpp:133 #, kde-format msgid "Unlock Item" msgstr "Posten entsperren" #: positionviewwidget.cpp:135 #, kde-format msgid "Delete Item" msgstr "Posten löschen" #: positionviewwidget.cpp:226 #, kde-format msgid "All items" msgstr "Alle Posten" #: positionviewwidget.cpp:236 #, kde-format msgid "%1-tagged items" msgstr "Mit „%1“ markierte Posten" #: positionviewwidget.cpp:268 #, kde-format msgid "Tag: %1" msgstr "Markierung: %1" #: positionviewwidget.cpp:270 #, kde-format msgid "Tags:
    " msgstr "Markierungen:
      " #: positionviewwidget.cpp:281 #, kde-format msgid "No tags assigned yet." msgstr "Es sind noch keine Stichwörter zugewiesen." #: positionviewwidget.cpp:410 #, kde-format msgid "Active" msgstr "Aktiv" #: positionviewwidget.cpp:412 #, kde-format msgid "New" msgstr "Neu" #: positionviewwidget.cpp:414 #, kde-format msgid "Deleted" msgstr "Gelöscht" #: positionviewwidget.cpp:416 #, kde-format msgid "Locked" msgstr "Gesperrt" #: positionviewwidget.cpp:613 #, kde-format msgid "" "This item is either completely optional or its amount varies depending on " "the needs.

      Use the item toolbox to change the item type." msgstr "" "Dieser Posten ist entweder vollständig optional oder sein Betrag variiert " "abhängig von den Erfordernissen.

      Verwenden Sie die Posten-" "Werkzeuge, um die Art des Postens zu ändern." #: positionviewwidget.cpp:619 #, kde-format msgid "" "This is an alternative item.

      Use the position toolbox to change " "the item type." msgstr "" "Dies ist ein Alternativposten.

      Verwenden Sie die Posten-Werkzeuge, " "um die Art des Postens zu ändern." #: positionviewwidget.cpp:691 #, kde-format msgid "Demand" msgstr "Bedarf" #: prefswages.cpp:52 #, kde-format msgid "Code" msgstr "Code" #: prefswages.cpp:53 rc.cpp:126 rc.cpp:1036 rc.cpp:1874 rc.cpp:2757 #: rc.cpp:3808 rc.cpp:4712 templkataloglistview.cpp:46 #, kde-format msgid "Price" msgstr "Preis" #: prefswages.cpp:54 #, kde-format msgid "Sortkey" msgstr "Sortierschlüssel" #: prefswages.cpp:80 #, kde-format msgid "Up" msgstr "Nach oben" #: prefswages.cpp:85 #, kde-format msgid "Down" msgstr "Nach unten" #: prefswages.cpp:94 prefsunits.cpp:84 rc.cpp:313 rc.cpp:1166 rc.cpp:2070 #: rc.cpp:2953 rc.cpp:3523 rc.cpp:4427 #, kde-format msgid "Edit" msgstr "Bearbeiten" #: prefswages.cpp:201 #, kde-format msgid "Edit a wage group" msgstr "Lohngruppe bearbeiten" #: prefswages.cpp:241 #, kde-format msgid "

      Edit wage group

      " msgstr "

      Lohngruppe bearbeiten

      " #: prefsunits.cpp:54 #, kde-format msgid "Short" msgstr "Kurz" #: prefsunits.cpp:55 #, kde-format msgid "Long" msgstr "Lang" #: prefsunits.cpp:56 #, kde-format msgid "Short plural" msgstr "Mehrzahl kurz" #: prefsunits.cpp:57 #, kde-format msgid "Long plural" msgstr "Mehrzahl lang" #: prefsunits.cpp:58 #, kde-format msgid "ECE20" msgstr "ECE20" #: prefsunits.cpp:153 #, kde-format msgid "Edit a unit" msgstr "Eine Maßeinheit bearbeiten" #: prefsunits.cpp:197 #, kde-format msgid "

      Edit unit

      " msgstr "

      Maßeinheit bearbeiten

      " #: reportgenerator.cpp:113 #, kde-format msgid "Document generation process is still running." msgstr "Die Dokument-Generierung läuft noch." #: reportgenerator.cpp:168 #, kde-format msgid "Template file is not accessible." msgstr "Vorlage ist nicht lesbar." #: reportgenerator.cpp:193 #, kde-format msgid "The template conversion failed." msgstr "Vorlagenkonvertierung ist fehlgeschlagen." #: reportgenerator.cpp:201 #, kde-format msgid "Saving to temporar file failed." msgstr "Speichern in eine temporäre Datei ist fehlgeschlagen." #: reportgenerator.cpp:332 #, kde-format msgid "No converter error." msgstr "Kein Konverter gefunden." #: reportgenerator.cpp:335 #, kde-format msgid "The ReportLab based converter script can not be executed." msgstr "Das Reportlab-Script kann nicht ausgeführt werden." #: reportgenerator.cpp:338 #, kde-format msgid "An unknown error happened." msgstr "Ein unerwarteter Fehler ist aufgetreten." #: reportgenerator.cpp:341 #, kde-format msgid "The ReportLab python module is not installed." msgstr "Das Reportlab Python-Modul ist nicht installiert." #: reportgenerator.cpp:344 #, kde-format msgid "The PyPDF2 python module is not installed." msgstr "Das PyPDF2 Python Modul ist nicht installiert." #: reportgenerator.cpp:347 #, kde-format msgid "The source file can not be read." msgstr "Die Quelldatei kann nicht gelesen werden." #: reportgenerator.cpp:350 #, kde-format msgid "The target can not be opened to write." msgstr "Das Ziel kann nicht zum Schreiben geöffnet werden." #: reportgenerator.cpp:353 #, kde-format msgid "The target file does not exist." msgstr "Die Zieldatei existiert nicht." #: reportgenerator.cpp:356 #, kde-format msgid "The WeasyPrint tool is not installed." msgstr "Das Tool Weasyprint ist nicht installiert." #: reportgenerator.cpp:359 #, kde-format msgid "The PDF merger utility failed." msgstr "Das Programm zum Verbinden von PDFs ist fehlgeschlagen." #: reportgenerator.cpp:378 #, kde-format msgid "There is not template defined for %1." msgstr "Für %1 ist keine Vorlage angegeben." #: reportgenerator.cpp:383 #, kde-format msgid "The template file %1 for document type %2 does not exist." msgstr "Die Vorlage %1 für Dokument Typ %2 existiert nicht." #: reportgenerator.cpp:387 #, kde-format msgid "The template file %1 for document type %2 can not be read." msgstr "Die Vorlage %1 für Dokument Typ %2 kann nicht gelesen werden." #: rc.cpp:6 rc.cpp:916 rc.cpp:1754 rc.cpp:2637 rc.cpp:3688 rc.cpp:4592 #: templkataloglistview.cpp:45 texteditdialog.cpp:76 #, kde-format msgid "Template" msgstr "Vorlage" #: rc.cpp:9 rc.cpp:919 rc.cpp:1757 rc.cpp:2640 rc.cpp:3691 rc.cpp:4595 #, kde-format msgid "Text:" msgstr "Text:" #: rc.cpp:12 rc.cpp:922 rc.cpp:1760 rc.cpp:2643 rc.cpp:3694 rc.cpp:4598 #, kde-format msgid "&Store in Chapter" msgstr "In Kategorie s&peichern" #: rc.cpp:15 rc.cpp:925 rc.cpp:1763 rc.cpp:2646 rc.cpp:3697 rc.cpp:4601 #, kde-format msgid "&Unit" msgstr "&Einheit" #: rc.cpp:18 rc.cpp:928 rc.cpp:1766 rc.cpp:2649 rc.cpp:3700 rc.cpp:4604 #, kde-format msgid "&Count Time for Overalltime" msgstr "Zeiten für &Gesamtzeit zusammenzählen" #: rc.cpp:24 rc.cpp:934 rc.cpp:1772 rc.cpp:2655 rc.cpp:3706 rc.cpp:4610 #, kde-format msgid "full" msgstr "Allgemein" #: rc.cpp:27 rc.cpp:937 rc.cpp:1775 rc.cpp:2658 rc.cpp:3709 rc.cpp:4613 #, kde-format msgid "half" msgstr "Reduziert" #: rc.cpp:30 rc.cpp:940 rc.cpp:1778 rc.cpp:2661 rc.cpp:3712 rc.cpp:4616 #, kde-format msgid "Time Calculation" msgstr "Arbeitszeit" #: rc.cpp:33 rc.cpp:72 rc.cpp:111 rc.cpp:943 rc.cpp:982 rc.cpp:1021 #: rc.cpp:1781 rc.cpp:1820 rc.cpp:1859 rc.cpp:2664 rc.cpp:2703 rc.cpp:2742 #: rc.cpp:3715 rc.cpp:3754 rc.cpp:3793 rc.cpp:4619 rc.cpp:4658 rc.cpp:4697 #, kde-format msgid "text" msgstr "text" #: rc.cpp:36 rc.cpp:946 rc.cpp:1784 rc.cpp:2667 rc.cpp:3718 rc.cpp:4622 #, kde-format msgid "Time measureable effort for this template:" msgstr "In Geldeinheiten umgerechneter Zeitaufwand für diese Vorlage:" #: rc.cpp:39 rc.cpp:81 rc.cpp:117 rc.cpp:949 rc.cpp:991 rc.cpp:1027 #: rc.cpp:1787 rc.cpp:1829 rc.cpp:1865 rc.cpp:2670 rc.cpp:2712 rc.cpp:2748 #: rc.cpp:3721 rc.cpp:3763 rc.cpp:3799 rc.cpp:4625 rc.cpp:4667 rc.cpp:4703 #, kde-format msgid "Label" msgstr "Bezeichnung" #: rc.cpp:42 rc.cpp:952 rc.cpp:1790 rc.cpp:2673 rc.cpp:3724 rc.cpp:4628 #, kde-format msgid "Duration" msgstr "Dauer" #: rc.cpp:45 rc.cpp:955 rc.cpp:1793 rc.cpp:2676 rc.cpp:3727 rc.cpp:4631 #, kde-format msgid "Hourly Rate" msgstr "Stundensatz" #: rc.cpp:48 rc.cpp:958 rc.cpp:1796 rc.cpp:2679 rc.cpp:3730 rc.cpp:4634 #, kde-format msgid "Glob. Rate" msgstr "Glob. Tarif" #: rc.cpp:51 rc.cpp:961 rc.cpp:1799 rc.cpp:2682 rc.cpp:3733 rc.cpp:4637 #, kde-format msgid "Adds a new time calculation part to the template" msgstr "Fügt eine neue Komponente zur Zeitberechnung zur Vorlage hinzu" #: rc.cpp:54 rc.cpp:93 rc.cpp:132 rc.cpp:964 rc.cpp:1003 rc.cpp:1042 #: rc.cpp:1802 rc.cpp:1841 rc.cpp:1880 rc.cpp:2685 rc.cpp:2724 rc.cpp:2763 #: rc.cpp:3736 rc.cpp:3775 rc.cpp:3814 rc.cpp:4640 rc.cpp:4679 rc.cpp:4718 #, kde-format msgid "new..." msgstr "Neu ..." #: rc.cpp:57 rc.cpp:967 rc.cpp:1805 rc.cpp:2688 rc.cpp:3739 rc.cpp:4643 #, kde-format msgid "Edits the current time calculation part" msgstr "Ändert die aktuelle Komponente zur Zeitberechnung" #: rc.cpp:60 rc.cpp:99 rc.cpp:138 rc.cpp:970 rc.cpp:1009 rc.cpp:1048 #: rc.cpp:1808 rc.cpp:1847 rc.cpp:1886 rc.cpp:2691 rc.cpp:2730 rc.cpp:2769 #: rc.cpp:3742 rc.cpp:3781 rc.cpp:3820 rc.cpp:4646 rc.cpp:4685 rc.cpp:4724 #, kde-format msgid "edit..." msgstr "Bearbeiten ..." #: rc.cpp:63 rc.cpp:973 rc.cpp:1811 rc.cpp:2694 rc.cpp:3745 rc.cpp:4649 #, kde-format msgid "Deletes the current time calculation part" msgstr "Löscht die aktuelle Komponente zur Zeitberechnung" #: rc.cpp:66 rc.cpp:105 rc.cpp:144 rc.cpp:976 rc.cpp:1015 rc.cpp:1054 #: rc.cpp:1814 rc.cpp:1853 rc.cpp:1892 rc.cpp:2697 rc.cpp:2736 rc.cpp:2775 #: rc.cpp:3748 rc.cpp:3787 rc.cpp:3826 rc.cpp:4652 rc.cpp:4691 rc.cpp:4730 #, kde-format msgid "delete" msgstr "Entfernen" #: rc.cpp:69 rc.cpp:979 rc.cpp:1817 rc.cpp:2700 rc.cpp:3751 rc.cpp:4655 #, kde-format msgid "Fix Costs" msgstr "Fixkosten" #: rc.cpp:75 rc.cpp:985 rc.cpp:1823 rc.cpp:2706 rc.cpp:3757 rc.cpp:4661 #, kde-format msgid "Fix costs for this template per one unit:" msgstr "Fixkosten für diese Vorlage für eine Einheit:" #: rc.cpp:84 rc.cpp:994 rc.cpp:1832 rc.cpp:2715 rc.cpp:3766 rc.cpp:4670 #, kde-format msgid "Single Price" msgstr "Einzelpreis" #: rc.cpp:87 rc.cpp:997 rc.cpp:1835 rc.cpp:2718 rc.cpp:3769 rc.cpp:4673 #, kde-format msgid "Overall Price" msgstr "Gesamtpreis" #: rc.cpp:90 rc.cpp:1000 rc.cpp:1838 rc.cpp:2721 rc.cpp:3772 rc.cpp:4676 #, kde-format msgid "adds a new fix calculation part" msgstr "Fügt eine neue Festpreis-Kalkulationskomponente hinzu" #: rc.cpp:96 rc.cpp:1006 rc.cpp:1844 rc.cpp:2727 rc.cpp:3778 rc.cpp:4682 #, kde-format msgid "edits the current fix calculation part" msgstr "Festpreis-Kalkulationskomponente bearbeiten" #: rc.cpp:102 rc.cpp:1012 rc.cpp:1850 rc.cpp:2733 rc.cpp:3784 rc.cpp:4688 #, kde-format msgid "deletes the current fix calculation part" msgstr "Festpreis-Kalkulationskomponente entfernen" #: rc.cpp:114 rc.cpp:1024 rc.cpp:1862 rc.cpp:2745 rc.cpp:3796 rc.cpp:4700 #, kde-format msgid "Needed materials for one unit of this template:" msgstr "Benötigte Materialien für eine Einheit dieser Vorlage:" #: rc.cpp:129 rc.cpp:1039 rc.cpp:1877 rc.cpp:2760 rc.cpp:3811 rc.cpp:4715 #, kde-format msgid "adds a new material calculation part" msgstr "Fügt eine neue Material-Kalkulationskomponente hinzu" #: rc.cpp:135 rc.cpp:1045 rc.cpp:1883 rc.cpp:2766 rc.cpp:3817 rc.cpp:4721 #, kde-format msgid "edits the current material part" msgstr "Material-Kalkulationskomponente bearbeiten" #: rc.cpp:141 rc.cpp:1051 rc.cpp:1889 rc.cpp:2772 rc.cpp:3823 rc.cpp:4727 #, kde-format msgid "deletes the current material calculation part" msgstr "Material-Kalkulationskomponente entfernen" #: rc.cpp:147 rc.cpp:1057 rc.cpp:1895 rc.cpp:2778 rc.cpp:3829 rc.cpp:4733 #, kde-format msgid "Overall Price per Unit" msgstr "Gesamtpreis pro Einheit" #: rc.cpp:150 rc.cpp:1060 rc.cpp:1898 rc.cpp:2781 rc.cpp:3832 rc.cpp:4736 #, kde-format msgid "&Manual Price" msgstr "&Manueller Preis" #: rc.cpp:153 rc.cpp:1063 rc.cpp:1901 rc.cpp:2784 rc.cpp:3835 rc.cpp:4739 #, kde-format msgid "Calculated Price" msgstr "Kalkulierter Preis" #: rc.cpp:156 rc.cpp:1066 rc.cpp:1904 rc.cpp:2787 rc.cpp:3838 rc.cpp:4742 #, kde-format msgid "Fix Costs Part:" msgstr "Fixkostenanteil:" #: rc.cpp:159 rc.cpp:1069 rc.cpp:1907 rc.cpp:2790 rc.cpp:3841 rc.cpp:4745 #, kde-format msgid "Material Part:" msgstr "Material-Anteil:" #: rc.cpp:162 rc.cpp:1072 rc.cpp:1910 rc.cpp:2793 rc.cpp:3844 rc.cpp:4748 #, kde-format msgid "Profit:" msgstr "Gewinn:" #: rc.cpp:166 rc.cpp:1076 rc.cpp:1914 rc.cpp:2797 rc.cpp:3848 rc.cpp:4752 #, no-c-format, kde-format msgid " %" msgstr " %" #: rc.cpp:169 rc.cpp:1079 rc.cpp:1917 rc.cpp:2800 rc.cpp:3851 rc.cpp:4755 #, kde-format msgid "Time Calculation Part:" msgstr "Arbeitszeit:" #: rc.cpp:172 rc.cpp:1082 rc.cpp:1920 rc.cpp:2803 rc.cpp:3854 rc.cpp:4758 #, kde-format msgid "Calculated Price:" msgstr "Kalkulierter Preis:" #: rc.cpp:175 rc.cpp:1085 rc.cpp:1923 rc.cpp:2806 rc.cpp:3857 rc.cpp:4761 #, kde-format msgid "88.888,88 €" msgstr "88.888,88 €" #: rc.cpp:178 rc.cpp:1088 rc.cpp:1959 rc.cpp:2842 rc.cpp:3860 rc.cpp:4764 #, kde-format msgid "Database creation and initial schema setup:" msgstr "Einrichtung der Datenbank und Setup des Anfangsschemas:" #: rc.cpp:181 rc.cpp:190 rc.cpp:844 rc.cpp:1091 rc.cpp:1100 rc.cpp:1706 #: rc.cpp:1962 rc.cpp:1971 rc.cpp:2598 rc.cpp:2845 rc.cpp:2854 rc.cpp:3502 #: rc.cpp:3863 rc.cpp:3872 rc.cpp:4385 rc.cpp:4767 rc.cpp:4776 rc.cpp:5292 #, kde-format msgid "0 / 129" msgstr "0 / 129" #: rc.cpp:184 rc.cpp:193 rc.cpp:847 rc.cpp:1094 rc.cpp:1103 rc.cpp:1709 #: rc.cpp:1965 rc.cpp:1974 rc.cpp:2601 rc.cpp:2848 rc.cpp:2857 rc.cpp:3505 #: rc.cpp:3866 rc.cpp:3875 rc.cpp:4388 rc.cpp:4770 rc.cpp:4779 rc.cpp:5295 #, kde-format msgid "X" msgstr "X" #: rc.cpp:187 rc.cpp:1097 rc.cpp:1968 rc.cpp:2851 rc.cpp:3869 rc.cpp:4773 #, kde-format msgid "Filling the database with initial values:" msgstr "Füllen der Datenbank mit Anfangswerten:" #: rc.cpp:196 rc.cpp:850 rc.cpp:1106 rc.cpp:1712 rc.cpp:1977 rc.cpp:2604 #: rc.cpp:2860 rc.cpp:3508 rc.cpp:3878 rc.cpp:4391 rc.cpp:4782 rc.cpp:5298 #, kde-format msgid "Status: " msgstr "Status: " #: rc.cpp:199 rc.cpp:1109 rc.cpp:1980 rc.cpp:2863 rc.cpp:3881 rc.cpp:4785 #, kde-format msgid "Database setup status..." msgstr "Status der Datenbank-Einrichtung ..." #: rc.cpp:202 rc.cpp:1112 rc.cpp:1926 rc.cpp:2809 rc.cpp:3884 rc.cpp:4788 #, kde-format msgid "Bruns Data File:" msgstr "Bruns-Datendatei:" #: rc.cpp:205 rc.cpp:1115 rc.cpp:1929 rc.cpp:2812 rc.cpp:3887 rc.cpp:4791 #, kde-format msgid "Bruns Key File:" msgstr "Bruns-Schlüsseldatei:" #: rc.cpp:208 rc.cpp:1118 rc.cpp:1932 rc.cpp:2815 rc.cpp:3890 rc.cpp:4794 #, kde-format msgid "Qt Database Driver:" msgstr "Qt-Datenbank-Treiber:" #: rc.cpp:211 rc.cpp:1121 rc.cpp:1935 rc.cpp:2818 rc.cpp:3893 rc.cpp:4797 #, kde-format msgid "Database Server:" msgstr "Datenbank-Server:" #: rc.cpp:214 rc.cpp:1124 rc.cpp:1938 rc.cpp:2821 rc.cpp:3896 rc.cpp:4800 #, kde-format msgid "Server Port:" msgstr "Server Port:" #: rc.cpp:217 rc.cpp:1127 rc.cpp:1941 rc.cpp:2824 rc.cpp:3899 rc.cpp:4803 #, kde-format msgid "Database Name" msgstr "Datenbankname" #: rc.cpp:220 rc.cpp:700 rc.cpp:1130 rc.cpp:1555 rc.cpp:1944 rc.cpp:2399 #: rc.cpp:2827 rc.cpp:3315 rc.cpp:3902 rc.cpp:4238 rc.cpp:4806 rc.cpp:5145 #, kde-format msgid "Database User:" msgstr "Datenbank-Benutzer:" #: rc.cpp:223 rc.cpp:1133 rc.cpp:1947 rc.cpp:2830 rc.cpp:3905 rc.cpp:4809 #, kde-format msgid "Database Password:" msgstr "Datenbank-Passwort:" #: rc.cpp:226 rc.cpp:1136 rc.cpp:1950 rc.cpp:2833 rc.cpp:3908 rc.cpp:4812 #, kde-format msgid "The default database name when creating new databases" msgstr "Standard-Datenbankname bei neu erstellter Datenbank" #: rc.cpp:229 rc.cpp:1139 rc.cpp:1953 rc.cpp:2836 rc.cpp:3911 rc.cpp:4815 #, kde-format msgid "File Name" msgstr "Dateiname" #: rc.cpp:232 rc.cpp:1142 rc.cpp:1956 rc.cpp:2839 rc.cpp:3914 rc.cpp:4818 #, kde-format msgid "The path where database file are stored. Leave empty!" msgstr "Pfad zu den Datenbankdateien. Leer lassen!" #: rc.cpp:235 rc.cpp:1145 rc.cpp:2016 rc.cpp:2899 rc.cpp:3640 rc.cpp:4544 #, kde-format msgid "Database Update:" msgstr "Datenbank-Aktualisierung:" #: rc.cpp:238 rc.cpp:1148 rc.cpp:2019 rc.cpp:2902 rc.cpp:3643 rc.cpp:4547 #, kde-format msgid "Overall Progress:" msgstr "Gesamtfortschritt:" #: rc.cpp:241 rc.cpp:1151 rc.cpp:2022 rc.cpp:2905 rc.cpp:3646 rc.cpp:4550 #, kde-format msgid "Detail Progress:" msgstr "Fortschrittsanzeige:" #: rc.cpp:244 rc.cpp:1154 rc.cpp:2025 rc.cpp:2908 rc.cpp:3649 rc.cpp:4553 #, kde-format msgid "Status:" msgstr "Status:" #: rc.cpp:247 rc.cpp:1289 rc.cpp:1727 rc.cpp:2610 rc.cpp:3631 rc.cpp:4535 #, kde-format msgid "" "

      Kraft uses a database backend to store values. By " "default it uses a file based database with easy setup targeted to single " "user mode.


      " msgstr "" "

      Kraft nutzt ein Datenbank-Backend, um Werte zu " "speichern. Standardmäßig wird eine dateibasierte Datenbank mit einfacher " "Einrichtung verwendet, die auf Einbenutzerbetrieb ausgelegt ist. " "


      Bitte wählen Sie das Datenbank-Backend, das " "Sie verwenden möchten:" #: rc.cpp:250 rc.cpp:1292 rc.cpp:1730 rc.cpp:2613 rc.cpp:3634 rc.cpp:4538 #, kde-format msgid "SQLite 3 - file based database (default)" msgstr "SQLite 3 – Datei-basierte Datenbank (Voreinstellung)" #: rc.cpp:253 rc.cpp:1295 rc.cpp:1733 rc.cpp:2616 rc.cpp:3637 rc.cpp:4541 #, kde-format msgid "MySQL Serverbased Database for advanced Setups" msgstr "MySQL – Server-basierte Datenbank für fortgeschrittene Einrichtungen" #: rc.cpp:256 rc.cpp:865 rc.cpp:1736 rc.cpp:2619 rc.cpp:3917 rc.cpp:4821 #, kde-format msgid "Footer Texts" msgstr "Fußzeilentexte" #: rc.cpp:259 rc.cpp:868 rc.cpp:1739 rc.cpp:2622 rc.cpp:3920 rc.cpp:4824 #, kde-format msgid "&Summary Text on Last Page:" msgstr "&Zusammenfassung auf letzter Seite:" #: rc.cpp:262 rc.cpp:871 rc.cpp:1742 rc.cpp:2625 rc.cpp:3923 rc.cpp:4827 #, kde-format msgid "&Greeting:" msgstr "&Anrede:" #: rc.cpp:268 rc.cpp:877 rc.cpp:1748 rc.cpp:2631 rc.cpp:3929 rc.cpp:4833 #, kde-format msgid "Document &Tax:" msgstr "&Steuersatz:" #: rc.cpp:271 rc.cpp:880 rc.cpp:2028 rc.cpp:2911 rc.cpp:3932 rc.cpp:4836 #, kde-format msgid "TextLabel" msgstr "Textlabel" #: rc.cpp:274 rc.cpp:883 rc.cpp:2031 rc.cpp:2914 rc.cpp:3935 rc.cpp:4839 #, kde-format msgid "&Project:" msgstr "&Projekt:" #: rc.cpp:277 rc.cpp:886 rc.cpp:2034 rc.cpp:2917 rc.cpp:3938 rc.cpp:4842 #, kde-format msgid "&Whiteboard:" msgstr "&Notizen:" #: rc.cpp:280 rc.cpp:889 rc.cpp:2037 rc.cpp:2920 rc.cpp:3941 rc.cpp:4845 #, kde-format msgid "" "Enter a label that describes the project. This may appear on the customer " "document." msgstr "" "Geben Sie eine Beschriftung an, die das Projekt beschreibt. Diese kann auf " "dem Kundendokument erscheinen." #: rc.cpp:283 rc.cpp:892 rc.cpp:2040 rc.cpp:2923 rc.cpp:3944 rc.cpp:4848 #, kde-format msgid "Postal &Address:" msgstr "&Anschrift:" #: rc.cpp:286 rc.cpp:895 rc.cpp:2043 rc.cpp:2926 rc.cpp:3947 rc.cpp:4851 #, kde-format msgid "not selected" msgstr "nicht ausgewählt" #: rc.cpp:289 rc.cpp:898 rc.cpp:2046 rc.cpp:2929 rc.cpp:3950 rc.cpp:4854 #, kde-format msgid "Select an addressee from the address books." msgstr "Wählt eine Adresse aus den Adressbüchern." #: rc.cpp:292 rc.cpp:901 rc.cpp:2049 rc.cpp:2932 rc.cpp:3953 rc.cpp:4857 #, kde-format msgid "select..." msgstr "Auswählen ..." #: rc.cpp:295 rc.cpp:904 rc.cpp:2052 rc.cpp:2935 rc.cpp:3956 rc.cpp:4860 #, kde-format msgid "&Salutatory Address:" msgstr "&Grußformel:" #: rc.cpp:298 rc.cpp:907 rc.cpp:2055 rc.cpp:2938 rc.cpp:3959 rc.cpp:4863 #, kde-format msgid "Customer:" msgstr "Kunde:" #: rc.cpp:301 rc.cpp:910 rc.cpp:2058 rc.cpp:2941 rc.cpp:3962 rc.cpp:4866 #, kde-format msgid "&Entry Text on First Page:" msgstr "&Einleitender Text auf der ersten Seite:" #: rc.cpp:304 rc.cpp:733 rc.cpp:1157 rc.cpp:1588 rc.cpp:2061 rc.cpp:2432 #: rc.cpp:2944 rc.cpp:3348 rc.cpp:3514 rc.cpp:4271 rc.cpp:4418 rc.cpp:5178 #, kde-format msgid "Click to add a new document type to the list." msgstr "Klicken Sie, um der Liste einen neuen Dokumenttyp hinzuzufügen." #: rc.cpp:310 rc.cpp:1163 rc.cpp:2067 rc.cpp:2950 rc.cpp:3520 rc.cpp:4424 #, kde-format msgid "click to edit the selected document type name" msgstr "" "Klicken Sie hier, um den Namen des ausgewählten Dokumenttyps zu bearbeiten." #: rc.cpp:316 rc.cpp:739 rc.cpp:1169 rc.cpp:1594 rc.cpp:2073 rc.cpp:2438 #: rc.cpp:2956 rc.cpp:3354 rc.cpp:3526 rc.cpp:4277 rc.cpp:4430 rc.cpp:5184 #, kde-format msgid "click to remove the current document type" msgstr "Klicken Sie hier, um den aktuellen Dokumenttyp zu entfernen." #: rc.cpp:322 rc.cpp:1175 rc.cpp:2079 rc.cpp:2962 rc.cpp:3532 rc.cpp:4436 #, kde-format msgid "Unique Document Number" msgstr "Eindeutige Dokumentennummer" #: rc.cpp:325 rc.cpp:1178 rc.cpp:2082 rc.cpp:2965 rc.cpp:3535 rc.cpp:4439 #, kde-format msgid "Number &Cycle:" msgstr "Nummern&bestimmung:" #: rc.cpp:328 rc.cpp:337 rc.cpp:340 rc.cpp:724 rc.cpp:1181 rc.cpp:1190 #: rc.cpp:1193 rc.cpp:1579 rc.cpp:2085 rc.cpp:2094 rc.cpp:2097 rc.cpp:2423 #: rc.cpp:2968 rc.cpp:2977 rc.cpp:2980 rc.cpp:3339 rc.cpp:3538 rc.cpp:3547 #: rc.cpp:3550 rc.cpp:4262 rc.cpp:4442 rc.cpp:4451 rc.cpp:4454 rc.cpp:5169 #, kde-format msgid "example" msgstr "Beispiel" #: rc.cpp:331 rc.cpp:1184 rc.cpp:2088 rc.cpp:2971 rc.cpp:3541 rc.cpp:4445 #, kde-format msgid "ident Template:" msgstr "Nummernvorlage:" #: rc.cpp:334 rc.cpp:718 rc.cpp:1187 rc.cpp:1573 rc.cpp:2091 rc.cpp:2417 #: rc.cpp:2974 rc.cpp:3333 rc.cpp:3544 rc.cpp:4256 rc.cpp:4448 rc.cpp:5163 #, kde-format msgid "Example Id:" msgstr "Beispielnummer:" #: rc.cpp:343 rc.cpp:1196 rc.cpp:2100 rc.cpp:2983 rc.cpp:3553 rc.cpp:4457 #, kde-format msgid "Counter:" msgstr "Anfangswert:" #: rc.cpp:346 rc.cpp:1199 rc.cpp:2103 rc.cpp:2986 rc.cpp:3556 rc.cpp:4460 #, kde-format msgid "&Edit Number Cycles..." msgstr "Nummernkreise &bearbeiten ..." #: rc.cpp:349 rc.cpp:1202 rc.cpp:2106 #, kde-format msgid "Template for PDF Creation" msgstr "Vorlage für PDF-Erstellung" #: rc.cpp:352 rc.cpp:1205 #, kde-format msgid "&Template File" msgstr "&Vorlagendatei" #: rc.cpp:355 rc.cpp:1208 rc.cpp:2115 rc.cpp:2998 rc.cpp:3568 rc.cpp:4472 #, kde-format msgid "W&atermark:" msgstr "W&asserzeichen:" #: rc.cpp:358 rc.cpp:1211 rc.cpp:2121 rc.cpp:3001 rc.cpp:3571 rc.cpp:4475 #, kde-format msgid "no watermark" msgstr "Kein Wasserzeichen" #: rc.cpp:361 rc.cpp:1214 rc.cpp:2124 rc.cpp:3004 rc.cpp:3574 rc.cpp:4478 #, kde-format msgid "on first page" msgstr "Auf erster Seite" #: rc.cpp:364 rc.cpp:1217 rc.cpp:2127 rc.cpp:3007 rc.cpp:3577 rc.cpp:4481 #, kde-format msgid "on all pages" msgstr "Auf allen Seiten" #: rc.cpp:367 rc.cpp:1220 #, kde-format msgid "&Watermark File" msgstr "&Wasserzeichendatei" #: rc.cpp:370 rc.cpp:1223 rc.cpp:1983 rc.cpp:2866 rc.cpp:3598 rc.cpp:4502 #, kde-format msgid "Calculation Parts Fix" msgstr "Fixkostenanteil der Kalkulation" #: rc.cpp:373 rc.cpp:1226 rc.cpp:1986 rc.cpp:2869 rc.cpp:3601 rc.cpp:4505 #, kde-format msgid "

      Fix Cost Parts

      " msgstr "

      Fixkostenanteil

      " #: rc.cpp:376 rc.cpp:1229 rc.cpp:1989 rc.cpp:2872 rc.cpp:3604 rc.cpp:4508 #, kde-format msgid "Add a fix cost for one unit of the template:" msgstr "Fixkosten für eine Einheit der Vorlage hinzufügen" #: rc.cpp:379 rc.cpp:808 rc.cpp:1232 rc.cpp:1529 rc.cpp:1992 rc.cpp:2528 #: rc.cpp:2875 rc.cpp:3432 rc.cpp:3607 rc.cpp:4346 rc.cpp:4511 rc.cpp:5253 #, kde-format msgid "&Label:" msgstr "&Bezeichnung" #: rc.cpp:382 rc.cpp:1235 rc.cpp:1995 rc.cpp:2878 rc.cpp:3610 rc.cpp:4514 #, kde-format msgid "describing text" msgstr "Beschreibungstext" #: rc.cpp:385 rc.cpp:1238 rc.cpp:1998 rc.cpp:2881 rc.cpp:3613 rc.cpp:4517 #, kde-format msgid "amortisation" msgstr "Amortisation" #: rc.cpp:388 rc.cpp:680 rc.cpp:1241 rc.cpp:1511 rc.cpp:2001 rc.cpp:2211 #: rc.cpp:2884 rc.cpp:3106 rc.cpp:3616 rc.cpp:4218 rc.cpp:4520 rc.cpp:5125 #, kde-format msgid "&Amount:" msgstr "&Menge:" #: rc.cpp:391 rc.cpp:1244 rc.cpp:2004 rc.cpp:2887 rc.cpp:3619 rc.cpp:4523 #, kde-format msgid "amount multiplier" msgstr "Betrags-Multiplikator" #: rc.cpp:394 rc.cpp:1247 rc.cpp:2007 rc.cpp:2890 rc.cpp:3622 rc.cpp:4526 #, kde-format msgid "at &Price:" msgstr "zum &Preis von:" #: rc.cpp:397 rc.cpp:683 rc.cpp:1250 rc.cpp:1514 rc.cpp:2010 rc.cpp:2214 #: rc.cpp:2893 rc.cpp:3109 rc.cpp:3625 rc.cpp:4221 rc.cpp:4529 rc.cpp:5128 #, kde-format msgid "Price for one piece" msgstr "Stückpreis" #: rc.cpp:400 rc.cpp:1253 rc.cpp:2013 rc.cpp:2896 rc.cpp:3628 rc.cpp:4532 #, kde-format msgid "€" msgstr "€" #: rc.cpp:403 rc.cpp:1256 rc.cpp:2133 rc.cpp:3028 rc.cpp:3652 rc.cpp:4556 #, kde-format msgid "Form" msgstr "Formular" #: rc.cpp:406 rc.cpp:1259 rc.cpp:2136 rc.cpp:3031 rc.cpp:3655 rc.cpp:4559 #: tagtemplatesdialog.cpp:58 #, kde-format msgid "Name:" msgstr "Name:" #: rc.cpp:409 rc.cpp:1262 rc.cpp:2139 rc.cpp:3034 rc.cpp:3658 rc.cpp:4562 #, kde-format msgid "Organization:" msgstr "Organisation:" #: rc.cpp:412 rc.cpp:1265 rc.cpp:2142 rc.cpp:3037 rc.cpp:3661 rc.cpp:4565 #, kde-format msgid "Street:" msgstr "Straße" #: rc.cpp:415 rc.cpp:1268 rc.cpp:2145 rc.cpp:3040 rc.cpp:3664 rc.cpp:4568 #, kde-format msgid "Post Code:" msgstr "Postleitzahl:" #: rc.cpp:418 rc.cpp:1271 rc.cpp:2148 rc.cpp:3043 rc.cpp:3667 rc.cpp:4571 #, kde-format msgid "City:" msgstr "Ort:" #: rc.cpp:421 rc.cpp:1274 rc.cpp:2151 rc.cpp:3046 rc.cpp:3670 rc.cpp:4574 #, kde-format msgid "Phone:" msgstr "Telefon (Arbeit)" #: rc.cpp:424 rc.cpp:1277 rc.cpp:2154 rc.cpp:3049 rc.cpp:3673 rc.cpp:4577 #, kde-format msgid "Fax:" msgstr "Fax:" #: rc.cpp:427 rc.cpp:1280 rc.cpp:2157 rc.cpp:3052 rc.cpp:3676 rc.cpp:4580 #, kde-format msgid "Mobile Phone:" msgstr "Mobil:" #: rc.cpp:430 rc.cpp:1283 rc.cpp:2160 rc.cpp:3055 rc.cpp:3679 rc.cpp:4583 #, kde-format msgid "EMail:" msgstr "EMail:" #: rc.cpp:433 rc.cpp:1286 rc.cpp:2163 rc.cpp:3058 rc.cpp:3682 rc.cpp:4586 #, kde-format msgid "Website:" msgstr "Webseite:" #: rc.cpp:436 rc.cpp:1298 rc.cpp:2166 rc.cpp:3061 rc.cpp:3965 rc.cpp:4869 #, kde-format msgid "Import Document Items" msgstr "Dokumentposten importieren" #: rc.cpp:439 rc.cpp:1301 rc.cpp:2169 rc.cpp:3064 rc.cpp:3968 rc.cpp:4872 #, kde-format msgid "Import information" msgstr "Informationen importieren" #: rc.cpp:442 rc.cpp:1304 rc.cpp:2172 rc.cpp:3067 rc.cpp:3971 rc.cpp:4875 #, kde-format msgid "Select a &File to import from:" msgstr "Bitte wählen Sie die zu importierende &Datei:" #: rc.cpp:445 rc.cpp:1307 rc.cpp:2175 rc.cpp:3070 rc.cpp:3974 rc.cpp:4878 #, kde-format msgid "FixMe!" msgstr "FixMe!" #: rc.cpp:448 rc.cpp:1310 rc.cpp:2178 rc.cpp:3073 rc.cpp:3977 rc.cpp:4881 #, kde-format msgid "Import &Schema:" msgstr "&Schema importieren:" #: rc.cpp:451 rc.cpp:1313 rc.cpp:2181 rc.cpp:3076 rc.cpp:3980 rc.cpp:4884 #, kde-format msgid "this is interesting information about the selected schema" msgstr "Dies sind nützliche Informationen über das ausgewählte Schema." #: rc.cpp:454 rc.cpp:1316 rc.cpp:2184 rc.cpp:3079 rc.cpp:3983 rc.cpp:4887 #, kde-format msgid "Insert all Items &after" msgstr "Alle Posten einfügen &nach" #: rc.cpp:457 rc.cpp:481 rc.cpp:1319 rc.cpp:1352 rc.cpp:2187 rc.cpp:2241 #: rc.cpp:3082 rc.cpp:3136 rc.cpp:3986 rc.cpp:4010 rc.cpp:4890 rc.cpp:4914 #, kde-format msgid "Tags" msgstr "Stichwörter" #: rc.cpp:463 rc.cpp:1334 rc.cpp:2223 rc.cpp:3118 rc.cpp:3992 rc.cpp:4896 #, kde-format msgid "New Item Text" msgstr "Neuer Posten" #: rc.cpp:466 rc.cpp:1337 rc.cpp:2226 rc.cpp:3121 rc.cpp:3995 rc.cpp:4899 #, kde-format msgid "&insert" msgstr "Einfügen" #: rc.cpp:469 rc.cpp:1340 rc.cpp:2229 rc.cpp:3124 rc.cpp:3998 rc.cpp:4902 #, kde-format msgid "à" msgstr "à" #: rc.cpp:472 rc.cpp:1343 rc.cpp:2232 rc.cpp:3127 rc.cpp:4001 rc.cpp:4905 #, kde-format msgid "&after item" msgstr "&nach" #: rc.cpp:475 rc.cpp:1346 rc.cpp:2235 rc.cpp:3130 rc.cpp:4004 rc.cpp:4908 #, kde-format msgid "Keep this item as template for future documents" msgstr "Diesen Posten als Vorlage für zukünftige Dokumente speichern" #: rc.cpp:478 rc.cpp:1349 rc.cpp:2238 rc.cpp:3133 rc.cpp:4007 rc.cpp:4911 #, kde-format msgid "save in &chapter" msgstr "in &Kapitel" #: rc.cpp:490 rc.cpp:1361 rc.cpp:2250 rc.cpp:3157 rc.cpp:4019 rc.cpp:4923 #, kde-format msgid "Do Database Initialisation" msgstr "Datenbank initialisieren" #: rc.cpp:493 rc.cpp:1364 rc.cpp:2253 rc.cpp:3160 rc.cpp:4022 rc.cpp:4926 #, kde-format msgid "Do XML archiving of documents they're printed?" msgstr "XML-Dokumente archivieren, sobald sie gedruckt sind?" #: rc.cpp:496 rc.cpp:1367 rc.cpp:2256 rc.cpp:3163 rc.cpp:4025 rc.cpp:4929 #, kde-format msgid "" "Where Kraft stores the XML archive documents. If empty, KDEHOME/share/apps " "is used." msgstr "" "Speicherort für die XML-Archiv-Dokumente. Falls leer, wird " "$KDEHOME/share/apps verwendet." #: rc.cpp:499 rc.cpp:1370 rc.cpp:2259 rc.cpp:3166 rc.cpp:4028 rc.cpp:4932 #, kde-format msgid "The local xml document storage path" msgstr "Der lokale Speicherpfad für XML-Dokumente" #: rc.cpp:502 rc.cpp:1373 rc.cpp:2262 rc.cpp:3169 rc.cpp:4031 rc.cpp:4935 #, kde-format msgid "Default mail user agent. Set xdg for xdg-email" msgstr "Standard Email-Versende-Tool. Setze xdg für xdg-email" #: rc.cpp:505 rc.cpp:508 rc.cpp:1376 rc.cpp:1379 rc.cpp:2265 rc.cpp:2268 #: rc.cpp:3172 rc.cpp:3175 rc.cpp:4034 rc.cpp:4037 rc.cpp:4938 rc.cpp:4941 #, kde-format msgid "The default geometry of the document view dialog" msgstr "Standardgröße der Dokumentansicht" #: rc.cpp:511 rc.cpp:1382 rc.cpp:2271 rc.cpp:3178 rc.cpp:4040 rc.cpp:4944 #, kde-format msgid "The current state of the portal" msgstr "Der momentane Status des Portals" #: rc.cpp:514 rc.cpp:1385 rc.cpp:2274 rc.cpp:3181 rc.cpp:4043 rc.cpp:4947 #, kde-format msgid "The current geometry of the portal" msgstr "Die aktuelle Geometry des Portals" #: rc.cpp:517 rc.cpp:1388 rc.cpp:2277 rc.cpp:3184 rc.cpp:4046 rc.cpp:4950 #, kde-format msgid "The current geometry of the new doc assistant" msgstr "Aktuelle Geometry des Dokument-Neu Assistenten" #: rc.cpp:520 rc.cpp:1391 rc.cpp:2280 rc.cpp:3187 rc.cpp:4049 rc.cpp:4953 #, kde-format msgid "The splitter position of the document view dialog" msgstr "Teilungsstelle des Dokumentansicht-Dialogs" #: rc.cpp:523 rc.cpp:1394 rc.cpp:2283 rc.cpp:3190 rc.cpp:4052 rc.cpp:4956 #, kde-format msgid "The default size of the material catalog view" msgstr "Standardgröße der Material-Katalogs-Ansicht" #: rc.cpp:526 rc.cpp:1397 rc.cpp:2286 rc.cpp:3193 rc.cpp:4055 rc.cpp:4959 #, kde-format msgid "The splitter setting for the doc assistant" msgstr "Splitter-Einstellung für den Dokument-Assistenten" #: rc.cpp:529 rc.cpp:1400 rc.cpp:2289 rc.cpp:3196 rc.cpp:4058 rc.cpp:4962 #, kde-format msgid "The window size of the template to document dialog for plants" msgstr "Die Fenstergröße des Dialogs „Vorlage zu Dokument für Pflanzen“." #: rc.cpp:532 rc.cpp:1403 rc.cpp:2292 rc.cpp:3199 rc.cpp:4061 rc.cpp:4965 #, kde-format msgid "The window size of the template to document dialog" msgstr "Die Fenstergröße des Dialogs „Vorlage zu Dokument“" #: rc.cpp:535 rc.cpp:1406 rc.cpp:2295 rc.cpp:3202 rc.cpp:4064 rc.cpp:4968 #, kde-format msgid "The digest list column arrangement for the Latest-list" msgstr "" "Die Anordnung der Übersicht der Listenspalte für die Liste der letzten " "Einträge" #: rc.cpp:538 rc.cpp:1409 rc.cpp:2298 rc.cpp:3205 rc.cpp:4067 rc.cpp:4971 #, kde-format msgid "The digest list column arrangement for the all-list" msgstr "" "Die Anordnung der Übersicht der Listenspalte für die Liste aller Einträge" #: rc.cpp:541 rc.cpp:1412 rc.cpp:2301 rc.cpp:3208 rc.cpp:4070 rc.cpp:4974 #, kde-format msgid "The digest list column arrangement for timeline" msgstr "Die Anordnung der Übersicht der Listenspalte für die Zeitleiste" #: rc.cpp:544 rc.cpp:1415 rc.cpp:2304 rc.cpp:3211 rc.cpp:4073 rc.cpp:4977 #, kde-format msgid "The sizes of the slider in the address picker Widget" msgstr "Die Größe der Schieberegler im Adress-Auswahlfenster" #: rc.cpp:547 rc.cpp:1418 rc.cpp:2307 rc.cpp:3214 rc.cpp:4076 rc.cpp:4980 #, kde-format msgid "The state of the treeview inside the address selector widget" msgstr "Der Status der Baumansicht im Address-Auswahlwidget" #: rc.cpp:550 rc.cpp:1421 rc.cpp:2310 rc.cpp:3217 rc.cpp:4079 rc.cpp:4983 #, kde-format msgid "Size of the address select dialog" msgstr "Größe des Adressauswahldialoges" #: rc.cpp:553 rc.cpp:1424 rc.cpp:2313 rc.cpp:3220 rc.cpp:4082 rc.cpp:4986 #, kde-format msgid "State of the window of the material catalog" msgstr "Status des Materialkatalogfensters" #: rc.cpp:556 rc.cpp:1427 rc.cpp:2316 rc.cpp:3223 rc.cpp:4085 rc.cpp:4989 #, kde-format msgid "Geometry of the material catalog" msgstr "Geometrie des Materialkatalogfensters" #: rc.cpp:559 rc.cpp:1430 rc.cpp:2319 rc.cpp:3226 rc.cpp:4088 rc.cpp:4992 #, kde-format msgid "State of the header of the material catalog" msgstr "Standardgröße der Material-Katalogs-Ansicht" #: rc.cpp:562 rc.cpp:1433 rc.cpp:2322 rc.cpp:3229 rc.cpp:4091 rc.cpp:4995 #, kde-format msgid "State of the window of the template catalog" msgstr "Status des Katalog-Fensters" #: rc.cpp:565 rc.cpp:1436 rc.cpp:2325 rc.cpp:3232 rc.cpp:4094 rc.cpp:4998 #, kde-format msgid "Geometry the template catalog" msgstr "Geometrie des Katalog-Fensters" #: rc.cpp:568 rc.cpp:1439 rc.cpp:2328 rc.cpp:3235 rc.cpp:4097 rc.cpp:5001 #, kde-format msgid "State of the header of the template catalog" msgstr "Status der Kopfzeile des Vorlagenkatalogs" #: rc.cpp:571 rc.cpp:1442 rc.cpp:2331 rc.cpp:3238 rc.cpp:4100 rc.cpp:5004 #, kde-format msgid "" "Default percentage the sale price for a material should be higher than its " "purchase price" msgstr "" "Der prozentuale Aufschlag für den VK-Preis eines Materials sollte höher als " "sein EK-Preis sein." #: rc.cpp:574 rc.cpp:1445 rc.cpp:2334 rc.cpp:3241 rc.cpp:4103 rc.cpp:5007 #, kde-format msgid "The name of the last selected chapter in the catalog" msgstr "Der Name der zuletzt ausgewählten Kategorie im Katalog." #: rc.cpp:577 rc.cpp:1448 rc.cpp:2337 rc.cpp:3244 rc.cpp:4106 rc.cpp:5010 #, kde-format msgid "The complete filename of the trml2pdf binary" msgstr "Vollständiger Pfad zu trml2pdf" #: rc.cpp:580 rc.cpp:1451 rc.cpp:2340 rc.cpp:3247 rc.cpp:4109 rc.cpp:5013 #, kde-format msgid "The path to the output directory for document pdfs" msgstr "Pfad zum Ausgabe-Ordner für die Dokument-PDFs" #: rc.cpp:583 rc.cpp:1454 rc.cpp:2343 rc.cpp:3250 rc.cpp:4112 rc.cpp:5016 #, kde-format msgid "The last created doc type." msgstr "Typ des zuletzt erstellten Dokuments" #: rc.cpp:586 rc.cpp:1457 rc.cpp:2346 rc.cpp:3253 rc.cpp:4115 rc.cpp:5019 #, kde-format msgid "The date format for print." msgstr "Datumsformat für den Ausdruck." #: rc.cpp:589 rc.cpp:1460 rc.cpp:2349 rc.cpp:3256 rc.cpp:4118 rc.cpp:5022 #, kde-format msgid "The greeting below on the document footer." msgstr "Der Abschlussgruß im Dokumentfuß." #: rc.cpp:592 rc.cpp:1463 rc.cpp:2352 rc.cpp:3259 rc.cpp:4121 rc.cpp:5025 #, kde-format msgid "The salut message on the document header." msgstr "Die Anrede im Kopfbereich des Dokuments." #: rc.cpp:595 rc.cpp:1466 rc.cpp:2355 rc.cpp:3262 rc.cpp:4124 rc.cpp:5028 #, kde-format msgid "" "The name of the catalog chapter where to store new templates in by default" msgstr "" "Der Name des Katalogkapitels, in dem neue Vorlagen standardmäßig gespeichert" " werden" #: rc.cpp:598 rc.cpp:1469 rc.cpp:2358 rc.cpp:3265 rc.cpp:4127 rc.cpp:5031 #, kde-format msgid "The name of the last used import schema for items." msgstr "Der Name des letzten Eingabeschemas für Posten." #: rc.cpp:601 rc.cpp:1472 rc.cpp:2361 rc.cpp:3268 rc.cpp:4130 rc.cpp:5034 #, kde-format msgid "The name of the last used input file for items." msgstr "Der Name der letzten Eingabedatei für Posten." #: rc.cpp:604 rc.cpp:1475 rc.cpp:2364 rc.cpp:3271 rc.cpp:4133 rc.cpp:5037 #, kde-format msgid "" "User name as reference to the KAddressbook to identify 'my' address " "(DEPRECATED)." msgstr "" "Benutzername als Verknüpfung zu KAddressbook, um „Meine Adresse“ festzulegen" " (veraltet)." #: rc.cpp:607 rc.cpp:1478 rc.cpp:2367 rc.cpp:3274 rc.cpp:4136 rc.cpp:5040 #, kde-format msgid "" "UID of the user as reference to the KAddressbook to identify 'my' address." msgstr "" "Kennung des Benutzers als Verknüpfung zu KAddressbook, um „Meine Adresse“ " "festzulegen." #: rc.cpp:610 rc.cpp:1481 rc.cpp:2370 rc.cpp:3286 rc.cpp:4148 rc.cpp:5052 #, kde-format msgid "The doc id template" msgstr "Dokumentennummer-Vorlage" #: rc.cpp:613 rc.cpp:1484 rc.cpp:2373 rc.cpp:3289 rc.cpp:4151 rc.cpp:5055 #, kde-format msgid "Localization on document level" msgstr "Lokalisierung auf Dokumentebene" #: rc.cpp:616 rc.cpp:1487 rc.cpp:2376 rc.cpp:3292 rc.cpp:4154 rc.cpp:5058 #, kde-format msgid "The tax default for new documents." msgstr "Der standardmäßige Steuersatz für neue Dokumente." #: rc.cpp:619 rc.cpp:1490 rc.cpp:2379 rc.cpp:3295 rc.cpp:4157 rc.cpp:5061 #, kde-format msgid "The label for alternative positions" msgstr "Bezeichnung für Alternativposten" #: rc.cpp:622 rc.cpp:625 rc.cpp:1493 rc.cpp:1496 rc.cpp:2382 rc.cpp:2385 #: rc.cpp:3298 rc.cpp:3301 rc.cpp:4160 rc.cpp:4163 rc.cpp:5064 rc.cpp:5067 #, kde-format msgid "The label for demand positions" msgstr "Bezeichnung für Bedarfsposten" #: rc.cpp:631 rc.cpp:1325 rc.cpp:2193 rc.cpp:3088 rc.cpp:4169 rc.cpp:5076 #, kde-format msgid "Settings" msgstr "Einstellungen" #: rc.cpp:637 rc.cpp:1669 rc.cpp:2561 rc.cpp:3465 rc.cpp:4175 rc.cpp:5082 #, kde-format msgid "Edit Material" msgstr "Material bearbeiten" #: rc.cpp:640 rc.cpp:1672 rc.cpp:2564 rc.cpp:3468 rc.cpp:4178 rc.cpp:5085 #, kde-format msgid "Store in C&hapter" msgstr "In &Kategorie speichern" #: rc.cpp:646 rc.cpp:1678 rc.cpp:2570 rc.cpp:3474 rc.cpp:4184 rc.cpp:5091 #, kde-format msgid "Pac&kaged:" msgstr "Ge&binde:" #: rc.cpp:649 rc.cpp:1681 rc.cpp:2573 rc.cpp:3477 rc.cpp:4187 rc.cpp:5094 #, kde-format msgid "per P&ackage" msgstr "pro Ge&binde" #: rc.cpp:652 rc.cpp:1684 rc.cpp:2576 rc.cpp:3480 rc.cpp:4190 rc.cpp:5097 #, kde-format msgid "Prices" msgstr "Preise" #: rc.cpp:655 rc.cpp:1687 rc.cpp:2579 rc.cpp:3483 rc.cpp:4193 rc.cpp:5100 #, kde-format msgid "= Price of &Sale:" msgstr "= &Verkaufspreis:" #: rc.cpp:658 rc.cpp:1690 rc.cpp:2582 rc.cpp:3486 rc.cpp:4196 rc.cpp:5103 #, kde-format msgid "pl&us" msgstr "&zzgl." #: rc.cpp:662 rc.cpp:755 rc.cpp:1610 rc.cpp:1694 rc.cpp:2454 rc.cpp:2586 #: rc.cpp:3370 rc.cpp:3490 rc.cpp:4200 rc.cpp:4293 rc.cpp:5107 rc.cpp:5200 #, no-c-format, kde-format msgid "%" msgstr " %" #: rc.cpp:665 rc.cpp:1697 rc.cpp:2589 rc.cpp:3493 rc.cpp:4203 rc.cpp:5110 #, kde-format msgid "&Purchase Price:" msgstr "&Einkaufspreis:" #: rc.cpp:668 rc.cpp:1499 rc.cpp:2199 rc.cpp:3094 rc.cpp:4206 rc.cpp:5113 #, kde-format msgid "Calculation Item Material" msgstr "Materialkostenanteil" #: rc.cpp:671 rc.cpp:1502 rc.cpp:2202 rc.cpp:3097 rc.cpp:4209 rc.cpp:5116 #, kde-format msgid "

      Calculation Part 'Material'

      " msgstr "

      Kalkulationsanteil „Material“

      " #: rc.cpp:674 rc.cpp:1505 rc.cpp:2205 rc.cpp:3100 rc.cpp:4212 rc.cpp:5119 #, kde-format msgid "Add Material to the template calculation." msgstr "Material zur Kalkulation der Vorlage hinzufügen" #: rc.cpp:677 rc.cpp:1508 rc.cpp:2208 rc.cpp:3103 rc.cpp:4215 rc.cpp:5122 #, kde-format msgid "material" msgstr "Material" #: rc.cpp:686 rc.cpp:1517 rc.cpp:2217 rc.cpp:3112 rc.cpp:4224 rc.cpp:5131 #, kde-format msgid "unit" msgstr "Einheit" #: rc.cpp:689 rc.cpp:1544 rc.cpp:2388 rc.cpp:3304 rc.cpp:4227 rc.cpp:5134 #, kde-format msgid "" "Please enter the MySQL Database server settings. \n" "\n" "For detailed setup instructions for the MySQL to use with Kraft please check the Kraft website." msgstr "" "Bitte bestätigen Sie die Einstellungen der MySQL-Datenbank. \n" "\n" "Für ausführliche Setup Anweisungen, um MySQL mit Kraft zu nutzen besuchen Sie bitte die Kraft Homepage. " #: rc.cpp:694 rc.cpp:1549 rc.cpp:2393 rc.cpp:3309 rc.cpp:4232 rc.cpp:5139 #, kde-format msgid "Database Host:" msgstr "Datenbank-Rechner:" #: rc.cpp:697 rc.cpp:1552 rc.cpp:2396 rc.cpp:3312 rc.cpp:4235 rc.cpp:5142 #, kde-format msgid "Database Name:" msgstr "Datenbankname:" #: rc.cpp:703 rc.cpp:1558 rc.cpp:2402 rc.cpp:3318 rc.cpp:4241 rc.cpp:5148 #, kde-format msgid "Password:" msgstr "Passwort:" #: rc.cpp:706 rc.cpp:1561 rc.cpp:2405 rc.cpp:3321 rc.cpp:4244 rc.cpp:5151 #, kde-format msgid "

      Edit Number Cycles

      " msgstr "

      Nummernbestimmung bearbeiten

      " #: rc.cpp:709 rc.cpp:1564 rc.cpp:2408 rc.cpp:3324 rc.cpp:4247 rc.cpp:5154 #, kde-format msgid "Number Cycle Details" msgstr "Nummernbestimmung" #: rc.cpp:712 rc.cpp:1567 rc.cpp:2411 rc.cpp:3327 rc.cpp:4250 rc.cpp:5157 #, kde-format msgid "&Number Cycle:" msgstr "&Nummernbestimmung" #: rc.cpp:715 rc.cpp:1570 rc.cpp:2414 rc.cpp:3330 rc.cpp:4253 rc.cpp:5160 #, kde-format msgid "&Counter:" msgstr "&Anfangswert:" #: rc.cpp:721 rc.cpp:1576 rc.cpp:2420 rc.cpp:3336 rc.cpp:4259 rc.cpp:5166 #, kde-format msgid "ident &Template:" msgstr "Identifizierungs&vorlage:" #: rc.cpp:727 rc.cpp:1582 rc.cpp:2426 rc.cpp:3342 rc.cpp:4265 rc.cpp:5172 #, kde-format msgid "&Select a number cycle and edit the details on the right:" msgstr "" "&Wählen Sie eine Nummernbestimmung aus der Liste und bearbeiten Sie diese " "auf der rechten Seite:" #: rc.cpp:730 rc.cpp:1585 rc.cpp:2429 rc.cpp:3345 rc.cpp:4268 rc.cpp:5175 #, kde-format msgid "New Item" msgstr "Neuer Posten" #: rc.cpp:736 rc.cpp:1591 rc.cpp:2435 rc.cpp:3351 rc.cpp:4274 rc.cpp:5181 #, kde-format msgid "add" msgstr "Hinzufügen" #: rc.cpp:742 rc.cpp:1597 rc.cpp:2441 rc.cpp:3357 rc.cpp:4280 rc.cpp:5187 #, kde-format msgid "remove" msgstr "Entfernen" #: rc.cpp:745 rc.cpp:1600 rc.cpp:2444 rc.cpp:3360 rc.cpp:4283 rc.cpp:5190 #, kde-format msgid "1." msgstr "1." #: rc.cpp:748 rc.cpp:751 rc.cpp:1603 rc.cpp:1606 rc.cpp:2447 rc.cpp:2450 #: rc.cpp:3363 rc.cpp:3366 rc.cpp:4286 rc.cpp:4289 rc.cpp:5193 rc.cpp:5196 #, kde-format msgid "D" msgstr "D" #: rc.cpp:758 rc.cpp:1613 rc.cpp:2457 rc.cpp:3373 rc.cpp:4296 rc.cpp:5203 #, kde-format msgid "of the sum of" msgstr "der Summe von" #: rc.cpp:761 rc.cpp:1616 rc.cpp:2460 rc.cpp:3376 rc.cpp:4299 rc.cpp:5206 #, kde-format msgid "" "Please enter the SQLite Database Settings.\n" "\n" "Pick a filename to name the SQLite database file or leave the default setting." msgstr "" "Bitte bestätigen Sie die SQLite-Datenbank-Einstellungen.\n" "\n" "Wählen Sie einen Dateinamen, um die SQLite-Datenbank-Datei zu benennen, oder übernehmen Sie die Voreinstellung. " #: rc.cpp:766 rc.cpp:1621 rc.cpp:2465 rc.cpp:3381 rc.cpp:4304 rc.cpp:5211 #, kde-format msgid "store the database file at default place." msgstr "Speichern der Datenbank-Datei am voreingestellten Ort." #: rc.cpp:769 rc.cpp:1624 rc.cpp:2468 rc.cpp:3384 rc.cpp:4307 rc.cpp:5214 #, kde-format msgid "select a file name:" msgstr "Dateinamen auswählen:" #: rc.cpp:772 rc.cpp:1627 rc.cpp:2480 rc.cpp:3396 rc.cpp:4310 rc.cpp:5217 #, kde-format msgid "

      Add a Tax Rate

      " msgstr "

      Steuersatz hinzufügen

      " #: rc.cpp:775 rc.cpp:1630 rc.cpp:2483 rc.cpp:3399 rc.cpp:4313 rc.cpp:5220 #, kde-format msgid "Start-Date:" msgstr "Anfangsdatum:" #: rc.cpp:778 rc.cpp:1633 rc.cpp:2486 rc.cpp:3402 rc.cpp:4316 rc.cpp:5223 #, kde-format msgid "&Reduced Tax Rate:" msgstr "&Reduzierter Steuersatz:" #: rc.cpp:781 rc.cpp:1636 rc.cpp:2489 rc.cpp:3405 rc.cpp:4319 rc.cpp:5226 #, kde-format msgid "&Full Tax Rate:" msgstr "&Allgemeiner Steuersatz:" #: rc.cpp:784 rc.cpp:1639 rc.cpp:2492 rc.cpp:3408 rc.cpp:4322 rc.cpp:5229 #, kde-format msgid "Edit Document Text Template" msgstr "Dokumenten-Textvorlage bearbeiten" #: rc.cpp:787 rc.cpp:1642 rc.cpp:2495 rc.cpp:3411 rc.cpp:4325 rc.cpp:5232 #, kde-format msgid "&Name:" msgstr "&Name:" #: rc.cpp:790 rc.cpp:1645 rc.cpp:2498 rc.cpp:3414 rc.cpp:4328 rc.cpp:5235 #, kde-format msgid "displayed as" msgstr "angezeigt als" #: rc.cpp:793 rc.cpp:1648 rc.cpp:2501 rc.cpp:3417 rc.cpp:4331 rc.cpp:5238 #, kde-format msgid "in doc type" msgstr "im Dokumenttyp" #: rc.cpp:796 rc.cpp:1651 rc.cpp:2504 rc.cpp:3420 rc.cpp:4334 rc.cpp:5241 #, kde-format msgid "&Text:" msgstr "&Text:" #: rc.cpp:799 rc.cpp:1520 rc.cpp:2519 rc.cpp:3423 rc.cpp:4337 rc.cpp:5244 #, kde-format msgid "Calculation Item Time" msgstr "Zeitkostenanteil" #: rc.cpp:802 rc.cpp:1523 rc.cpp:2522 rc.cpp:3426 rc.cpp:4340 rc.cpp:5247 #, kde-format msgid "

      Calculation Part 'Time'

      " msgstr "

      Arbeitszeitverrechnung

      " #: rc.cpp:805 rc.cpp:1526 rc.cpp:2525 rc.cpp:3429 rc.cpp:4343 rc.cpp:5250 #, kde-format msgid "" "Calculate time efforts here for one unit of the template.
      Note that the" " costs may depend on a global hourly rate." msgstr "" "Hier den zeitlichen Aufwand für eine Einheit der Vorlage berechnen. " "
      Beachten Sie dabei, dass die Kosten auf einem globalen Stundensatz " "beruhen können." #: rc.cpp:811 rc.cpp:1532 rc.cpp:2531 rc.cpp:3435 rc.cpp:4349 rc.cpp:5256 #, kde-format msgid "Work" msgstr "Arbeitsaufwand" #: rc.cpp:814 rc.cpp:1535 rc.cpp:2534 rc.cpp:3438 rc.cpp:4352 rc.cpp:5259 #, kde-format msgid "&Time Effort:" msgstr "&Zeitaufwand:" #: rc.cpp:817 rc.cpp:1538 rc.cpp:2537 rc.cpp:3441 rc.cpp:4355 rc.cpp:5262 #, kde-format msgid "&Hourly Rate:" msgstr "&Stundensatz:" #: rc.cpp:820 rc.cpp:1541 rc.cpp:2540 rc.cpp:3444 rc.cpp:4358 rc.cpp:5265 #, kde-format msgid "Apply the &global hourly rate" msgstr "Globalen Stundensatz anwenden" #: rc.cpp:823 rc.cpp:1654 rc.cpp:2543 rc.cpp:3447 rc.cpp:4361 rc.cpp:5268 #, kde-format msgid "

      Add a unit

      " msgstr "

      Einheit hinzufügen

      " #: rc.cpp:826 rc.cpp:1657 rc.cpp:2546 rc.cpp:3450 rc.cpp:4364 rc.cpp:5271 #, kde-format msgid "Unit short" msgstr "Einheit (kurz)" #: rc.cpp:829 rc.cpp:1660 rc.cpp:2549 rc.cpp:3453 rc.cpp:4367 rc.cpp:5274 #, kde-format msgid "Unit long" msgstr "Einheit (ausführlich)" #: rc.cpp:832 rc.cpp:1663 rc.cpp:2552 rc.cpp:3456 rc.cpp:4370 rc.cpp:5277 #, kde-format msgid "Unit plural short" msgstr "Einheiten-Mehrzahl (kurz)" #: rc.cpp:835 rc.cpp:1666 rc.cpp:2555 rc.cpp:3459 rc.cpp:4373 rc.cpp:5280 #, kde-format msgid "Unit plural long" msgstr "Einheiten-Mehrzahl (ausführlich)" #: rc.cpp:838 rc.cpp:1700 rc.cpp:2592 rc.cpp:3496 rc.cpp:4379 rc.cpp:5286 #, kde-format msgid "" "This step checks if the database schema version is sufficient for this version of Kraft. \n" "\n" "In case it is not, the schema is updated automatically.\n" msgstr "" "Dieser Schritt überprüft, ob die Datenbankschema-Version für diese Version von Kraft ausreicht.\n" "\n" "Wenn sie nicht ausreicht, wird das Schema automatisch aktualisiert.\n" #: rc.cpp:853 rc.cpp:1715 rc.cpp:2607 rc.cpp:3511 rc.cpp:4394 rc.cpp:5301 #, kde-format msgid "Upgrade not yet started" msgstr "Die Aktualisierung wurde noch nicht eingeleitet." #: rc.cpp:856 rc.cpp:1718 rc.cpp:2471 rc.cpp:3387 rc.cpp:4397 rc.cpp:5304 #, kde-format msgid "

      Add a Wage group

      " msgstr "

      Lohngruppe hinzufügen

      " #: rc.cpp:859 rc.cpp:1721 rc.cpp:2474 rc.cpp:3390 rc.cpp:4400 rc.cpp:5307 #, kde-format msgid "Group name" msgstr "Gruppenname" #: rc.cpp:862 rc.cpp:1724 rc.cpp:2477 rc.cpp:3393 rc.cpp:4403 rc.cpp:5310 #, kde-format msgid "Wage" msgstr "Arbeitslohn" #: rc.cpp:2109 rc.cpp:2118 rc.cpp:2995 rc.cpp:3019 rc.cpp:3025 rc.cpp:3565 #: rc.cpp:3589 rc.cpp:3595 rc.cpp:4469 rc.cpp:4493 rc.cpp:4499 #, kde-format msgid "select" msgstr "auswählen" #: rc.cpp:2112 rc.cpp:3016 rc.cpp:3586 rc.cpp:4490 #, kde-format msgid "&Watermark File:" msgstr "&Wasserzeichen Datei:" #: rc.cpp:2130 rc.cpp:2992 rc.cpp:3562 rc.cpp:4466 #, kde-format msgid "&Template File:" msgstr "Vorlagen Da&tei:" #: rc.cpp:2507 rc.cpp:3145 rc.cpp:4406 rc.cpp:5313 #, kde-format msgid "Dialog" msgstr "Dialog" #: rc.cpp:2510 rc.cpp:3148 rc.cpp:4409 rc.cpp:5316 #, kde-format msgid "" "

      XRechnung Additional Data

      " msgstr "" "

      XRechnung: Zusätzliche Daten

      " #: rc.cpp:2513 rc.cpp:3151 rc.cpp:4412 rc.cpp:5319 #, kde-format msgid "Due Date:" msgstr "Zahlungsziel-Datum:" #: rc.cpp:2516 rc.cpp:3154 rc.cpp:4415 rc.cpp:5322 #, kde-format msgid "Buyer Reference:" msgstr "Käufer-Referenz:" #: rc.cpp:2558 rc.cpp:3462 rc.cpp:4376 rc.cpp:5283 #, kde-format msgid "Unit ECE20" msgstr "Einheit ECE20" #: rc.cpp:2989 rc.cpp:3559 rc.cpp:4463 #, kde-format msgid "PDF Creation and Postprocessing" msgstr "PDF Generieren und Nachbearbeiten" #: rc.cpp:3010 rc.cpp:3580 rc.cpp:4484 #, kde-format msgid "alternating (3 pages)" msgstr "abwechselnd (3 Seiten)" #: rc.cpp:3013 rc.cpp:3583 rc.cpp:4487 #, kde-format msgid "different first and last page (3 pages)" msgstr "unterschiedliche erste und letzte Seite (3 Seiten)" #: rc.cpp:3022 rc.cpp:3592 rc.cpp:4496 #, kde-format msgid "Append PDF:" msgstr "PDF anhängen:" #: rc.cpp:3277 rc.cpp:4139 rc.cpp:5043 #, kde-format msgid "Bank account name." msgstr "Bankkonto Inhaber" #: rc.cpp:3280 rc.cpp:4142 rc.cpp:5046 #, kde-format msgid "Business Identifier Code\" (BIC) of the bank." msgstr "BIC der Bank." #: rc.cpp:3283 rc.cpp:4145 rc.cpp:5049 #, kde-format msgid "IBAN of the bank account." msgstr "IBAN des Bankkontos." #: rc.cpp:5070 #, kde-format msgid "Display the EPC Code as long as the doc sum is below this value." msgstr "" "Anzeige des EPC Code solang die Netto Summe kleiner ist als dieser Wert." #: setupassistant.cpp:36 #, kde-format msgid "Welcome to the Kraft Setup Assistant" msgstr "Willkommen beim Einrichtungsassistenten von Kraft" #: setupassistant.cpp:55 #, kde-format msgid "Select the Database Backend" msgstr "Bitte wählen Sie das Datenbank-Modul" #: setupassistant.cpp:92 #, kde-format msgid "Sqlite File Name" msgstr "Dateiname der Sqlite-Datenbank" #: setupassistant.cpp:146 #, kde-format msgid "MySql Detail Information" msgstr "MySQL Datenbank-Informationen" #: setupassistant.cpp:188 #, kde-format msgid "Create Database" msgstr "Datenbank neu erzeugen" #: setupassistant.cpp:210 setupassistant.cpp:223 #, kde-format msgid "0/%1" msgstr "0 / %1" #: setupassistant.cpp:242 setupassistant.cpp:252 setupassistant.cpp:290 #, kde-format msgid "%1/%2" msgstr "%1 / %2" #: setupassistant.cpp:265 #, kde-format msgid "Upgrade the Database" msgstr "Datenbankschema aktualisieren" #: setupassistant.cpp:314 #, kde-format msgid "Your Company Address" msgstr "Adresse der Firma" #: setupassistant.cpp:319 #, kde-format msgid "" "Select your companies address either from the address book or enter it " "manually. It is set as a consigner on the documents." msgstr "" "Wählen Sie die Adresse Ihrer Firma aus dem Adressbuch oder tragen Sie sie " "manuell ein. Sie wird als Absender der Dokumente verwendet." #: setupassistant.cpp:328 #, kde-format msgid "Select from Addressbook" msgstr "Aus dem Adressbuch" #: setupassistant.cpp:418 #, kde-format msgid "Final Status" msgstr "Endergebnis" #: setupassistant.cpp:512 #, kde-format msgid "" "

      Can't connect to your database. Are you sure your credentials are correct" " and the database exists?

      " msgstr "" "

      Die Verbindung zur Datenbank kann nicht hergestellt werden. Bitte stellen" " Sie sicher, dass die Einstellungen richtig sind und die Datenbank vorhanden" " ist.

      " #: setupassistant.cpp:523 #, kde-format msgid "

      Can't open your database file, check the permissions and such." msgstr "" "

      Die Datenbank-Datei kann nicht geöffnet werden. Bitte überprüfen Sie die " "Berechtigungen.

      " #: setupassistant.cpp:532 #, kde-format msgid "" "

      The database is already existing, no action needs to be taken " "here.

      Please hit next to proceed.

      " msgstr "" "

      Die Datenbank ist bereits angelegt, sodass hier keine weiteren Aktionen " "durchzuführen sind.

      Bitte drücken Sie auf Weiter, um " "fortzufahren.

      " #: setupassistant.cpp:581 #, kde-format msgid "

      The database setup was successfully completed.

      " msgstr "

      Die Datenbankeinrichtung ist erfolgreich abgeschlossen.

      " #: setupassistant.cpp:582 #, kde-format msgid "

      You can start to work with Kraft now. Please do not forget to

      " msgstr "" "

      Sie können nun Ihre Arbeit mit Kraft beginnen. Bitte vergessen Sie " "nicht:

      " #: setupassistant.cpp:584 #, kde-format msgid "
    • adjust various settings in the Kraft Preferences dialog.
    • " msgstr "" "
    • Verschiedene Einstellungen im Einstellungen-Fenster von Kraft " "anzupassen.
    • " #: setupassistant.cpp:585 #, kde-format msgid "
    • Check the Catalog chapter list.
    • " msgstr "
    • Überprüfen Sie die Kapitelliste des Katalogs.
    • " #: setupassistant.cpp:586 #, kde-format msgid "
    • Make your business and have fun.
    • " msgstr "
    • Führen Sie Ihre Geschäfte und haben Sie Spaß.
    • " #: setupassistant.cpp:588 #, kde-format msgid "" "

      If you press Finish now, the new database configuration is stored " "in Krafts configuration.

      " msgstr "" "

      Falls Sie nun auf Fertigstellen klicken, wird die neue Datenbank-" "Einrichtung in der Kraft-Konfiguration gespeichert.

      " #: setupassistant.cpp:604 #, kde-format msgid "" "The Database can not be connected. Please check the database credentials." msgstr "" "Die Verbindung zur Datenbank kann nicht hergestellt werden. Bitte stellen " "Sie sicher, dass die Einstellungen richtig sind." #: setupassistant.cpp:610 #, kde-format msgid "The database core tables do not exist. Please check initial setup." msgstr "" "Die grundlegenden Tabellen der Datenbank sind nicht vorhanden. Bitte " "überprüfen Sie die einleitende Einrichtung." #: setupassistant.cpp:617 #, kde-format msgid "Database is up to date. No upgrade is required." msgstr "" "Die Datenbank ist auf dem aktuellen Stand, sodass keine Aktualisierung " "notwendig ist." #: setupassistant.cpp:622 #, kde-format msgid "Parse Update Commands..." msgstr "Update-Anweisungen analysieren ..." #: setupassistant.cpp:665 #, kde-format msgid "The Upgrade failed!" msgstr "Die Aktualisierung ist fehlgeschlagen." #: setupassistant.cpp:667 #, kde-format msgid "The Upgrade succeeded, the current schema version is %1!" msgstr "" "Die Aktualisierung war erfolgreich. Die aktuelle Version des Schemas ist %1." #: setupassistant.cpp:680 #, kde-format msgid "" "The Database can not be connected. Please check the database credentials!" msgstr "" "Die Verbindung zur Datenbank kann nicht hergestellt werden. Bitte stellen " "Sie sicher, dass die Einstellungen richtig sind." #: setupassistant.cpp:686 #, kde-format msgid "Parse Create Commands..." msgstr "Create-Anweisungen analysieren ..." #: setupassistant.cpp:694 #, kde-format msgid "Parse database fillup commands..." msgstr "Datenbank-Füllbefehle analysieren ..." #: setupassistant.cpp:707 #, kde-format msgid "Processing database creation commands..." msgstr "Datenbank-Erzeugungsbefehle bearbeiten ..." #: setupassistant.cpp:724 #, kde-format msgid "Process database fillup commands..." msgstr "Datenbank-Füllbefehle bearbeiten ..." #: setupassistant.cpp:734 #, kde-format msgid "Successfully finished commands." msgstr "Die Befehle wurden erfolgreich ausgeführt." #: setupassistant.cpp:736 #, kde-format msgid "Failed to perform all commands." msgstr "Es kann kein Befehl erfolgreich ausgeführt werden." #: setupassistant.cpp:780 #, kde-format msgid "" "This assistant guides you through the basic settings of your Kraft " "installation." msgstr "" "Dieser Assistent führt Sie durch die Grundeinstellungen Ihrer Kraft-" "Installation" #: setupassistant.cpp:790 #, kde-format msgid "There was no database configuration found." msgstr "Es kann keine Datenbank-Einrichtung gefunden werden." #: setupassistant.cpp:792 #, kde-format msgid "A valid current database configuration file was found." msgstr "Eine gültige aktuelle Datenbank-Einrichtung ist gefunden worden." #: setupassistant.cpp:814 #, kde-format msgid "The database schema version is too low. It will be updated." msgstr "" "Die Version des Datenbank-Schemas ist zu niedrig. Es wird aktualisiert." #: setupassistant.cpp:817 #, kde-format msgid "The current database schema version is too high. Leaving untouched! " msgstr "" "Die Version des Datenbankschema ist zu hoch. Es wird nichts verändert." #: setupassistant.cpp:824 #, kde-format msgid "" "

      The database can be opened, but does not contain valid content.

      A " "new database can be created automatically from scratch.

      " msgstr "" "

      Die Datenbank kann geöffnet werden, enthält aber keine gültigen " "Inhalte.

      Eine neue Datenbank kann automatisch von Grund auf erzeugt " "werden.

      " #: setupassistant.cpp:831 #, kde-format msgid "

      Kraft failed to connect to the configured database.

      " msgstr "

      Kraft konnte nicht mit der konfigurierten Datenbank verbinden

      " #: setupassistant.cpp:833 #, kde-format msgid "" "

      Please check the database server setup and restart Kraft to connect." msgstr "" "

      Bitte überprüfen Sie die Einstellungen des Datenbank-Servers und starten " "Sie Kraft neu, um eine Verbindung herzustellen." #: setupassistant.cpp:835 #, kde-format msgid "

      Please check the database file." msgstr "

      Bitte überprüfen Sie die Datenbank-Datei." #: setupassistant.cpp:837 #, kde-format msgid "or create a new database by hitting next.

      " msgstr "" "Oder erstellen Sie eine neue Datenbank, indem Sie Weiter drücken.

      " #: setupassistant.cpp:845 #, kde-format msgid "

      Please hit next and follow the instructions.

      " msgstr "

      Drücken Sie Weiter und folgen Sie den Angaben.

      " #: tagtemplatesdialog.cpp:47 #, kde-format msgid "Edit Tag Template" msgstr "Stichwort-Vorlage bearbeiten" #: tagtemplatesdialog.cpp:54 #, kde-format msgid "Edit a Tag Template" msgstr "Marker-Vorlage bearbeiten" #: tagtemplatesdialog.cpp:55 #, kde-format msgid "Adjust settings for name, color and description." msgstr "Legen Sie einen Namen, eine Farbe und eine Beschreibung fest." #: tagtemplatesdialog.cpp:63 #, kde-format msgid "Description:" msgstr "Beschreibung:" #: tagtemplatesdialog.cpp:69 #, kde-format msgid "Associated Color:" msgstr "Zugehörige Farbe:" #: tagtemplatesdialog.cpp:141 #, kde-format msgid "Add, edit and remove tag templates for use in the documents." msgstr "" "Stichwort-Vorlagen hinzufügen, ändern oder entfernen, die in diesen " "Dokumenten verwendet werden." #: tagtemplatesdialog.cpp:165 #, kde-format msgid "Add..." msgstr "Hinzufügen ..." #: tagtemplatesdialog.cpp:167 #, kde-format msgid "Edit..." msgstr "Bearbeiten ..." #: tagtemplatesdialog.cpp:170 #, kde-format msgid "Delete..." msgstr "Löschen ..." #: tagtemplatesdialog.cpp:223 #, kde-format msgid "Do you really want to delete the template?" msgstr "Möchten Sie die ausgewählte Vorlage wirklich löschen?" #: taxeditdialog.cpp:36 #, kde-format msgid "Edit Tax Rates" msgstr "Steuersätze bearbeiten" #: templkatalogview.cpp:101 #, kde-format msgid "" msgstr "" #: templkataloglistview.cpp:47 #, kde-format msgid "Calc. Type" msgstr "Kalkulationsart" #: templkataloglistview.cpp:54 #, kde-format msgid "Template Catalog" msgstr "Vorlagenkatalog" #: textselection.cpp:42 #, kde-format msgid "Template Collection" msgstr "Vorlagensammlung" #: textselection.cpp:100 #, kde-format msgid "Template Actions" msgstr "Vorlagenaktionen" #: textselection.cpp:129 #, kde-format msgid "This is the standard text used in new documents." msgstr "Dies ist der Standardtext, der in neuen Dokumenten verwendet wird." #: textselection.cpp:138 #, kde-format msgid "%1 Templates for %2" msgstr "%1 Vorlagen für %2" #: textselection.cpp:146 #, kde-format msgid "" "There is no %1 template text available for document type %2.
      Click the " "add-button below to create one." msgstr "" "Es ist kein Vorlagentext %1 für den Dokumenttyp %2 vorhanden.
      Klicken " "Sie auf den Knopf „Hinzufügen“ um einen Vorlagentext zu erstellen." #: textselection.cpp:201 #, kde-format msgid "&Use in Document" msgstr "Im Dokument &verwenden" #: texteditdialog.cpp:42 #, kde-format msgid "Edit Text Templates" msgstr "Textvorlagen bearbeiten" #: texteditdialog.cpp:62 #, kde-format msgid "Edit %1 Template" msgstr "Vorlage „%1“ bearbeiten" #: texttemplate.cpp:103 #, kde-format msgid "Failed to open template source" msgstr "Die Vorlagendatei kann nicht geöffnet werden." #: texttemplateinterface.cpp:53 #, kde-format msgid "No file name given for template" msgstr "Für die Vorlage ist kein Name angegeben worden." #: texttemplateinterface.cpp:61 #, kde-format msgid "Could not find template file %1" msgstr "Die Vorlagendatei „%1“ kann nicht gefunden werden." #: timecalcpart.cpp:82 #, kde-format msgid "Minutes" msgstr "Minuten" #: timecalcpart.cpp:84 #, kde-format msgid "Hours" msgstr "Stunden" #: timecalcpart.cpp:86 #, kde-format msgid "Seconds" msgstr "Sekunden" kraft-1.1/po/kraft.pot000066400000000000000000002571011450127457600147540ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-09-10 18:34+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: models/docbasemodel.cpp:32 docdigestdetailview.cpp:413 #, kde-format msgid "Date" msgstr "" #: models/docbasemodel.cpp:33 #, kde-format msgid "Doc. Number" msgstr "" #: models/docbasemodel.cpp:34 #, kde-format msgid "Doc. Type" msgstr "" #: models/docbasemodel.cpp:35 docdigestdetailview.cpp:418 #, kde-format msgid "Whiteboard" msgstr "" #: models/docbasemodel.cpp:36 #, kde-format msgid "Client Id" msgstr "" #: models/docbasemodel.cpp:37 #, kde-format msgid "Last modified" msgstr "" #: models/docbasemodel.cpp:38 #, kde-format msgid "Creation date" msgstr "" #: models/docbasemodel.cpp:39 docdigestdetailview.cpp:423 #, kde-format msgid "Project" msgstr "" #: models/docbasemodel.cpp:40 #, kde-format msgid "Client Address" msgstr "" #: models/docbasemodel.cpp:41 #, kde-format msgid "Client" msgstr "" #: models/docbasemodel.cpp:109 #, kde-format msgid "Looking up address" msgstr "" #: models/docbasemodel.cpp:111 #, kde-format msgid "Lookup started" msgstr "" #: documentman.cpp:93 #, kde-format msgctxt "" "Text to be inserted into a doc, if the sum of another doc needs to be " "substracted ie. in a final invoice if there was a partial invoice before%1 " "is substited by the doc type, %2 by the id of the predecessor doc." msgid "Substract sum from %1 %2" msgstr "" #: katalog.cpp:137 #, kde-format msgid "not found" msgstr "" #: addeditchapterdialog.cpp:35 #, kde-format msgid "Add/Edit Catalog Chapter" msgstr "" #: addeditchapterdialog.cpp:41 #, kde-format msgid "Create a new Catalog Chapter" msgstr "" #: addeditchapterdialog.cpp:45 #, kde-format msgid "Chapter Name:" msgstr "" #: addeditchapterdialog.cpp:49 #, kde-format msgid "Chapter Description:" msgstr "" #: addeditchapterdialog.cpp:76 #, kde-format msgid "Create new Catalog Chapter below chapter %1" msgstr "" #: addeditchapterdialog.cpp:83 #, kde-format msgid "Edit name and description of chapter %1" msgstr "" #: kraftdoc.cpp:160 #, kde-format msgctxt "First argument is the doctype, like Invoice, followed by the ID" msgid "%1 (Id %2)" msgstr "" #: kraftdoc.cpp:308 #, kde-format msgctxt "Document part header" msgid "Header" msgstr "" #: kraftdoc.cpp:310 #, kde-format msgctxt "Document part footer" msgid "Footer" msgstr "" #: kraftdoc.cpp:312 #, kde-format msgctxt "Document part containing the items" msgid "Items" msgstr "" #: kraftdoc.cpp:314 #, kde-format msgid "Unknown document part" msgstr "" #: defaultprovider.cpp:63 doctext.cpp:80 positionviewwidget.cpp:418 #, kde-format msgid "Unknown" msgstr "" #: docassistant.cpp:52 #, kde-format msgid "Show &Templates" msgstr "" #: docassistant.cpp:57 #, kde-format msgid "Show mask to create or select templates to be used in the document" msgstr "" #: docassistant.cpp:121 #, kde-format msgid "Add a template to the document" msgstr "" #: docassistant.cpp:128 #, kde-format msgid "Insert the template to the document" msgstr "" #: docassistant.cpp:136 #, kde-format msgid "Create a new template" msgstr "" #: docassistant.cpp:143 #, kde-format msgid "Edit the current template" msgstr "" #: docassistant.cpp:150 #, kde-format msgid "Delete the current template" msgstr "" #: docassistant.cpp:319 #, kde-format msgid "" "Do you really want to delete the template permanently?\n" "It can not be recovered." msgstr "" #: addressselectorwidget.cpp:219 #, kde-format msgid "Name" msgstr "" #: addressselectorwidget.cpp:221 #, kde-format msgid "Address" msgstr "" #: addressselectorwidget.cpp:288 filterheader.cpp:40 #, kde-format msgid "&Search:" msgstr "" #: addressselectorwidget.cpp:325 #, kde-format msgid "Edit Contact..." msgstr "" #: addressselectorwidget.cpp:326 #, kde-format msgid "Edit the currently selected contact" msgstr "" #: addressselectorwidget.cpp:329 #, kde-format msgid "New Contact..." msgstr "" #: addressselectorwidget.cpp:330 #, kde-format msgid "Create a new Contact" msgstr "" #: docpostcard.cpp:33 #, kde-format msgid "Document Overview" msgstr "" #: docpostcard.cpp:125 #, kde-format msgid "Netto:" msgstr "" #: docpostcard.cpp:136 docpostcard.cpp:143 #, kde-format msgid "+ %1% Tax:" msgstr "" #: docpostcard.cpp:149 #, kde-format msgid "Sum Tax:" msgstr "" #: docpostcard.cpp:154 #, kde-format msgid "Total:" msgstr "" #: docpostcard.cpp:246 #, kde-format msgid "%1 Items" msgstr "" #: docpostcard.cpp:248 #, kde-format msgid "%1 Items, netto %2" msgstr "" #: archdoc.cpp:65 #, kde-format msgid "%1 for %2 (Id %3)" msgstr "" #: doctext.cpp:61 #, kde-format msgid "Standard" msgstr "" #: doctext.cpp:76 #, kde-format msgid "Header Text" msgstr "" #: doctext.cpp:77 #, kde-format msgid "Footer Text" msgstr "" #: doctext.cpp:78 #, kde-format msgid "Items" msgstr "" #: alldocsview.cpp:64 #, kde-format msgid "All documents" msgstr "" #: alldocsview.cpp:65 #, kde-format msgid "Documents of last week" msgstr "" #: alldocsview.cpp:66 #, kde-format msgid "Documents of last month" msgstr "" #: alldocsview.cpp:72 #, kde-format msgid "&Show: " msgstr "" #: alldocsview.cpp:79 #, kde-format msgid "&Search: " msgstr "" #: alldocsview.cpp:134 portal.cpp:305 portal.cpp:306 rc.cpp:634 rc.cpp:1328 #: rc.cpp:2196 rc.cpp:3091 rc.cpp:4172 rc.cpp:5079 #, kde-format msgid "Document Actions" msgstr "" #: documenttemplate.cpp:113 #, kde-format msgctxt "Sequence number printed on the document" msgid "No." msgstr "" #: documenttemplate.cpp:114 #, kde-format msgctxt "Document item printed on the document" msgid "Item" msgstr "" #: documenttemplate.cpp:115 #, kde-format msgctxt "Abbrev. of Quantity printed on the document" msgid "Qty." msgstr "" #: documenttemplate.cpp:116 #, kde-format msgctxt "Unit printed on the document" msgid "Unit" msgstr "" #: documenttemplate.cpp:117 #, kde-format msgctxt "Price of an item printed on the document" msgid "Price" msgstr "" #: documenttemplate.cpp:118 #, kde-format msgctxt "Printed on the document" msgid "Sum" msgstr "" #: documenttemplate.cpp:119 #, kde-format msgctxt "printed on the document" msgid "Net" msgstr "" #: documenttemplate.cpp:120 #, kde-format msgctxt "Printed on the document" msgid "VAT" msgstr "" #: documenttemplate.cpp:121 #, kde-format msgctxt "Document type, printed on the document" msgid "Type" msgstr "" #: documenttemplate.cpp:123 #, kde-format msgctxt "Printed on the document" msgid "Phone" msgstr "" #: documenttemplate.cpp:124 #, kde-format msgctxt "Printed on the document" msgid "FAX" msgstr "" #: documenttemplate.cpp:125 #, kde-format msgctxt "Printed on the document" msgid "Mobile" msgstr "" #: documenttemplate.cpp:126 #, kde-format msgctxt "Printed on the document" msgid "Email" msgstr "" #: documenttemplate.cpp:127 #, kde-format msgctxt "Printed on the document" msgid "Website" msgstr "" #: documenttemplate.cpp:129 #, kde-format msgctxt "Printed on the document" msgid "Page" msgstr "" #: documenttemplate.cpp:130 #, kde-format msgctxt "Label of Predecessor document number" msgid "Predecessor-Doc" msgstr "" #: documenttemplate.cpp:131 #, kde-format msgctxt "the 'of' in page X of Y" msgid "of" msgstr "" #: documenttemplate.cpp:132 #, kde-format msgctxt "Document number on document" msgid "Document No." msgstr "" #: documenttemplate.cpp:133 #, kde-format msgctxt "Date on document" msgid "Date" msgstr "" #: documenttemplate.cpp:134 #, kde-format msgctxt "Project label" msgid "Project" msgstr "" #: documenttemplate.cpp:135 #, kde-format msgctxt "Customer ID on document" msgid "Customer Id" msgstr "" #: documenttemplate.cpp:200 #, kde-format msgctxt "" "Credit Transfer reason string, 1=DocType, 2=DocIdent, 3=Date, ie. Invoice " "2022-183 dated 2022-03-22" msgid "%1 %2 dated %3" msgstr "" #: documenttemplate.cpp:321 #, kde-format msgid "" "Please note: This offer contains %1 alternative or demand positions, printed " "in italic font. These do not add to the overall sum." msgstr "" #: documenttemplate.cpp:332 #, kde-format msgid "tax free items (%1 pcs.)" msgstr "" #: documenttemplate.cpp:338 #, kde-format msgid "items with reduced tax of %1% (%2 pcs.)" msgstr "" #: documenttemplate.cpp:347 #, kde-format msgid "No label: items with full tax of %1% (%2 pcs.)" msgstr "" #: documenttemplate.cpp:377 kraftview_ro.cpp:225 #, kde-format msgid "reduced VAT" msgstr "" #: documenttemplate.cpp:385 kraftview_ro.cpp:197 kraftview_ro.cpp:234 rc.cpp:21 #: rc.cpp:931 rc.cpp:1769 rc.cpp:2652 rc.cpp:3703 rc.cpp:4607 #, kde-format msgid "VAT" msgstr "" #: documenttemplate.cpp:439 #, kde-format msgid "Template to convert is not existing!" msgstr "" #: documenttemplate.cpp:442 #, kde-format msgid "Can not read template file!" msgstr "" #: flostempldialog.cpp:71 #, kde-format msgid "Create or Edit Template Items" msgstr "" #: flostempldialog.cpp:213 flostempldialog.cpp:604 #, kde-format msgid "No" msgstr "" #: flostempldialog.cpp:214 flostempldialog.cpp:604 #, kde-format msgid "Yes" msgstr "" #: flostempldialog.cpp:251 #, kde-format msgid "Calculated Price: " msgstr "" #: flostempldialog.cpp:255 #, kde-format msgid "Manual Price: " msgstr "" #: flostempldialog.cpp:260 #, kde-format msgid "(+%1%)" msgstr "" #: flostempldialog.cpp:264 #, kde-format msgid "%1%" msgstr "" #: flostempldialog.cpp:266 #, kde-format msgid ": " msgstr "" #: flostempldialog.cpp:388 #, kde-format msgid "Template Error" msgstr "" #: flostempldialog.cpp:388 #, kde-format msgid "Saving of this template failed, sorry" msgstr "" #: flostempldialog.cpp:416 #, kde-format msgid "The template has been modified." msgstr "" #: flostempldialog.cpp:417 #, kde-format msgid "Do you want to discard your changes?" msgstr "" #: flostempldialog.cpp:446 #, kde-format msgid "" "The catalog chapter was changed for this template.\n" "Do you really want to move the template to the new chapter?" msgstr "" #: flostempldialog.cpp:448 #, kde-format msgid "Chapter Change" msgstr "" #: flostempldialog.h:104 #, kde-format msgid "Calculated material" msgstr "" #: calcpart.cpp:98 #, kde-format msgid "Base" msgstr "" #: catalogselection.cpp:50 #, kde-format msgid "Selected &Catalog: " msgstr "" #: catalogselection.cpp:159 #, kde-format msgid "Append to Document" msgstr "" #: fixcalcdialog.cpp:36 #, kde-format msgid "Calculation Fix Item" msgstr "" #: catalogtemplate.cpp:52 #, kde-format msgid "Manual Price" msgstr "" #: catalogtemplate.cpp:54 #, kde-format msgid "Calculated" msgstr "" #: catalogtemplate.cpp:56 #, kde-format msgid "AutoCalc" msgstr "" #: catalogtemplate.cpp:57 #, kde-format msgid "Err: Unknown type %d" msgstr "" #: main.cpp:58 #, kde-format msgid "Open document with arch doc number " msgstr "" #: main.cpp:59 #, kde-format msgid "Open Kraft in read only mode - document changes prohibited" msgstr "" #: templtopositiondialogbase.cpp:35 rc.cpp:460 rc.cpp:1331 rc.cpp:2220 #: rc.cpp:3115 rc.cpp:3989 rc.cpp:4893 #, kde-format msgid "Create Item from Template" msgstr "" #: templtopositiondialogbase.cpp:51 #, kde-format msgid "the Header of the Document as first item" msgstr "" #: templtopositiondialogbase.cpp:58 importitemdialog.cpp:125 #, kde-format msgid "..." msgstr "" #: portal.cpp:105 #, kde-format msgid "&Quit" msgstr "" #: portal.cpp:110 #, kde-format msgid "&Cut" msgstr "" #: portal.cpp:115 #, kde-format msgid "C&opy" msgstr "" #: portal.cpp:120 #, kde-format msgid "&Paste" msgstr "" #: portal.cpp:125 #, kde-format msgid "&Settings" msgstr "" #: portal.cpp:130 #, kde-format msgid "&Create Document" msgstr "" #: portal.cpp:135 #, kde-format msgid "&Copy Document" msgstr "" #: portal.cpp:140 #, kde-format msgid "Create &Followup Document" msgstr "" #: portal.cpp:145 #, kde-format msgid "Print Document" msgstr "" #: portal.cpp:150 #, kde-format msgid "Show Document" msgstr "" #: portal.cpp:155 #, kde-format msgid "Edit Document" msgstr "" #: portal.cpp:160 #, kde-format msgid "Open Archived Document" msgstr "" #: portal.cpp:165 #, kde-format msgid "Mail Document" msgstr "" #: portal.cpp:170 #, kde-format msgid "Export XRechnung" msgstr "" #: portal.cpp:175 tagtemplatesdialog.cpp:135 tagtemplatesdialog.cpp:140 #, kde-format msgid "Edit Tag Templates" msgstr "" #: portal.cpp:180 #, kde-format msgid "Redo Initial Setup..." msgstr "" #: portal.cpp:185 #, kde-format msgid "Kraft Handbook..." msgstr "" #: portal.cpp:190 #, kde-format msgid "About Qt..." msgstr "" #: portal.cpp:195 #, kde-format msgid "About Kraft..." msgstr "" #: portal.cpp:199 #, kde-format msgid "Quits the application" msgstr "" #: portal.cpp:201 #, kde-format msgid "Cuts the selected section and puts it to the clipboard" msgstr "" #: portal.cpp:202 #, kde-format msgid "Copies the selected section to the clipboard" msgstr "" #: portal.cpp:203 #, kde-format msgid "Pastes the clipboard contents to current position" msgstr "" #: portal.cpp:205 #, kde-format msgid "Creates a new Document" msgstr "" #: portal.cpp:206 #, kde-format msgid "Print and archive this Document" msgstr "" #: portal.cpp:207 #, kde-format msgid "Creates a new document which is a copy of the selected document" msgstr "" #: portal.cpp:208 #, kde-format msgid "Create a followup document for the current document" msgstr "" #: portal.cpp:209 #, kde-format msgid "Opens the document for editing" msgstr "" #: portal.cpp:210 #, kde-format msgid "Opens a read only view on the document." msgstr "" #: portal.cpp:211 #, kde-format msgid "Send document per mail" msgstr "" #: portal.cpp:212 #, kde-format msgid "Export invoice in XRechnung XML format." msgstr "" #: portal.cpp:213 #, kde-format msgid "" "Edit the available tag templates which can be assigned to document items." msgstr "" #: portal.cpp:214 #, kde-format msgid "Configure the Database Kraft is working on." msgstr "" #: portal.cpp:215 #, kde-format msgid "Open a viewer on an archived document" msgstr "" #: portal.cpp:229 rc.cpp:484 rc.cpp:1355 rc.cpp:2244 rc.cpp:3139 rc.cpp:4013 #: rc.cpp:4917 #, kde-format msgid "&File" msgstr "" #: portal.cpp:233 #, kde-format msgid "&Edit" msgstr "" #: portal.cpp:238 rc.cpp:628 rc.cpp:1322 rc.cpp:2190 rc.cpp:3085 rc.cpp:4166 #: rc.cpp:5073 #, kde-format msgid "&Document" msgstr "" #: portal.cpp:253 #, kde-format msgid "Kraft" msgstr "" #: portal.cpp:256 #, kde-format msgid "&Preferences" msgstr "" #: portal.cpp:260 #, kde-format msgid "Toolbars" msgstr "" #: portal.cpp:266 #, kde-format msgid "&Help" msgstr "" #: portal.cpp:354 #, kde-format msgid "Database not running" msgstr "" #: portal.cpp:355 #, kde-format msgid "" "Kraft was started in readonly mode, but the configured database can not be " "connected.\n" "\n" "Kraft will abort." msgstr "" #: portal.cpp:371 #, kde-format msgid "" "Kraft can not connect to the specified MySQL server. Please check the Kraft " "database settings, check if the server is running and verify if a database " "with the name %1 exits!" msgstr "" #: portal.cpp:375 #, kde-format msgid "" "The database with the name %1 does not exist on the database server. Please " "make sure the database exists and is accessible by the user running Kraft." msgstr "" #: portal.cpp:379 #, kde-format msgid "" "The Qt database driver could not be loaded. That probably means, that they " "are not installed. Please make sure the Qt database packages are installed " "and try again." msgstr "" #: portal.cpp:383 #, kde-format msgid "There is a database problem: %1" msgstr "" #: portal.cpp:401 #, kde-format msgid "Database Problem." msgstr "" #: portal.cpp:413 #, kde-format msgid "Check commandline actions" msgstr "" #: portal.cpp:503 #, kde-format msgid "Welcome to Kraft, %1" msgstr "" #: portal.cpp:532 #, kde-format msgid "Creating new document..." msgstr "" #: portal.cpp:558 #, kde-format msgctxt "" "Dialog title of the followup doc dialog, followed by the id of the source " "doc" msgid "Create follow up document for %1" msgstr "" #: portal.cpp:603 #, kde-format msgctxt "Title of the new doc dialog, %1 is the source doc id" msgid "Create new Document as Copy of %1" msgstr "" #: portal.cpp:638 #, kde-format msgid "Opening document to view..." msgstr "" #: portal.cpp:665 #, kde-format msgid "XRechnung Template file not set. Please check the application settings!" msgstr "" #: portal.cpp:669 #, kde-format msgid "The XRechnung template file can not be read!" msgstr "" #: portal.cpp:674 #, kde-format msgid "XRechnung Export" msgstr "" #: portal.cpp:694 #, kde-format msgid "Save XRechnung" msgstr "" #: portal.cpp:696 #, kde-format msgid "Saved XRechnung to %1" msgstr "" #: portal.cpp:730 #, kde-format msgid "Generating PDF..." msgstr "" #: portal.cpp:744 portal.cpp:767 portal.cpp:1093 katalogview.cpp:236 #: katalogview.cpp:302 katalogview.cpp:316 katalogview.cpp:325 #: katalogview.cpp:334 #, kde-format msgid "Ready." msgstr "" #: portal.cpp:753 #, kde-format msgid "Generating PDF for EMail" msgstr "" #: portal.cpp:772 #, kde-format msgid "Doc Generation Error" msgstr "" #: portal.cpp:828 #, kde-format msgid "Printing archived document..." msgstr "" #: portal.cpp:880 #, kde-format msgid "Opening document %1" msgstr "" #: portal.cpp:1037 katalogview.cpp:241 #, kde-format msgid "Exiting..." msgstr "" #: portal.cpp:1064 #, kde-format msgid "Cutting selection..." msgstr "" #: portal.cpp:1071 #, kde-format msgid "Copying selection to clipboard..." msgstr "" #: portal.cpp:1078 #, kde-format msgid "Inserting clipboard contents..." msgstr "" #: portal.cpp:1091 #, kde-format msgid "" "Ready. Kraft is running in read only mode. Document editing is prohibited." msgstr "" #: doctypeedit.cpp:49 #, kde-format msgid "" msgstr "" #: doctypeedit.cpp:50 #, kde-format msgid "
      " msgstr "" #: doctypeedit.cpp:85 #, kde-format msgid "Select template file from harddisk" msgstr "" #: doctypeedit.cpp:86 #, kde-format msgid "Select watermark file from harddisk" msgstr "" #: doctypeedit.cpp:87 #, kde-format msgid "Select PDF file to append to documents from harddisk" msgstr "" #: doctypeedit.cpp:91 prefsdialog.cpp:409 #, kde-format msgid "Find Template File" msgstr "" #: doctypeedit.cpp:92 #, kde-format msgid "Kraft Templates (*.trml *.gtmpl)" msgstr "" #: doctypeedit.cpp:100 #, kde-format msgid "Find Watermark File" msgstr "" #: doctypeedit.cpp:101 doctypeedit.cpp:111 #, kde-format msgid "PDF file (*.pdf)" msgstr "" #: doctypeedit.cpp:110 #, kde-format msgid "Find Append PDF File" msgstr "" #: doctypeedit.cpp:171 doctypeedit.cpp:197 #, kde-format msgid "Add Document Type" msgstr "" #: doctypeedit.cpp:172 #, kde-format msgid "Enter the name of a new document type" msgstr "" #: doctypeedit.cpp:198 #, kde-format msgid "Edit the name of a document type" msgstr "" #: docdigestdetailview.cpp:230 rc.cpp:78 rc.cpp:120 rc.cpp:988 rc.cpp:1030 #: rc.cpp:1826 rc.cpp:1868 rc.cpp:2709 rc.cpp:2751 rc.cpp:3760 rc.cpp:3802 #: rc.cpp:4664 rc.cpp:4706 #, kde-format msgid "Amount" msgstr "" #: docdigestdetailview.cpp:231 #, kde-format msgid "Type" msgstr "" #: docdigestdetailview.cpp:232 #, kde-format msgid "Sum" msgstr "" #: docdigestdetailview.cpp:261 #, kde-format msgid "Results in %1 %2" msgstr "" #: docdigestdetailview.cpp:262 docdigestdetailview.cpp:295 #, kde-format msgid "Year" msgstr "" #: docdigestdetailview.cpp:264 #, kde-format msgid "Month" msgstr "" #: docdigestdetailview.cpp:297 #, kde-format msgid "Results in Year %1" msgstr "" #: docdigestdetailview.cpp:316 docdigestdetailview.cpp:325 #, kde-format msgid "Customer" msgstr "" #: docdigestdetailview.cpp:320 #, kde-format msgid "not set" msgstr "" #: docdigestdetailview.cpp:336 #, kde-format msgid "The address is not listed in an address book." msgstr "" #: docdigestdetailview.cpp:338 #, kde-format msgid "" "The client has the address book id %1 but can not found in our address books." msgstr "" #: docdigestdetailview.cpp:341 #, kde-format msgid "The client can be found in our address books." msgstr "" #: docdigestdetailview.cpp:352 prefsdialog.cpp:744 #, kde-format msgid "preferred address" msgstr "" #: docdigestdetailview.cpp:356 prefsdialog.cpp:748 #, kde-format msgid "home address" msgstr "" #: docdigestdetailview.cpp:360 prefsdialog.cpp:752 #, kde-format msgid "work address" msgstr "" #: docdigestdetailview.cpp:364 prefsdialog.cpp:756 #, kde-format msgid "postal address" msgstr "" #: docdigestdetailview.cpp:368 prefsdialog.cpp:760 #, kde-format msgid "international address" msgstr "" #: docdigestdetailview.cpp:372 prefsdialog.cpp:764 #, kde-format msgid "domestic address" msgstr "" #: docdigestdetailview.cpp:376 prefsdialog.cpp:768 #, kde-format msgid "unknown" msgstr "" #: docdigestdetailview.cpp:433 #, kde-format msgid "This document was never printed." msgstr "" #: docdigestdetailview.cpp:440 #, kde-format msgid "Last printed" msgstr "" #: docdigestdetailview.cpp:441 #, kde-format msgid "Opens last created PDF document" msgstr "" #: docdigestdetailview.cpp:442 #, kde-format msgid "open" msgstr "" #: docdigestdetailview.cpp:447 #, kde-format msgid "One older print" msgstr "" #: docdigestdetailview.cpp:449 #, kde-format msgid "%1 older prints" msgstr "" #: docdigestdetailview.cpp:453 #, kde-format msgid "Archived documents can not be found. Check PDF Output dir." msgstr "" #: docdigestdetailview.cpp:457 #, kde-format msgid "Export the invoice in XRechnung file format" msgstr "" #: docdigestdetailview.cpp:458 #, kde-format msgid "XRechnung" msgstr "" #: importfilter.cpp:50 #, kde-format msgid "Unable to find filter called %1" msgstr "" #: importfilter.cpp:58 #, kde-format msgid "Could not open the definition file!" msgstr "" #: importfilter.cpp:143 #, kde-format msgid "Unknown tags: " msgstr "" #: importfilter.cpp:184 #, kde-format msgid "Could not recode input file!" msgstr "" #: importfilter.cpp:192 #, kde-format msgid "Unable to open temp file " msgstr "" #: importfilter.cpp:198 #, kde-format msgid "Could not open the import source file!" msgstr "" #: importitemdialog.cpp:47 #, kde-format msgid "Import Items From File" msgstr "" #: importitemdialog.cpp:116 #, kde-format msgid "the Header of the Document" msgstr "" #: inserttempldialog.cpp:105 #, kde-format msgid "Create a new Item" msgstr "" #: inserttempldialog.cpp:107 #, kde-format msgid "Create a new Item from Template" msgstr "" #: itemtagdialog.cpp:82 #, kde-format msgid "Edit Item Tags" msgstr "" #: itemtagdialog.cpp:89 #, kde-format msgid "Item Tags" msgstr "" #: itemtagdialog.cpp:90 #, kde-format msgid "Select all tags for the item should be tagged with." msgstr "" #: itemtagdialog.cpp:105 tagtemplatesdialog.cpp:150 #, kde-format msgid "Tag" msgstr "" #: itemtagdialog.cpp:106 tagtemplatesdialog.cpp:151 #, kde-format msgid "Color" msgstr "" #: itemtagdialog.cpp:107 tagtemplatesdialog.cpp:152 #, kde-format msgid "Description" msgstr "" #: kataloglistview.cpp:355 #, kde-format msgid "A catalog chapter can not be deleted as long it has children." msgstr "" #: kataloglistview.cpp:356 #, kde-format msgid "Chapter can not be deleted" msgstr "" #: katalogview.cpp:164 #, kde-format msgid "Edit Sub chapter" msgstr "" #: katalogview.cpp:166 #, kde-format msgid "Edit a catalog sub chapter" msgstr "" #: katalogview.cpp:170 #, kde-format msgid "Add a sub chapter" msgstr "" #: katalogview.cpp:172 #, kde-format msgid "Add a sub chapter below the selected one" msgstr "" #: katalogview.cpp:176 katalogview.cpp:178 #, kde-format msgid "Remove a sub chapter" msgstr "" #: katalogview.cpp:182 rc.cpp:3 rc.cpp:913 rc.cpp:1751 rc.cpp:2634 rc.cpp:3685 #: rc.cpp:4589 #, kde-format msgid "Edit Template" msgstr "" #: katalogview.cpp:184 #, kde-format msgid "Opens the editor window for templates to edit the selected one" msgstr "" #: katalogview.cpp:189 #, kde-format msgid "New template" msgstr "" #: katalogview.cpp:191 #, kde-format msgid "Opens the editor window for templates to enter a new template" msgstr "" #: katalogview.cpp:196 #, kde-format msgid "Delete template" msgstr "" #: katalogview.cpp:198 #, kde-format msgid "Deletes the template" msgstr "" #: katalogview.cpp:203 #, kde-format msgid "Export catalog" msgstr "" #: katalogview.cpp:205 #, kde-format msgid "Export the whole catalog as XML encoded file" msgstr "" #: katalogview.cpp:210 #, kde-format msgid "Import catalog" msgstr "" #: katalogview.cpp:212 #, kde-format msgid "Import a catalog from a XML file" msgstr "" #: katalogview.cpp:216 rc.cpp:487 rc.cpp:1358 rc.cpp:2247 rc.cpp:3142 #: rc.cpp:4016 rc.cpp:4920 #, kde-format msgid "&Catalog" msgstr "" #: katalogview.cpp:234 #, kde-format msgid "Opening file..." msgstr "" #: katalogview.cpp:298 #, kde-format msgid "Exporting file..." msgstr "" #: katalogview.cpp:307 #, kde-format msgid "Importfile... (not yet implemented)" msgstr "" #: katalogview.cpp:312 #, kde-format msgid "Creating a new sub chapter..." msgstr "" #: katalogview.cpp:321 #, kde-format msgid "Editing a sub chapter..." msgstr "" #: katalogview.cpp:330 #, kde-format msgid "Removing a sub chapter..." msgstr "" #: katalogview.cpp:363 #, kde-format msgid "Created at %1 " msgstr "" #: katalogview.cpp:367 #, kde-format msgid ", last modified at %1" msgstr "" #: katalogview.cpp:373 #, kde-format msgid "%1 times used, last at %2" msgstr "" #: kraftdocheaderedit.cpp:57 #, kde-format msgid "Document Header" msgstr "" #: kraftdocheaderedit.cpp:65 #, kde-format msgid "Manually set in address field." msgstr "" #: kraftview.cpp:89 kraftview_ro.cpp:60 #, kde-format msgid "Document" msgstr "" #: kraftview.cpp:257 #, kde-format msgid "Successor of %1" msgstr "" #: kraftview.cpp:395 kraftview.cpp:847 #, kde-format msgid "" "The address label is not empty and different from the selected one.
      Do " "you really want to replace it with the text shown below?
      %1
      " msgstr "" #: kraftview.cpp:442 #, kde-format msgid "" "

      The Document Items List is still empty, but Items can be added now.To add items to the document either
      • Press the 'Add item' button " "above.
      • Open the template catalog by clicking on the 'show Template' " "button on the right and pick one of the available templates.
      " msgstr "" #: kraftview.cpp:634 prefsdialog.cpp:329 #, kde-format msgid "Display no tax at all" msgstr "" #: kraftview.cpp:635 prefsdialog.cpp:330 #, kde-format msgid "Calculate reduced tax for all items" msgstr "" #: kraftview.cpp:636 prefsdialog.cpp:331 #, kde-format msgid "Calculate full tax for all items" msgstr "" #: kraftview.cpp:637 #, kde-format msgid "Calculate individual tax for each item" msgstr "" #: kraftview.cpp:694 #, kde-format msgid "Tax Settings Overwrite" msgstr "" #: kraftview.cpp:695 #, kde-format msgid "Really overwrite all individual tax settings of the items?" msgstr "" #: kraftview.cpp:846 #, kde-format msgid "Address Overwrite" msgstr "" #: kraftview.cpp:1111 #, kde-format msgid "Discount" msgstr "" #: kraftview.cpp:1351 #, kde-format msgid "The document has been modified." msgstr "" #: kraftview.cpp:1352 #, kde-format msgid "Do you want to save your changes?" msgstr "" #: kraftdocfooteredit.cpp:52 #, kde-format msgid "Document Footer" msgstr "" #: kraftdocpositionsedit.cpp:94 #, kde-format msgid "Add Item..." msgstr "" #: kraftdocpositionsedit.cpp:96 #, kde-format msgid "Add a normal item to the document manually." msgstr "" #: kraftdocpositionsedit.cpp:100 #, kde-format msgid "Add Discount Item" msgstr "" #: kraftdocpositionsedit.cpp:103 #, kde-format msgid "" "Adds an item to the document that allows discounts on other items in the " "document" msgstr "" #: kraftdocpositionsedit.cpp:106 #, kde-format msgid "Import Items..." msgstr "" #: kraftdocpositionsedit.cpp:109 #, kde-format msgid "Opens a dialog where multiple items can be imported from a text file." msgstr "" #: kraftdocpositionsedit.cpp:118 #, kde-format msgid "Document Items" msgstr "" #: kraftview_ro.cpp:198 #, kde-format msgid "Reduced TAX" msgstr "" #: materialkataloglistview.cpp:40 rc.cpp:108 rc.cpp:643 rc.cpp:1018 rc.cpp:1675 #: rc.cpp:1856 rc.cpp:2567 rc.cpp:2739 rc.cpp:3471 rc.cpp:3790 rc.cpp:4181 #: rc.cpp:4694 rc.cpp:5088 #, kde-format msgid "Material" msgstr "" #: materialkataloglistview.cpp:41 #, kde-format msgid "Pack" msgstr "" #: materialkataloglistview.cpp:42 rc.cpp:123 rc.cpp:1033 rc.cpp:1871 #: rc.cpp:2754 rc.cpp:3805 rc.cpp:4709 #, kde-format msgid "Unit" msgstr "" #: materialkataloglistview.cpp:43 #, kde-format msgid "Purchase" msgstr "" #: materialkataloglistview.cpp:44 #, kde-format msgid "Sale" msgstr "" #: materialkataloglistview.cpp:45 #, kde-format msgid "Last Modified" msgstr "" #: materialkataloglistview.cpp:51 #, kde-format msgid "Material Catalog" msgstr "" #: materialkatalogview.cpp:106 #, kde-format msgid "" msgstr "" #: materialkatalogview.cpp:136 templkatalogview.cpp:139 #, kde-format msgid "Do you really want to delete the template from the catalog?" msgstr "" #: prefsdialog.cpp:64 #, kde-format msgid "Configure Kraft" msgstr "" #: prefsdialog.cpp:98 #, kde-format msgid "Document Defaults" msgstr "" #: prefsdialog.cpp:99 #, kde-format msgid "Taxes" msgstr "" #: prefsdialog.cpp:100 #, kde-format msgid "Document Types" msgstr "" #: prefsdialog.cpp:102 #, kde-format msgid "Wages" msgstr "" #: prefsdialog.cpp:104 #, kde-format msgid "Units" msgstr "" #: prefsdialog.cpp:105 #, kde-format msgid "Own Identity" msgstr "" #: prefsdialog.cpp:152 #, kde-format msgid "Tax rates beginning at date:" msgstr "" #: prefsdialog.cpp:160 prefswages.cpp:51 prefsunits.cpp:53 #, kde-format msgid "ID" msgstr "" #: prefsdialog.cpp:161 #, kde-format msgid "Full Tax [%]" msgstr "" #: prefsdialog.cpp:162 #, kde-format msgid "Reduced Tax [%]" msgstr "" #: prefsdialog.cpp:163 #, kde-format msgid "Start Date" msgstr "" #: prefsdialog.cpp:182 prefswages.cpp:90 prefsunits.cpp:80 rc.cpp:307 #: rc.cpp:1160 rc.cpp:2064 rc.cpp:2947 rc.cpp:3517 rc.cpp:4421 #, kde-format msgid "Add" msgstr "" #: prefsdialog.cpp:186 prefswages.cpp:99 prefsunits.cpp:89 rc.cpp:319 #: rc.cpp:1172 rc.cpp:2076 rc.cpp:2959 rc.cpp:3529 rc.cpp:4433 #, kde-format msgid "Remove" msgstr "" #: prefsdialog.cpp:203 #, kde-format msgid "" "Select the identity of the sending entity of documents. That's your " "companies address." msgstr "" #: prefsdialog.cpp:219 #, kde-format msgid "Select Identity..." msgstr "" #: prefsdialog.cpp:225 #, kde-format msgid "From AddressBook" msgstr "" #: prefsdialog.cpp:230 setupassistant.cpp:342 #, kde-format msgid "Manual Entry" msgstr "" #: prefsdialog.cpp:242 #, kde-format msgid "Manual Address" msgstr "" #: prefsdialog.cpp:245 #, kde-format msgid "Bank Account Information" msgstr "" #: prefsdialog.cpp:309 #, kde-format msgid "&Default document type on creation:" msgstr "" #: prefsdialog.cpp:314 #, kde-format msgid "New documents default to the selected type." msgstr "" #: prefsdialog.cpp:323 #, kde-format msgid "Default &Tax for Documents:" msgstr "" #: prefsdialog.cpp:328 #, kde-format msgid "The default tax setting for all documents." msgstr "" #: prefsdialog.cpp:340 #, kde-format msgid "Document Date Format:" msgstr "" #: prefsdialog.cpp:346 #, kde-format msgid "The default date format for documents." msgstr "" #: prefsdialog.cpp:348 #, kde-format msgid "ISO-Format: %1" msgstr "" #: prefsdialog.cpp:350 #, kde-format msgid "Short-Date: %1" msgstr "" #: prefsdialog.cpp:352 #, kde-format msgid "Long-Date: %1" msgstr "" #: prefsdialog.cpp:354 #, kde-format msgid "RFC 2822-Format: %1" msgstr "" #: prefsdialog.cpp:356 #, kde-format msgid "\"German Format\": %1" msgstr "" #: prefsdialog.cpp:357 #, kde-format msgid "Custom Setting in Settingsfile" msgstr "" #: prefsdialog.cpp:366 #, kde-format msgid "Prefix text for Demand items:" msgstr "" #: prefsdialog.cpp:371 #, kde-format msgid "This text is automatically prepended to new 'on demand' items." msgstr "" #: prefsdialog.cpp:375 #, kde-format msgid "Prefix text for Alternative items:" msgstr "" #: prefsdialog.cpp:380 #, kde-format msgid "This text is automatically prepended to new 'alternative' items." msgstr "" #: prefsdialog.cpp:391 #, kde-format msgid "XRechnung Template File:" msgstr "" #: prefsdialog.cpp:397 #, kde-format msgid "Select..." msgstr "" #: prefsdialog.cpp:405 #, kde-format msgid "Select template file for XRechnung" msgstr "" #: prefsdialog.cpp:410 #, kde-format msgid "XRechnung Templates (*.xrtmpl)" msgstr "" #: prefsdialog.cpp:450 #, kde-format msgid "" "The old default doc type for new documents was just deleted.Please check the " "setting in the Document Defaults in the Kraft preferences Dialog." msgstr "" #: prefsdialog.cpp:453 #, kde-format msgid "Document Default Change" msgstr "" #: prefsdialog.cpp:701 #, kde-format msgid "The identity can not be found." msgstr "" #: prefsdialog.cpp:703 #, kde-format msgid "" "

      Kraft Addressbook Integration down.

      The address book backend " "is not up and running.

      Please check your addressbook integration setup." "

      " msgstr "" #: prefsdialog.cpp:709 #, kde-format msgid "The identity is not listed in an address book." msgstr "" #: prefsdialog.cpp:711 #, kde-format msgid "" "

      Kraft does not know your identity.

      Please pick one from the " "address books by clicking on the Button below.

      Not having an identity " "selected can make your documents look incomplete.

      " msgstr "" #: prefsdialog.cpp:728 #, kde-format msgid "Your identity can be found in the address books." msgstr "" #: prefsdialog.cpp:739 #, kde-format msgid "Work Phone" msgstr "" #: prefsdialog.cpp:740 #, kde-format msgid "Fax" msgstr "" #: prefsdialog.cpp:741 #, kde-format msgid "Cell Phone" msgstr "" #: materialselectdialog.cpp:39 #, kde-format msgid "Add Material to Calculation" msgstr "" #: materialselectdialog.cpp:44 #, kde-format msgid "

      Add Material to Calculation

      " msgstr "" #: newdocassistant.cpp:52 newdocassistant.cpp:96 #, kde-format msgid "New Document Settings" msgstr "" #: newdocassistant.cpp:55 #, kde-format msgid "" "Please select a customer as addressee for the document. If there is no entry " "for the customer in the addressbook yet, it can be opened by clicking on the " "button below." msgstr "" #: newdocassistant.cpp:100 #, kde-format msgid "" "Select a document type and a date. A comment on the whiteboard helps to " "classify the document." msgstr "" #: newdocassistant.cpp:107 #, kde-format msgid "Customer: Not yet selected!" msgstr "" #: newdocassistant.cpp:116 #, kde-format msgid "Document &Type:" msgstr "" #: newdocassistant.cpp:120 #, kde-format msgid "Document Date: " msgstr "" #: newdocassistant.cpp:123 #, kde-format msgid "Whiteboard Content:" msgstr "" #: newdocassistant.cpp:127 #, kde-format msgid "Copy document items from predecessor document" msgstr "" #: newdocassistant.cpp:175 #, kde-format msgid "Create a new Kraft Document" msgstr "" #: newdocassistant.cpp:265 #, kde-format msgid "Followup Document for %1" msgstr "" #: numbercycledialog.cpp:52 #, kde-format msgid "Edit Number Cycles" msgstr "" #: numbercycledialog.cpp:67 #, kde-format msgid "" "The template may contain the following tags:
      • %y or %yyyy - the year " "of the documents date.
      • %yy - the year of the document (two digits).
      • %w - the week number of the documents date.
      • %ww - the week " "number of the documents date with leading zero.
      • %d - the day number " "of the documents date.
      • %dd - the day number of the documents date " "with leading zero.
      • %m or %M - the month number of the documents date." "
      • %MM - the month number with leading zero.
      • %c - the customer " "id from kaddressbook
      • %i - the unique counter
      • %ii .. %iiiiii " "- the counter padded with leading 0, ie. 012
      • %n - a day based " "counter, resets every day. Combined with date, it makes the number unique.
      • %nn .. %nnnnnn - the day based counter padded with leading 0.
      • %type - the localised doc type (offer, invoice etc.)
      • %uid - " "the contact id of the client.
      %i or %n need to be part of the " "template." msgstr "" #: numbercycledialog.cpp:141 #, kde-format msgid "Doc-Type" msgstr "" #: numbercycledialog.cpp:154 #, kde-format msgctxt "do not translate %i, it is a template variable." msgid "(%i added)" msgstr "" #: numbercycledialog.cpp:227 #, kde-format msgid "Add Number Cycle" msgstr "" #: numbercycledialog.cpp:228 #, kde-format msgid "Enter the name of a new number cycle." msgstr "" #: numbercycledialog.cpp:286 #, kde-format msgid "The numbercycle %1 is still assigned to a document type." msgstr "" #: numbercycledialog.cpp:287 #, kde-format msgid "" "The number cycle can not be deleted as long as it is assigned to a document " "type." msgstr "" #: numbercycledialog.cpp:346 #, kde-format msgid "Dangerous Counter Change" msgstr "" #: numbercycledialog.cpp:347 #, kde-format msgid "The new counter is lower than the old one. " msgstr "" #: numbercycledialog.cpp:348 #, kde-format msgid "" "That has potential to create duplicate document numbers. Do you really want " "to decrease it?" msgstr "" #: portalview.cpp:68 #, kde-format msgid "About Kraft" msgstr "" #: portalview.cpp:98 #, kde-format msgid "Documents" msgstr "" #: portalview.cpp:105 #, kde-format msgid "Timeline" msgstr "" #: portalview.cpp:113 #, kde-format msgid "Catalogs" msgstr "" #: portalview.cpp:152 #, kde-format msgid "Kraft Document Overview" msgstr "" #: portalview.cpp:159 portalview.cpp:178 #, kde-format msgid "Available Catalogs" msgstr "" #: portalview.cpp:161 #, kde-format msgid "No catalogs available." msgstr "" #: portalview.cpp:210 #, kde-format msgid "Open" msgstr "" #: portalview.cpp:221 #, kde-format msgid "No templates yet." msgstr "" #: portalview.cpp:225 #, kde-format msgid "%1 templates in %2 chapters
      last modified at %3" msgstr "" #: portalview.cpp:276 #, kde-format msgid "Kraft Website" msgstr "" #: portalview.cpp:279 #, kde-format msgctxt "The string is followed by a link to the GPL2 text" msgid "Kraft is free software licensed under the" msgstr "" #: portalview.cpp:280 #, kde-format msgctxt "The string is followed by the link to github" msgid "Kraft is maintained on " msgstr "" #: portalview.cpp:281 #, kde-format msgid "Authors" msgstr "" #: portalview.cpp:282 #, kde-format msgid "Developer and Maintainer" msgstr "" #: portalview.cpp:283 #, kde-format msgid "Developer" msgstr "" #: portalview.cpp:284 #, kde-format msgctxt "The person who provided the logo graphics" msgid "Logo design" msgstr "" #: portalview.cpp:285 #, kde-format msgctxt "The person who provided the user manual" msgid "User Manual" msgstr "" #: portalview.cpp:287 #, kde-format msgid "" "Kraft helps you to handle documents like quotes and invoices in your small " "business." msgstr "" #: portalview.cpp:288 #, kde-format msgid "Welcome to Kraft" msgstr "" #: portalview.cpp:289 #, kde-format msgid "Kraft Version" msgstr "" #: portalview.cpp:291 #, kde-format msgid "Codename" msgstr "" #: portalview.cpp:300 #, kde-format msgid "Git Information" msgstr "" #: portalview.cpp:308 #, kde-format msgid "Country Setting" msgstr "" #: portalview.cpp:311 #, kde-format msgid "Language Setting" msgstr "" #: portalview.cpp:315 #, kde-format msgid "Kraft Initialisation Problem" msgstr "" #: portalview.cpp:316 #, kde-format msgid "" "There is a initialisation error on your system. Kraft will not work that way." msgstr "" #: portalview.cpp:323 #, kde-format msgid "Database Information" msgstr "" #: portalview.cpp:324 #, kde-format msgid "Kraft database name" msgstr "" #: portalview.cpp:329 #, kde-format msgid "Required Version" msgstr "" #: portalview.cpp:332 #, kde-format msgid "Database schema version" msgstr "" #: portalview.cpp:334 #, kde-format msgid "Qt database driver" msgstr "" #: portalview.cpp:338 #, kde-format msgid "established" msgstr "" #: portalview.cpp:338 #, kde-format msgid "NOT AVAILABLE!" msgstr "" #: portalview.cpp:339 #, kde-format msgid "Database connection" msgstr "" #: portalview.cpp:348 #, kde-format msgid "Database Version" msgstr "" #: portalview.cpp:356 #, kde-format msgid "Addressbook Backend" msgstr "" #: portalview.cpp:357 #, kde-format msgid "Backend type" msgstr "" #: portalview.cpp:359 #, kde-format msgid "running" msgstr "" #: portalview.cpp:359 #, kde-format msgid "not running" msgstr "" #: portalview.cpp:363 #, kde-format msgid "External Tools" msgstr "" #: portalview.cpp:365 #, kde-format msgid "RML to PDF conversion tool" msgstr "" #: portalview.cpp:367 #, kde-format msgid "not found!" msgstr "" #: portalview.cpp:370 #, kde-format msgid "iconv tool for text import" msgstr "" #: portalview.cpp:373 #, kde-format msgid "weasyprint for PDF generation" msgstr "" #: portalview.cpp:377 #, kde-format msgid "not available" msgstr "" #: portalview.cpp:382 #, kde-format msgid "Some Icons are made by" msgstr "" #: portalview.cpp:383 #, kde-format msgid "Acknowledgements" msgstr "" #: positionviewwidget.cpp:90 #, kde-format msgid "Item Actions" msgstr "" #: positionviewwidget.cpp:93 #, kde-format msgid "Item Kind" msgstr "" #: positionviewwidget.cpp:94 positionviewwidget.cpp:687 #, kde-format msgid "Normal" msgstr "" #: positionviewwidget.cpp:96 positionviewwidget.cpp:695 #, kde-format msgid "Alternative" msgstr "" #: positionviewwidget.cpp:98 #, kde-format msgid "On Demand" msgstr "" #: positionviewwidget.cpp:103 rc.cpp:265 rc.cpp:874 rc.cpp:1745 rc.cpp:2628 #: rc.cpp:3926 rc.cpp:4830 #, kde-format msgid "Tax" msgstr "" #: positionviewwidget.cpp:106 #, kde-format msgid "Taxfree Item" msgstr "" #: positionviewwidget.cpp:112 #, kde-format msgid "Reduced Tax" msgstr "" #: positionviewwidget.cpp:118 #, kde-format msgid "Full Tax" msgstr "" #: positionviewwidget.cpp:127 #, kde-format msgid "Move Up" msgstr "" #: positionviewwidget.cpp:129 #, kde-format msgid "Move Down" msgstr "" #: positionviewwidget.cpp:131 #, kde-format msgid "Lock Item" msgstr "" #: positionviewwidget.cpp:133 #, kde-format msgid "Unlock Item" msgstr "" #: positionviewwidget.cpp:135 #, kde-format msgid "Delete Item" msgstr "" #: positionviewwidget.cpp:226 #, kde-format msgid "All items" msgstr "" #: positionviewwidget.cpp:236 #, kde-format msgid "%1-tagged items" msgstr "" #: positionviewwidget.cpp:268 #, kde-format msgid "Tag: %1" msgstr "" #: positionviewwidget.cpp:270 #, kde-format msgid "Tags:
        " msgstr "" #: positionviewwidget.cpp:281 #, kde-format msgid "No tags assigned yet." msgstr "" #: positionviewwidget.cpp:410 #, kde-format msgid "Active" msgstr "" #: positionviewwidget.cpp:412 #, kde-format msgid "New" msgstr "" #: positionviewwidget.cpp:414 #, kde-format msgid "Deleted" msgstr "" #: positionviewwidget.cpp:416 #, kde-format msgid "Locked" msgstr "" #: positionviewwidget.cpp:613 #, kde-format msgid "" "This item is either completely optional or its amount varies depending on " "the needs.

        Use the item toolbox to change the item type." msgstr "" #: positionviewwidget.cpp:619 #, kde-format msgid "" "This is an alternative item.

        Use the position toolbox to change " "the item type." msgstr "" #: positionviewwidget.cpp:691 #, kde-format msgid "Demand" msgstr "" #: prefswages.cpp:52 #, kde-format msgid "Code" msgstr "" #: prefswages.cpp:53 rc.cpp:126 rc.cpp:1036 rc.cpp:1874 rc.cpp:2757 rc.cpp:3808 #: rc.cpp:4712 templkataloglistview.cpp:46 #, kde-format msgid "Price" msgstr "" #: prefswages.cpp:54 #, kde-format msgid "Sortkey" msgstr "" #: prefswages.cpp:80 #, kde-format msgid "Up" msgstr "" #: prefswages.cpp:85 #, kde-format msgid "Down" msgstr "" #: prefswages.cpp:94 prefsunits.cpp:84 rc.cpp:313 rc.cpp:1166 rc.cpp:2070 #: rc.cpp:2953 rc.cpp:3523 rc.cpp:4427 #, kde-format msgid "Edit" msgstr "" #: prefswages.cpp:201 #, kde-format msgid "Edit a wage group" msgstr "" #: prefswages.cpp:241 #, kde-format msgid "

        Edit wage group

        " msgstr "" #: prefsunits.cpp:54 #, kde-format msgid "Short" msgstr "" #: prefsunits.cpp:55 #, kde-format msgid "Long" msgstr "" #: prefsunits.cpp:56 #, kde-format msgid "Short plural" msgstr "" #: prefsunits.cpp:57 #, kde-format msgid "Long plural" msgstr "" #: prefsunits.cpp:58 #, kde-format msgid "ECE20" msgstr "" #: prefsunits.cpp:153 #, kde-format msgid "Edit a unit" msgstr "" #: prefsunits.cpp:197 #, kde-format msgid "

        Edit unit

        " msgstr "" #: reportgenerator.cpp:113 #, kde-format msgid "Document generation process is still running." msgstr "" #: reportgenerator.cpp:168 #, kde-format msgid "Template file is not accessible." msgstr "" #: reportgenerator.cpp:193 #, kde-format msgid "The template conversion failed." msgstr "" #: reportgenerator.cpp:201 #, kde-format msgid "Saving to temporar file failed." msgstr "" #: reportgenerator.cpp:332 #, kde-format msgid "No converter error." msgstr "" #: reportgenerator.cpp:335 #, kde-format msgid "The ReportLab based converter script can not be executed." msgstr "" #: reportgenerator.cpp:338 #, kde-format msgid "An unknown error happened." msgstr "" #: reportgenerator.cpp:341 #, kde-format msgid "The ReportLab python module is not installed." msgstr "" #: reportgenerator.cpp:344 #, kde-format msgid "The PyPDF2 python module is not installed." msgstr "" #: reportgenerator.cpp:347 #, kde-format msgid "The source file can not be read." msgstr "" #: reportgenerator.cpp:350 #, kde-format msgid "The target can not be opened to write." msgstr "" #: reportgenerator.cpp:353 #, kde-format msgid "The target file does not exist." msgstr "" #: reportgenerator.cpp:356 #, kde-format msgid "The WeasyPrint tool is not installed." msgstr "" #: reportgenerator.cpp:359 #, kde-format msgid "The PDF merger utility failed." msgstr "" #: reportgenerator.cpp:378 #, kde-format msgid "There is not template defined for %1." msgstr "" #: reportgenerator.cpp:383 #, kde-format msgid "The template file %1 for document type %2 does not exist." msgstr "" #: reportgenerator.cpp:387 #, kde-format msgid "The template file %1 for document type %2 can not be read." msgstr "" #: rc.cpp:6 rc.cpp:916 rc.cpp:1754 rc.cpp:2637 rc.cpp:3688 rc.cpp:4592 #: templkataloglistview.cpp:45 texteditdialog.cpp:76 #, kde-format msgid "Template" msgstr "" #: rc.cpp:9 rc.cpp:919 rc.cpp:1757 rc.cpp:2640 rc.cpp:3691 rc.cpp:4595 #, kde-format msgid "Text:" msgstr "" #: rc.cpp:12 rc.cpp:922 rc.cpp:1760 rc.cpp:2643 rc.cpp:3694 rc.cpp:4598 #, kde-format msgid "&Store in Chapter" msgstr "" #: rc.cpp:15 rc.cpp:925 rc.cpp:1763 rc.cpp:2646 rc.cpp:3697 rc.cpp:4601 #, kde-format msgid "&Unit" msgstr "" #: rc.cpp:18 rc.cpp:928 rc.cpp:1766 rc.cpp:2649 rc.cpp:3700 rc.cpp:4604 #, kde-format msgid "&Count Time for Overalltime" msgstr "" #: rc.cpp:24 rc.cpp:934 rc.cpp:1772 rc.cpp:2655 rc.cpp:3706 rc.cpp:4610 #, kde-format msgid "full" msgstr "" #: rc.cpp:27 rc.cpp:937 rc.cpp:1775 rc.cpp:2658 rc.cpp:3709 rc.cpp:4613 #, kde-format msgid "half" msgstr "" #: rc.cpp:30 rc.cpp:940 rc.cpp:1778 rc.cpp:2661 rc.cpp:3712 rc.cpp:4616 #, kde-format msgid "Time Calculation" msgstr "" #: rc.cpp:33 rc.cpp:72 rc.cpp:111 rc.cpp:943 rc.cpp:982 rc.cpp:1021 rc.cpp:1781 #: rc.cpp:1820 rc.cpp:1859 rc.cpp:2664 rc.cpp:2703 rc.cpp:2742 rc.cpp:3715 #: rc.cpp:3754 rc.cpp:3793 rc.cpp:4619 rc.cpp:4658 rc.cpp:4697 #, kde-format msgid "text" msgstr "" #: rc.cpp:36 rc.cpp:946 rc.cpp:1784 rc.cpp:2667 rc.cpp:3718 rc.cpp:4622 #, kde-format msgid "Time measureable effort for this template:" msgstr "" #: rc.cpp:39 rc.cpp:81 rc.cpp:117 rc.cpp:949 rc.cpp:991 rc.cpp:1027 rc.cpp:1787 #: rc.cpp:1829 rc.cpp:1865 rc.cpp:2670 rc.cpp:2712 rc.cpp:2748 rc.cpp:3721 #: rc.cpp:3763 rc.cpp:3799 rc.cpp:4625 rc.cpp:4667 rc.cpp:4703 #, kde-format msgid "Label" msgstr "" #: rc.cpp:42 rc.cpp:952 rc.cpp:1790 rc.cpp:2673 rc.cpp:3724 rc.cpp:4628 #, kde-format msgid "Duration" msgstr "" #: rc.cpp:45 rc.cpp:955 rc.cpp:1793 rc.cpp:2676 rc.cpp:3727 rc.cpp:4631 #, kde-format msgid "Hourly Rate" msgstr "" #: rc.cpp:48 rc.cpp:958 rc.cpp:1796 rc.cpp:2679 rc.cpp:3730 rc.cpp:4634 #, kde-format msgid "Glob. Rate" msgstr "" #: rc.cpp:51 rc.cpp:961 rc.cpp:1799 rc.cpp:2682 rc.cpp:3733 rc.cpp:4637 #, kde-format msgid "Adds a new time calculation part to the template" msgstr "" #: rc.cpp:54 rc.cpp:93 rc.cpp:132 rc.cpp:964 rc.cpp:1003 rc.cpp:1042 #: rc.cpp:1802 rc.cpp:1841 rc.cpp:1880 rc.cpp:2685 rc.cpp:2724 rc.cpp:2763 #: rc.cpp:3736 rc.cpp:3775 rc.cpp:3814 rc.cpp:4640 rc.cpp:4679 rc.cpp:4718 #, kde-format msgid "new..." msgstr "" #: rc.cpp:57 rc.cpp:967 rc.cpp:1805 rc.cpp:2688 rc.cpp:3739 rc.cpp:4643 #, kde-format msgid "Edits the current time calculation part" msgstr "" #: rc.cpp:60 rc.cpp:99 rc.cpp:138 rc.cpp:970 rc.cpp:1009 rc.cpp:1048 #: rc.cpp:1808 rc.cpp:1847 rc.cpp:1886 rc.cpp:2691 rc.cpp:2730 rc.cpp:2769 #: rc.cpp:3742 rc.cpp:3781 rc.cpp:3820 rc.cpp:4646 rc.cpp:4685 rc.cpp:4724 #, kde-format msgid "edit..." msgstr "" #: rc.cpp:63 rc.cpp:973 rc.cpp:1811 rc.cpp:2694 rc.cpp:3745 rc.cpp:4649 #, kde-format msgid "Deletes the current time calculation part" msgstr "" #: rc.cpp:66 rc.cpp:105 rc.cpp:144 rc.cpp:976 rc.cpp:1015 rc.cpp:1054 #: rc.cpp:1814 rc.cpp:1853 rc.cpp:1892 rc.cpp:2697 rc.cpp:2736 rc.cpp:2775 #: rc.cpp:3748 rc.cpp:3787 rc.cpp:3826 rc.cpp:4652 rc.cpp:4691 rc.cpp:4730 #, kde-format msgid "delete" msgstr "" #: rc.cpp:69 rc.cpp:979 rc.cpp:1817 rc.cpp:2700 rc.cpp:3751 rc.cpp:4655 #, kde-format msgid "Fix Costs" msgstr "" #: rc.cpp:75 rc.cpp:985 rc.cpp:1823 rc.cpp:2706 rc.cpp:3757 rc.cpp:4661 #, kde-format msgid "Fix costs for this template per one unit:" msgstr "" #: rc.cpp:84 rc.cpp:994 rc.cpp:1832 rc.cpp:2715 rc.cpp:3766 rc.cpp:4670 #, kde-format msgid "Single Price" msgstr "" #: rc.cpp:87 rc.cpp:997 rc.cpp:1835 rc.cpp:2718 rc.cpp:3769 rc.cpp:4673 #, kde-format msgid "Overall Price" msgstr "" #: rc.cpp:90 rc.cpp:1000 rc.cpp:1838 rc.cpp:2721 rc.cpp:3772 rc.cpp:4676 #, kde-format msgid "adds a new fix calculation part" msgstr "" #: rc.cpp:96 rc.cpp:1006 rc.cpp:1844 rc.cpp:2727 rc.cpp:3778 rc.cpp:4682 #, kde-format msgid "edits the current fix calculation part" msgstr "" #: rc.cpp:102 rc.cpp:1012 rc.cpp:1850 rc.cpp:2733 rc.cpp:3784 rc.cpp:4688 #, kde-format msgid "deletes the current fix calculation part" msgstr "" #: rc.cpp:114 rc.cpp:1024 rc.cpp:1862 rc.cpp:2745 rc.cpp:3796 rc.cpp:4700 #, kde-format msgid "Needed materials for one unit of this template:" msgstr "" #: rc.cpp:129 rc.cpp:1039 rc.cpp:1877 rc.cpp:2760 rc.cpp:3811 rc.cpp:4715 #, kde-format msgid "adds a new material calculation part" msgstr "" #: rc.cpp:135 rc.cpp:1045 rc.cpp:1883 rc.cpp:2766 rc.cpp:3817 rc.cpp:4721 #, kde-format msgid "edits the current material part" msgstr "" #: rc.cpp:141 rc.cpp:1051 rc.cpp:1889 rc.cpp:2772 rc.cpp:3823 rc.cpp:4727 #, kde-format msgid "deletes the current material calculation part" msgstr "" #: rc.cpp:147 rc.cpp:1057 rc.cpp:1895 rc.cpp:2778 rc.cpp:3829 rc.cpp:4733 #, kde-format msgid "Overall Price per Unit" msgstr "" #: rc.cpp:150 rc.cpp:1060 rc.cpp:1898 rc.cpp:2781 rc.cpp:3832 rc.cpp:4736 #, kde-format msgid "&Manual Price" msgstr "" #: rc.cpp:153 rc.cpp:1063 rc.cpp:1901 rc.cpp:2784 rc.cpp:3835 rc.cpp:4739 #, kde-format msgid "Calculated Price" msgstr "" #: rc.cpp:156 rc.cpp:1066 rc.cpp:1904 rc.cpp:2787 rc.cpp:3838 rc.cpp:4742 #, kde-format msgid "Fix Costs Part:" msgstr "" #: rc.cpp:159 rc.cpp:1069 rc.cpp:1907 rc.cpp:2790 rc.cpp:3841 rc.cpp:4745 #, kde-format msgid "Material Part:" msgstr "" #: rc.cpp:162 rc.cpp:1072 rc.cpp:1910 rc.cpp:2793 rc.cpp:3844 rc.cpp:4748 #, kde-format msgid "Profit:" msgstr "" #: rc.cpp:166 rc.cpp:1076 rc.cpp:1914 rc.cpp:2797 rc.cpp:3848 rc.cpp:4752 #, no-c-format, kde-format msgid " %" msgstr "" #: rc.cpp:169 rc.cpp:1079 rc.cpp:1917 rc.cpp:2800 rc.cpp:3851 rc.cpp:4755 #, kde-format msgid "Time Calculation Part:" msgstr "" #: rc.cpp:172 rc.cpp:1082 rc.cpp:1920 rc.cpp:2803 rc.cpp:3854 rc.cpp:4758 #, kde-format msgid "Calculated Price:" msgstr "" #: rc.cpp:175 rc.cpp:1085 rc.cpp:1923 rc.cpp:2806 rc.cpp:3857 rc.cpp:4761 #, kde-format msgid "88.888,88 €" msgstr "" #: rc.cpp:178 rc.cpp:1088 rc.cpp:1959 rc.cpp:2842 rc.cpp:3860 rc.cpp:4764 #, kde-format msgid "Database creation and initial schema setup:" msgstr "" #: rc.cpp:181 rc.cpp:190 rc.cpp:844 rc.cpp:1091 rc.cpp:1100 rc.cpp:1706 #: rc.cpp:1962 rc.cpp:1971 rc.cpp:2598 rc.cpp:2845 rc.cpp:2854 rc.cpp:3502 #: rc.cpp:3863 rc.cpp:3872 rc.cpp:4385 rc.cpp:4767 rc.cpp:4776 rc.cpp:5292 #, kde-format msgid "0 / 129" msgstr "" #: rc.cpp:184 rc.cpp:193 rc.cpp:847 rc.cpp:1094 rc.cpp:1103 rc.cpp:1709 #: rc.cpp:1965 rc.cpp:1974 rc.cpp:2601 rc.cpp:2848 rc.cpp:2857 rc.cpp:3505 #: rc.cpp:3866 rc.cpp:3875 rc.cpp:4388 rc.cpp:4770 rc.cpp:4779 rc.cpp:5295 #, kde-format msgid "X" msgstr "" #: rc.cpp:187 rc.cpp:1097 rc.cpp:1968 rc.cpp:2851 rc.cpp:3869 rc.cpp:4773 #, kde-format msgid "Filling the database with initial values:" msgstr "" #: rc.cpp:196 rc.cpp:850 rc.cpp:1106 rc.cpp:1712 rc.cpp:1977 rc.cpp:2604 #: rc.cpp:2860 rc.cpp:3508 rc.cpp:3878 rc.cpp:4391 rc.cpp:4782 rc.cpp:5298 #, kde-format msgid "Status: " msgstr "" #: rc.cpp:199 rc.cpp:1109 rc.cpp:1980 rc.cpp:2863 rc.cpp:3881 rc.cpp:4785 #, kde-format msgid "Database setup status..." msgstr "" #: rc.cpp:202 rc.cpp:1112 rc.cpp:1926 rc.cpp:2809 rc.cpp:3884 rc.cpp:4788 #, kde-format msgid "Bruns Data File:" msgstr "" #: rc.cpp:205 rc.cpp:1115 rc.cpp:1929 rc.cpp:2812 rc.cpp:3887 rc.cpp:4791 #, kde-format msgid "Bruns Key File:" msgstr "" #: rc.cpp:208 rc.cpp:1118 rc.cpp:1932 rc.cpp:2815 rc.cpp:3890 rc.cpp:4794 #, kde-format msgid "Qt Database Driver:" msgstr "" #: rc.cpp:211 rc.cpp:1121 rc.cpp:1935 rc.cpp:2818 rc.cpp:3893 rc.cpp:4797 #, kde-format msgid "Database Server:" msgstr "" #: rc.cpp:214 rc.cpp:1124 rc.cpp:1938 rc.cpp:2821 rc.cpp:3896 rc.cpp:4800 #, kde-format msgid "Server Port:" msgstr "" #: rc.cpp:217 rc.cpp:1127 rc.cpp:1941 rc.cpp:2824 rc.cpp:3899 rc.cpp:4803 #, kde-format msgid "Database Name" msgstr "" #: rc.cpp:220 rc.cpp:700 rc.cpp:1130 rc.cpp:1555 rc.cpp:1944 rc.cpp:2399 #: rc.cpp:2827 rc.cpp:3315 rc.cpp:3902 rc.cpp:4238 rc.cpp:4806 rc.cpp:5145 #, kde-format msgid "Database User:" msgstr "" #: rc.cpp:223 rc.cpp:1133 rc.cpp:1947 rc.cpp:2830 rc.cpp:3905 rc.cpp:4809 #, kde-format msgid "Database Password:" msgstr "" #: rc.cpp:226 rc.cpp:1136 rc.cpp:1950 rc.cpp:2833 rc.cpp:3908 rc.cpp:4812 #, kde-format msgid "The default database name when creating new databases" msgstr "" #: rc.cpp:229 rc.cpp:1139 rc.cpp:1953 rc.cpp:2836 rc.cpp:3911 rc.cpp:4815 #, kde-format msgid "File Name" msgstr "" #: rc.cpp:232 rc.cpp:1142 rc.cpp:1956 rc.cpp:2839 rc.cpp:3914 rc.cpp:4818 #, kde-format msgid "The path where database file are stored. Leave empty!" msgstr "" #: rc.cpp:235 rc.cpp:1145 rc.cpp:2016 rc.cpp:2899 rc.cpp:3640 rc.cpp:4544 #, kde-format msgid "Database Update:" msgstr "" #: rc.cpp:238 rc.cpp:1148 rc.cpp:2019 rc.cpp:2902 rc.cpp:3643 rc.cpp:4547 #, kde-format msgid "Overall Progress:" msgstr "" #: rc.cpp:241 rc.cpp:1151 rc.cpp:2022 rc.cpp:2905 rc.cpp:3646 rc.cpp:4550 #, kde-format msgid "Detail Progress:" msgstr "" #: rc.cpp:244 rc.cpp:1154 rc.cpp:2025 rc.cpp:2908 rc.cpp:3649 rc.cpp:4553 #, kde-format msgid "Status:" msgstr "" #: rc.cpp:247 rc.cpp:1289 rc.cpp:1727 rc.cpp:2610 rc.cpp:3631 rc.cpp:4535 #, kde-format msgid "" "

        Kraft uses a database backend to store values. By " "default it uses a file based database with easy setup targeted to single " "user mode.


        " msgstr "" #: rc.cpp:250 rc.cpp:1292 rc.cpp:1730 rc.cpp:2613 rc.cpp:3634 rc.cpp:4538 #, kde-format msgid "SQLite 3 - file based database (default)" msgstr "" #: rc.cpp:253 rc.cpp:1295 rc.cpp:1733 rc.cpp:2616 rc.cpp:3637 rc.cpp:4541 #, kde-format msgid "MySQL Serverbased Database for advanced Setups" msgstr "" #: rc.cpp:256 rc.cpp:865 rc.cpp:1736 rc.cpp:2619 rc.cpp:3917 rc.cpp:4821 #, kde-format msgid "Footer Texts" msgstr "" #: rc.cpp:259 rc.cpp:868 rc.cpp:1739 rc.cpp:2622 rc.cpp:3920 rc.cpp:4824 #, kde-format msgid "&Summary Text on Last Page:" msgstr "" #: rc.cpp:262 rc.cpp:871 rc.cpp:1742 rc.cpp:2625 rc.cpp:3923 rc.cpp:4827 #, kde-format msgid "&Greeting:" msgstr "" #: rc.cpp:268 rc.cpp:877 rc.cpp:1748 rc.cpp:2631 rc.cpp:3929 rc.cpp:4833 #, kde-format msgid "Document &Tax:" msgstr "" #: rc.cpp:271 rc.cpp:880 rc.cpp:2028 rc.cpp:2911 rc.cpp:3932 rc.cpp:4836 #, kde-format msgid "TextLabel" msgstr "" #: rc.cpp:274 rc.cpp:883 rc.cpp:2031 rc.cpp:2914 rc.cpp:3935 rc.cpp:4839 #, kde-format msgid "&Project:" msgstr "" #: rc.cpp:277 rc.cpp:886 rc.cpp:2034 rc.cpp:2917 rc.cpp:3938 rc.cpp:4842 #, kde-format msgid "&Whiteboard:" msgstr "" #: rc.cpp:280 rc.cpp:889 rc.cpp:2037 rc.cpp:2920 rc.cpp:3941 rc.cpp:4845 #, kde-format msgid "" "Enter a label that describes the project. This may appear on the customer " "document." msgstr "" #: rc.cpp:283 rc.cpp:892 rc.cpp:2040 rc.cpp:2923 rc.cpp:3944 rc.cpp:4848 #, kde-format msgid "Postal &Address:" msgstr "" #: rc.cpp:286 rc.cpp:895 rc.cpp:2043 rc.cpp:2926 rc.cpp:3947 rc.cpp:4851 #, kde-format msgid "not selected" msgstr "" #: rc.cpp:289 rc.cpp:898 rc.cpp:2046 rc.cpp:2929 rc.cpp:3950 rc.cpp:4854 #, kde-format msgid "Select an addressee from the address books." msgstr "" #: rc.cpp:292 rc.cpp:901 rc.cpp:2049 rc.cpp:2932 rc.cpp:3953 rc.cpp:4857 #, kde-format msgid "select..." msgstr "" #: rc.cpp:295 rc.cpp:904 rc.cpp:2052 rc.cpp:2935 rc.cpp:3956 rc.cpp:4860 #, kde-format msgid "&Salutatory Address:" msgstr "" #: rc.cpp:298 rc.cpp:907 rc.cpp:2055 rc.cpp:2938 rc.cpp:3959 rc.cpp:4863 #, kde-format msgid "Customer:" msgstr "" #: rc.cpp:301 rc.cpp:910 rc.cpp:2058 rc.cpp:2941 rc.cpp:3962 rc.cpp:4866 #, kde-format msgid "&Entry Text on First Page:" msgstr "" #: rc.cpp:304 rc.cpp:733 rc.cpp:1157 rc.cpp:1588 rc.cpp:2061 rc.cpp:2432 #: rc.cpp:2944 rc.cpp:3348 rc.cpp:3514 rc.cpp:4271 rc.cpp:4418 rc.cpp:5178 #, kde-format msgid "Click to add a new document type to the list." msgstr "" #: rc.cpp:310 rc.cpp:1163 rc.cpp:2067 rc.cpp:2950 rc.cpp:3520 rc.cpp:4424 #, kde-format msgid "click to edit the selected document type name" msgstr "" #: rc.cpp:316 rc.cpp:739 rc.cpp:1169 rc.cpp:1594 rc.cpp:2073 rc.cpp:2438 #: rc.cpp:2956 rc.cpp:3354 rc.cpp:3526 rc.cpp:4277 rc.cpp:4430 rc.cpp:5184 #, kde-format msgid "click to remove the current document type" msgstr "" #: rc.cpp:322 rc.cpp:1175 rc.cpp:2079 rc.cpp:2962 rc.cpp:3532 rc.cpp:4436 #, kde-format msgid "Unique Document Number" msgstr "" #: rc.cpp:325 rc.cpp:1178 rc.cpp:2082 rc.cpp:2965 rc.cpp:3535 rc.cpp:4439 #, kde-format msgid "Number &Cycle:" msgstr "" #: rc.cpp:328 rc.cpp:337 rc.cpp:340 rc.cpp:724 rc.cpp:1181 rc.cpp:1190 #: rc.cpp:1193 rc.cpp:1579 rc.cpp:2085 rc.cpp:2094 rc.cpp:2097 rc.cpp:2423 #: rc.cpp:2968 rc.cpp:2977 rc.cpp:2980 rc.cpp:3339 rc.cpp:3538 rc.cpp:3547 #: rc.cpp:3550 rc.cpp:4262 rc.cpp:4442 rc.cpp:4451 rc.cpp:4454 rc.cpp:5169 #, kde-format msgid "example" msgstr "" #: rc.cpp:331 rc.cpp:1184 rc.cpp:2088 rc.cpp:2971 rc.cpp:3541 rc.cpp:4445 #, kde-format msgid "ident Template:" msgstr "" #: rc.cpp:334 rc.cpp:718 rc.cpp:1187 rc.cpp:1573 rc.cpp:2091 rc.cpp:2417 #: rc.cpp:2974 rc.cpp:3333 rc.cpp:3544 rc.cpp:4256 rc.cpp:4448 rc.cpp:5163 #, kde-format msgid "Example Id:" msgstr "" #: rc.cpp:343 rc.cpp:1196 rc.cpp:2100 rc.cpp:2983 rc.cpp:3553 rc.cpp:4457 #, kde-format msgid "Counter:" msgstr "" #: rc.cpp:346 rc.cpp:1199 rc.cpp:2103 rc.cpp:2986 rc.cpp:3556 rc.cpp:4460 #, kde-format msgid "&Edit Number Cycles..." msgstr "" #: rc.cpp:349 rc.cpp:1202 rc.cpp:2106 #, kde-format msgid "Template for PDF Creation" msgstr "" #: rc.cpp:352 rc.cpp:1205 #, kde-format msgid "&Template File" msgstr "" #: rc.cpp:355 rc.cpp:1208 rc.cpp:2115 rc.cpp:2998 rc.cpp:3568 rc.cpp:4472 #, kde-format msgid "W&atermark:" msgstr "" #: rc.cpp:358 rc.cpp:1211 rc.cpp:2121 rc.cpp:3001 rc.cpp:3571 rc.cpp:4475 #, kde-format msgid "no watermark" msgstr "" #: rc.cpp:361 rc.cpp:1214 rc.cpp:2124 rc.cpp:3004 rc.cpp:3574 rc.cpp:4478 #, kde-format msgid "on first page" msgstr "" #: rc.cpp:364 rc.cpp:1217 rc.cpp:2127 rc.cpp:3007 rc.cpp:3577 rc.cpp:4481 #, kde-format msgid "on all pages" msgstr "" #: rc.cpp:367 rc.cpp:1220 #, kde-format msgid "&Watermark File" msgstr "" #: rc.cpp:370 rc.cpp:1223 rc.cpp:1983 rc.cpp:2866 rc.cpp:3598 rc.cpp:4502 #, kde-format msgid "Calculation Parts Fix" msgstr "" #: rc.cpp:373 rc.cpp:1226 rc.cpp:1986 rc.cpp:2869 rc.cpp:3601 rc.cpp:4505 #, kde-format msgid "

        Fix Cost Parts

        " msgstr "" #: rc.cpp:376 rc.cpp:1229 rc.cpp:1989 rc.cpp:2872 rc.cpp:3604 rc.cpp:4508 #, kde-format msgid "Add a fix cost for one unit of the template:" msgstr "" #: rc.cpp:379 rc.cpp:808 rc.cpp:1232 rc.cpp:1529 rc.cpp:1992 rc.cpp:2528 #: rc.cpp:2875 rc.cpp:3432 rc.cpp:3607 rc.cpp:4346 rc.cpp:4511 rc.cpp:5253 #, kde-format msgid "&Label:" msgstr "" #: rc.cpp:382 rc.cpp:1235 rc.cpp:1995 rc.cpp:2878 rc.cpp:3610 rc.cpp:4514 #, kde-format msgid "describing text" msgstr "" #: rc.cpp:385 rc.cpp:1238 rc.cpp:1998 rc.cpp:2881 rc.cpp:3613 rc.cpp:4517 #, kde-format msgid "amortisation" msgstr "" #: rc.cpp:388 rc.cpp:680 rc.cpp:1241 rc.cpp:1511 rc.cpp:2001 rc.cpp:2211 #: rc.cpp:2884 rc.cpp:3106 rc.cpp:3616 rc.cpp:4218 rc.cpp:4520 rc.cpp:5125 #, kde-format msgid "&Amount:" msgstr "" #: rc.cpp:391 rc.cpp:1244 rc.cpp:2004 rc.cpp:2887 rc.cpp:3619 rc.cpp:4523 #, kde-format msgid "amount multiplier" msgstr "" #: rc.cpp:394 rc.cpp:1247 rc.cpp:2007 rc.cpp:2890 rc.cpp:3622 rc.cpp:4526 #, kde-format msgid "at &Price:" msgstr "" #: rc.cpp:397 rc.cpp:683 rc.cpp:1250 rc.cpp:1514 rc.cpp:2010 rc.cpp:2214 #: rc.cpp:2893 rc.cpp:3109 rc.cpp:3625 rc.cpp:4221 rc.cpp:4529 rc.cpp:5128 #, kde-format msgid "Price for one piece" msgstr "" #: rc.cpp:400 rc.cpp:1253 rc.cpp:2013 rc.cpp:2896 rc.cpp:3628 rc.cpp:4532 #, kde-format msgid "€" msgstr "" #: rc.cpp:403 rc.cpp:1256 rc.cpp:2133 rc.cpp:3028 rc.cpp:3652 rc.cpp:4556 #, kde-format msgid "Form" msgstr "" #: rc.cpp:406 rc.cpp:1259 rc.cpp:2136 rc.cpp:3031 rc.cpp:3655 rc.cpp:4559 #: tagtemplatesdialog.cpp:58 #, kde-format msgid "Name:" msgstr "" #: rc.cpp:409 rc.cpp:1262 rc.cpp:2139 rc.cpp:3034 rc.cpp:3658 rc.cpp:4562 #, kde-format msgid "Organization:" msgstr "" #: rc.cpp:412 rc.cpp:1265 rc.cpp:2142 rc.cpp:3037 rc.cpp:3661 rc.cpp:4565 #, kde-format msgid "Street:" msgstr "" #: rc.cpp:415 rc.cpp:1268 rc.cpp:2145 rc.cpp:3040 rc.cpp:3664 rc.cpp:4568 #, kde-format msgid "Post Code:" msgstr "" #: rc.cpp:418 rc.cpp:1271 rc.cpp:2148 rc.cpp:3043 rc.cpp:3667 rc.cpp:4571 #, kde-format msgid "City:" msgstr "" #: rc.cpp:421 rc.cpp:1274 rc.cpp:2151 rc.cpp:3046 rc.cpp:3670 rc.cpp:4574 #, kde-format msgid "Phone:" msgstr "" #: rc.cpp:424 rc.cpp:1277 rc.cpp:2154 rc.cpp:3049 rc.cpp:3673 rc.cpp:4577 #, kde-format msgid "Fax:" msgstr "" #: rc.cpp:427 rc.cpp:1280 rc.cpp:2157 rc.cpp:3052 rc.cpp:3676 rc.cpp:4580 #, kde-format msgid "Mobile Phone:" msgstr "" #: rc.cpp:430 rc.cpp:1283 rc.cpp:2160 rc.cpp:3055 rc.cpp:3679 rc.cpp:4583 #, kde-format msgid "EMail:" msgstr "" #: rc.cpp:433 rc.cpp:1286 rc.cpp:2163 rc.cpp:3058 rc.cpp:3682 rc.cpp:4586 #, kde-format msgid "Website:" msgstr "" #: rc.cpp:436 rc.cpp:1298 rc.cpp:2166 rc.cpp:3061 rc.cpp:3965 rc.cpp:4869 #, kde-format msgid "Import Document Items" msgstr "" #: rc.cpp:439 rc.cpp:1301 rc.cpp:2169 rc.cpp:3064 rc.cpp:3968 rc.cpp:4872 #, kde-format msgid "Import information" msgstr "" #: rc.cpp:442 rc.cpp:1304 rc.cpp:2172 rc.cpp:3067 rc.cpp:3971 rc.cpp:4875 #, kde-format msgid "Select a &File to import from:" msgstr "" #: rc.cpp:445 rc.cpp:1307 rc.cpp:2175 rc.cpp:3070 rc.cpp:3974 rc.cpp:4878 #, kde-format msgid "FixMe!" msgstr "" #: rc.cpp:448 rc.cpp:1310 rc.cpp:2178 rc.cpp:3073 rc.cpp:3977 rc.cpp:4881 #, kde-format msgid "Import &Schema:" msgstr "" #: rc.cpp:451 rc.cpp:1313 rc.cpp:2181 rc.cpp:3076 rc.cpp:3980 rc.cpp:4884 #, kde-format msgid "this is interesting information about the selected schema" msgstr "" #: rc.cpp:454 rc.cpp:1316 rc.cpp:2184 rc.cpp:3079 rc.cpp:3983 rc.cpp:4887 #, kde-format msgid "Insert all Items &after" msgstr "" #: rc.cpp:457 rc.cpp:481 rc.cpp:1319 rc.cpp:1352 rc.cpp:2187 rc.cpp:2241 #: rc.cpp:3082 rc.cpp:3136 rc.cpp:3986 rc.cpp:4010 rc.cpp:4890 rc.cpp:4914 #, kde-format msgid "Tags" msgstr "" #: rc.cpp:463 rc.cpp:1334 rc.cpp:2223 rc.cpp:3118 rc.cpp:3992 rc.cpp:4896 #, kde-format msgid "New Item Text" msgstr "" #: rc.cpp:466 rc.cpp:1337 rc.cpp:2226 rc.cpp:3121 rc.cpp:3995 rc.cpp:4899 #, kde-format msgid "&insert" msgstr "" #: rc.cpp:469 rc.cpp:1340 rc.cpp:2229 rc.cpp:3124 rc.cpp:3998 rc.cpp:4902 #, kde-format msgid "à" msgstr "" #: rc.cpp:472 rc.cpp:1343 rc.cpp:2232 rc.cpp:3127 rc.cpp:4001 rc.cpp:4905 #, kde-format msgid "&after item" msgstr "" #: rc.cpp:475 rc.cpp:1346 rc.cpp:2235 rc.cpp:3130 rc.cpp:4004 rc.cpp:4908 #, kde-format msgid "Keep this item as template for future documents" msgstr "" #: rc.cpp:478 rc.cpp:1349 rc.cpp:2238 rc.cpp:3133 rc.cpp:4007 rc.cpp:4911 #, kde-format msgid "save in &chapter" msgstr "" #: rc.cpp:490 rc.cpp:1361 rc.cpp:2250 rc.cpp:3157 rc.cpp:4019 rc.cpp:4923 #, kde-format msgid "Do Database Initialisation" msgstr "" #: rc.cpp:493 rc.cpp:1364 rc.cpp:2253 rc.cpp:3160 rc.cpp:4022 rc.cpp:4926 #, kde-format msgid "Do XML archiving of documents they're printed?" msgstr "" #: rc.cpp:496 rc.cpp:1367 rc.cpp:2256 rc.cpp:3163 rc.cpp:4025 rc.cpp:4929 #, kde-format msgid "" "Where Kraft stores the XML archive documents. If empty, KDEHOME/share/apps " "is used." msgstr "" #: rc.cpp:499 rc.cpp:1370 rc.cpp:2259 rc.cpp:3166 rc.cpp:4028 rc.cpp:4932 #, kde-format msgid "The local xml document storage path" msgstr "" #: rc.cpp:502 rc.cpp:1373 rc.cpp:2262 rc.cpp:3169 rc.cpp:4031 rc.cpp:4935 #, kde-format msgid "Default mail user agent. Set xdg for xdg-email" msgstr "" #: rc.cpp:505 rc.cpp:508 rc.cpp:1376 rc.cpp:1379 rc.cpp:2265 rc.cpp:2268 #: rc.cpp:3172 rc.cpp:3175 rc.cpp:4034 rc.cpp:4037 rc.cpp:4938 rc.cpp:4941 #, kde-format msgid "The default geometry of the document view dialog" msgstr "" #: rc.cpp:511 rc.cpp:1382 rc.cpp:2271 rc.cpp:3178 rc.cpp:4040 rc.cpp:4944 #, kde-format msgid "The current state of the portal" msgstr "" #: rc.cpp:514 rc.cpp:1385 rc.cpp:2274 rc.cpp:3181 rc.cpp:4043 rc.cpp:4947 #, kde-format msgid "The current geometry of the portal" msgstr "" #: rc.cpp:517 rc.cpp:1388 rc.cpp:2277 rc.cpp:3184 rc.cpp:4046 rc.cpp:4950 #, kde-format msgid "The current geometry of the new doc assistant" msgstr "" #: rc.cpp:520 rc.cpp:1391 rc.cpp:2280 rc.cpp:3187 rc.cpp:4049 rc.cpp:4953 #, kde-format msgid "The splitter position of the document view dialog" msgstr "" #: rc.cpp:523 rc.cpp:1394 rc.cpp:2283 rc.cpp:3190 rc.cpp:4052 rc.cpp:4956 #, kde-format msgid "The default size of the material catalog view" msgstr "" #: rc.cpp:526 rc.cpp:1397 rc.cpp:2286 rc.cpp:3193 rc.cpp:4055 rc.cpp:4959 #, kde-format msgid "The splitter setting for the doc assistant" msgstr "" #: rc.cpp:529 rc.cpp:1400 rc.cpp:2289 rc.cpp:3196 rc.cpp:4058 rc.cpp:4962 #, kde-format msgid "The window size of the template to document dialog for plants" msgstr "" #: rc.cpp:532 rc.cpp:1403 rc.cpp:2292 rc.cpp:3199 rc.cpp:4061 rc.cpp:4965 #, kde-format msgid "The window size of the template to document dialog" msgstr "" #: rc.cpp:535 rc.cpp:1406 rc.cpp:2295 rc.cpp:3202 rc.cpp:4064 rc.cpp:4968 #, kde-format msgid "The digest list column arrangement for the Latest-list" msgstr "" #: rc.cpp:538 rc.cpp:1409 rc.cpp:2298 rc.cpp:3205 rc.cpp:4067 rc.cpp:4971 #, kde-format msgid "The digest list column arrangement for the all-list" msgstr "" #: rc.cpp:541 rc.cpp:1412 rc.cpp:2301 rc.cpp:3208 rc.cpp:4070 rc.cpp:4974 #, kde-format msgid "The digest list column arrangement for timeline" msgstr "" #: rc.cpp:544 rc.cpp:1415 rc.cpp:2304 rc.cpp:3211 rc.cpp:4073 rc.cpp:4977 #, kde-format msgid "The sizes of the slider in the address picker Widget" msgstr "" #: rc.cpp:547 rc.cpp:1418 rc.cpp:2307 rc.cpp:3214 rc.cpp:4076 rc.cpp:4980 #, kde-format msgid "The state of the treeview inside the address selector widget" msgstr "" #: rc.cpp:550 rc.cpp:1421 rc.cpp:2310 rc.cpp:3217 rc.cpp:4079 rc.cpp:4983 #, kde-format msgid "Size of the address select dialog" msgstr "" #: rc.cpp:553 rc.cpp:1424 rc.cpp:2313 rc.cpp:3220 rc.cpp:4082 rc.cpp:4986 #, kde-format msgid "State of the window of the material catalog" msgstr "" #: rc.cpp:556 rc.cpp:1427 rc.cpp:2316 rc.cpp:3223 rc.cpp:4085 rc.cpp:4989 #, kde-format msgid "Geometry of the material catalog" msgstr "" #: rc.cpp:559 rc.cpp:1430 rc.cpp:2319 rc.cpp:3226 rc.cpp:4088 rc.cpp:4992 #, kde-format msgid "State of the header of the material catalog" msgstr "" #: rc.cpp:562 rc.cpp:1433 rc.cpp:2322 rc.cpp:3229 rc.cpp:4091 rc.cpp:4995 #, kde-format msgid "State of the window of the template catalog" msgstr "" #: rc.cpp:565 rc.cpp:1436 rc.cpp:2325 rc.cpp:3232 rc.cpp:4094 rc.cpp:4998 #, kde-format msgid "Geometry the template catalog" msgstr "" #: rc.cpp:568 rc.cpp:1439 rc.cpp:2328 rc.cpp:3235 rc.cpp:4097 rc.cpp:5001 #, kde-format msgid "State of the header of the template catalog" msgstr "" #: rc.cpp:571 rc.cpp:1442 rc.cpp:2331 rc.cpp:3238 rc.cpp:4100 rc.cpp:5004 #, kde-format msgid "" "Default percentage the sale price for a material should be higher than its " "purchase price" msgstr "" #: rc.cpp:574 rc.cpp:1445 rc.cpp:2334 rc.cpp:3241 rc.cpp:4103 rc.cpp:5007 #, kde-format msgid "The name of the last selected chapter in the catalog" msgstr "" #: rc.cpp:577 rc.cpp:1448 rc.cpp:2337 rc.cpp:3244 rc.cpp:4106 rc.cpp:5010 #, kde-format msgid "The complete filename of the trml2pdf binary" msgstr "" #: rc.cpp:580 rc.cpp:1451 rc.cpp:2340 rc.cpp:3247 rc.cpp:4109 rc.cpp:5013 #, kde-format msgid "The path to the output directory for document pdfs" msgstr "" #: rc.cpp:583 rc.cpp:1454 rc.cpp:2343 rc.cpp:3250 rc.cpp:4112 rc.cpp:5016 #, kde-format msgid "The last created doc type." msgstr "" #: rc.cpp:586 rc.cpp:1457 rc.cpp:2346 rc.cpp:3253 rc.cpp:4115 rc.cpp:5019 #, kde-format msgid "The date format for print." msgstr "" #: rc.cpp:589 rc.cpp:1460 rc.cpp:2349 rc.cpp:3256 rc.cpp:4118 rc.cpp:5022 #, kde-format msgid "The greeting below on the document footer." msgstr "" #: rc.cpp:592 rc.cpp:1463 rc.cpp:2352 rc.cpp:3259 rc.cpp:4121 rc.cpp:5025 #, kde-format msgid "The salut message on the document header." msgstr "" #: rc.cpp:595 rc.cpp:1466 rc.cpp:2355 rc.cpp:3262 rc.cpp:4124 rc.cpp:5028 #, kde-format msgid "" "The name of the catalog chapter where to store new templates in by default" msgstr "" #: rc.cpp:598 rc.cpp:1469 rc.cpp:2358 rc.cpp:3265 rc.cpp:4127 rc.cpp:5031 #, kde-format msgid "The name of the last used import schema for items." msgstr "" #: rc.cpp:601 rc.cpp:1472 rc.cpp:2361 rc.cpp:3268 rc.cpp:4130 rc.cpp:5034 #, kde-format msgid "The name of the last used input file for items." msgstr "" #: rc.cpp:604 rc.cpp:1475 rc.cpp:2364 rc.cpp:3271 rc.cpp:4133 rc.cpp:5037 #, kde-format msgid "" "User name as reference to the KAddressbook to identify 'my' address " "(DEPRECATED)." msgstr "" #: rc.cpp:607 rc.cpp:1478 rc.cpp:2367 rc.cpp:3274 rc.cpp:4136 rc.cpp:5040 #, kde-format msgid "" "UID of the user as reference to the KAddressbook to identify 'my' address." msgstr "" #: rc.cpp:610 rc.cpp:1481 rc.cpp:2370 rc.cpp:3286 rc.cpp:4148 rc.cpp:5052 #, kde-format msgid "The doc id template" msgstr "" #: rc.cpp:613 rc.cpp:1484 rc.cpp:2373 rc.cpp:3289 rc.cpp:4151 rc.cpp:5055 #, kde-format msgid "Localization on document level" msgstr "" #: rc.cpp:616 rc.cpp:1487 rc.cpp:2376 rc.cpp:3292 rc.cpp:4154 rc.cpp:5058 #, kde-format msgid "The tax default for new documents." msgstr "" #: rc.cpp:619 rc.cpp:1490 rc.cpp:2379 rc.cpp:3295 rc.cpp:4157 rc.cpp:5061 #, kde-format msgid "The label for alternative positions" msgstr "" #: rc.cpp:622 rc.cpp:625 rc.cpp:1493 rc.cpp:1496 rc.cpp:2382 rc.cpp:2385 #: rc.cpp:3298 rc.cpp:3301 rc.cpp:4160 rc.cpp:4163 rc.cpp:5064 rc.cpp:5067 #, kde-format msgid "The label for demand positions" msgstr "" #: rc.cpp:631 rc.cpp:1325 rc.cpp:2193 rc.cpp:3088 rc.cpp:4169 rc.cpp:5076 #, kde-format msgid "Settings" msgstr "" #: rc.cpp:637 rc.cpp:1669 rc.cpp:2561 rc.cpp:3465 rc.cpp:4175 rc.cpp:5082 #, kde-format msgid "Edit Material" msgstr "" #: rc.cpp:640 rc.cpp:1672 rc.cpp:2564 rc.cpp:3468 rc.cpp:4178 rc.cpp:5085 #, kde-format msgid "Store in C&hapter" msgstr "" #: rc.cpp:646 rc.cpp:1678 rc.cpp:2570 rc.cpp:3474 rc.cpp:4184 rc.cpp:5091 #, kde-format msgid "Pac&kaged:" msgstr "" #: rc.cpp:649 rc.cpp:1681 rc.cpp:2573 rc.cpp:3477 rc.cpp:4187 rc.cpp:5094 #, kde-format msgid "per P&ackage" msgstr "" #: rc.cpp:652 rc.cpp:1684 rc.cpp:2576 rc.cpp:3480 rc.cpp:4190 rc.cpp:5097 #, kde-format msgid "Prices" msgstr "" #: rc.cpp:655 rc.cpp:1687 rc.cpp:2579 rc.cpp:3483 rc.cpp:4193 rc.cpp:5100 #, kde-format msgid "= Price of &Sale:" msgstr "" #: rc.cpp:658 rc.cpp:1690 rc.cpp:2582 rc.cpp:3486 rc.cpp:4196 rc.cpp:5103 #, kde-format msgid "pl&us" msgstr "" #: rc.cpp:662 rc.cpp:755 rc.cpp:1610 rc.cpp:1694 rc.cpp:2454 rc.cpp:2586 #: rc.cpp:3370 rc.cpp:3490 rc.cpp:4200 rc.cpp:4293 rc.cpp:5107 rc.cpp:5200 #, no-c-format, kde-format msgid "%" msgstr "" #: rc.cpp:665 rc.cpp:1697 rc.cpp:2589 rc.cpp:3493 rc.cpp:4203 rc.cpp:5110 #, kde-format msgid "&Purchase Price:" msgstr "" #: rc.cpp:668 rc.cpp:1499 rc.cpp:2199 rc.cpp:3094 rc.cpp:4206 rc.cpp:5113 #, kde-format msgid "Calculation Item Material" msgstr "" #: rc.cpp:671 rc.cpp:1502 rc.cpp:2202 rc.cpp:3097 rc.cpp:4209 rc.cpp:5116 #, kde-format msgid "

        Calculation Part 'Material'

        " msgstr "" #: rc.cpp:674 rc.cpp:1505 rc.cpp:2205 rc.cpp:3100 rc.cpp:4212 rc.cpp:5119 #, kde-format msgid "Add Material to the template calculation." msgstr "" #: rc.cpp:677 rc.cpp:1508 rc.cpp:2208 rc.cpp:3103 rc.cpp:4215 rc.cpp:5122 #, kde-format msgid "material" msgstr "" #: rc.cpp:686 rc.cpp:1517 rc.cpp:2217 rc.cpp:3112 rc.cpp:4224 rc.cpp:5131 #, kde-format msgid "unit" msgstr "" #: rc.cpp:689 rc.cpp:1544 rc.cpp:2388 rc.cpp:3304 rc.cpp:4227 rc.cpp:5134 #, kde-format msgid "" "Please enter the MySQL Database server settings. \n" "\n" "For detailed setup instructions for the MySQL to use with Kraft please check " "the Kraft website." msgstr "" #: rc.cpp:694 rc.cpp:1549 rc.cpp:2393 rc.cpp:3309 rc.cpp:4232 rc.cpp:5139 #, kde-format msgid "Database Host:" msgstr "" #: rc.cpp:697 rc.cpp:1552 rc.cpp:2396 rc.cpp:3312 rc.cpp:4235 rc.cpp:5142 #, kde-format msgid "Database Name:" msgstr "" #: rc.cpp:703 rc.cpp:1558 rc.cpp:2402 rc.cpp:3318 rc.cpp:4241 rc.cpp:5148 #, kde-format msgid "Password:" msgstr "" #: rc.cpp:706 rc.cpp:1561 rc.cpp:2405 rc.cpp:3321 rc.cpp:4244 rc.cpp:5151 #, kde-format msgid "

        Edit Number Cycles

        " msgstr "" #: rc.cpp:709 rc.cpp:1564 rc.cpp:2408 rc.cpp:3324 rc.cpp:4247 rc.cpp:5154 #, kde-format msgid "Number Cycle Details" msgstr "" #: rc.cpp:712 rc.cpp:1567 rc.cpp:2411 rc.cpp:3327 rc.cpp:4250 rc.cpp:5157 #, kde-format msgid "&Number Cycle:" msgstr "" #: rc.cpp:715 rc.cpp:1570 rc.cpp:2414 rc.cpp:3330 rc.cpp:4253 rc.cpp:5160 #, kde-format msgid "&Counter:" msgstr "" #: rc.cpp:721 rc.cpp:1576 rc.cpp:2420 rc.cpp:3336 rc.cpp:4259 rc.cpp:5166 #, kde-format msgid "ident &Template:" msgstr "" #: rc.cpp:727 rc.cpp:1582 rc.cpp:2426 rc.cpp:3342 rc.cpp:4265 rc.cpp:5172 #, kde-format msgid "&Select a number cycle and edit the details on the right:" msgstr "" #: rc.cpp:730 rc.cpp:1585 rc.cpp:2429 rc.cpp:3345 rc.cpp:4268 rc.cpp:5175 #, kde-format msgid "New Item" msgstr "" #: rc.cpp:736 rc.cpp:1591 rc.cpp:2435 rc.cpp:3351 rc.cpp:4274 rc.cpp:5181 #, kde-format msgid "add" msgstr "" #: rc.cpp:742 rc.cpp:1597 rc.cpp:2441 rc.cpp:3357 rc.cpp:4280 rc.cpp:5187 #, kde-format msgid "remove" msgstr "" #: rc.cpp:745 rc.cpp:1600 rc.cpp:2444 rc.cpp:3360 rc.cpp:4283 rc.cpp:5190 #, kde-format msgid "1." msgstr "" #: rc.cpp:748 rc.cpp:751 rc.cpp:1603 rc.cpp:1606 rc.cpp:2447 rc.cpp:2450 #: rc.cpp:3363 rc.cpp:3366 rc.cpp:4286 rc.cpp:4289 rc.cpp:5193 rc.cpp:5196 #, kde-format msgid "D" msgstr "" #: rc.cpp:758 rc.cpp:1613 rc.cpp:2457 rc.cpp:3373 rc.cpp:4296 rc.cpp:5203 #, kde-format msgid "of the sum of" msgstr "" #: rc.cpp:761 rc.cpp:1616 rc.cpp:2460 rc.cpp:3376 rc.cpp:4299 rc.cpp:5206 #, kde-format msgid "" "Please enter the SQLite Database Settings.\n" "\n" "Pick a filename to name the SQLite database file or leave the default " "setting." msgstr "" #: rc.cpp:766 rc.cpp:1621 rc.cpp:2465 rc.cpp:3381 rc.cpp:4304 rc.cpp:5211 #, kde-format msgid "store the database file at default place." msgstr "" #: rc.cpp:769 rc.cpp:1624 rc.cpp:2468 rc.cpp:3384 rc.cpp:4307 rc.cpp:5214 #, kde-format msgid "select a file name:" msgstr "" #: rc.cpp:772 rc.cpp:1627 rc.cpp:2480 rc.cpp:3396 rc.cpp:4310 rc.cpp:5217 #, kde-format msgid "

        Add a Tax Rate

        " msgstr "" #: rc.cpp:775 rc.cpp:1630 rc.cpp:2483 rc.cpp:3399 rc.cpp:4313 rc.cpp:5220 #, kde-format msgid "Start-Date:" msgstr "" #: rc.cpp:778 rc.cpp:1633 rc.cpp:2486 rc.cpp:3402 rc.cpp:4316 rc.cpp:5223 #, kde-format msgid "&Reduced Tax Rate:" msgstr "" #: rc.cpp:781 rc.cpp:1636 rc.cpp:2489 rc.cpp:3405 rc.cpp:4319 rc.cpp:5226 #, kde-format msgid "&Full Tax Rate:" msgstr "" #: rc.cpp:784 rc.cpp:1639 rc.cpp:2492 rc.cpp:3408 rc.cpp:4322 rc.cpp:5229 #, kde-format msgid "Edit Document Text Template" msgstr "" #: rc.cpp:787 rc.cpp:1642 rc.cpp:2495 rc.cpp:3411 rc.cpp:4325 rc.cpp:5232 #, kde-format msgid "&Name:" msgstr "" #: rc.cpp:790 rc.cpp:1645 rc.cpp:2498 rc.cpp:3414 rc.cpp:4328 rc.cpp:5235 #, kde-format msgid "displayed as" msgstr "" #: rc.cpp:793 rc.cpp:1648 rc.cpp:2501 rc.cpp:3417 rc.cpp:4331 rc.cpp:5238 #, kde-format msgid "in doc type" msgstr "" #: rc.cpp:796 rc.cpp:1651 rc.cpp:2504 rc.cpp:3420 rc.cpp:4334 rc.cpp:5241 #, kde-format msgid "&Text:" msgstr "" #: rc.cpp:799 rc.cpp:1520 rc.cpp:2519 rc.cpp:3423 rc.cpp:4337 rc.cpp:5244 #, kde-format msgid "Calculation Item Time" msgstr "" #: rc.cpp:802 rc.cpp:1523 rc.cpp:2522 rc.cpp:3426 rc.cpp:4340 rc.cpp:5247 #, kde-format msgid "

        Calculation Part 'Time'

        " msgstr "" #: rc.cpp:805 rc.cpp:1526 rc.cpp:2525 rc.cpp:3429 rc.cpp:4343 rc.cpp:5250 #, kde-format msgid "" "Calculate time efforts here for one unit of the template.
        Note that the " "costs may depend on a global hourly rate." msgstr "" #: rc.cpp:811 rc.cpp:1532 rc.cpp:2531 rc.cpp:3435 rc.cpp:4349 rc.cpp:5256 #, kde-format msgid "Work" msgstr "" #: rc.cpp:814 rc.cpp:1535 rc.cpp:2534 rc.cpp:3438 rc.cpp:4352 rc.cpp:5259 #, kde-format msgid "&Time Effort:" msgstr "" #: rc.cpp:817 rc.cpp:1538 rc.cpp:2537 rc.cpp:3441 rc.cpp:4355 rc.cpp:5262 #, kde-format msgid "&Hourly Rate:" msgstr "" #: rc.cpp:820 rc.cpp:1541 rc.cpp:2540 rc.cpp:3444 rc.cpp:4358 rc.cpp:5265 #, kde-format msgid "Apply the &global hourly rate" msgstr "" #: rc.cpp:823 rc.cpp:1654 rc.cpp:2543 rc.cpp:3447 rc.cpp:4361 rc.cpp:5268 #, kde-format msgid "

        Add a unit

        " msgstr "" #: rc.cpp:826 rc.cpp:1657 rc.cpp:2546 rc.cpp:3450 rc.cpp:4364 rc.cpp:5271 #, kde-format msgid "Unit short" msgstr "" #: rc.cpp:829 rc.cpp:1660 rc.cpp:2549 rc.cpp:3453 rc.cpp:4367 rc.cpp:5274 #, kde-format msgid "Unit long" msgstr "" #: rc.cpp:832 rc.cpp:1663 rc.cpp:2552 rc.cpp:3456 rc.cpp:4370 rc.cpp:5277 #, kde-format msgid "Unit plural short" msgstr "" #: rc.cpp:835 rc.cpp:1666 rc.cpp:2555 rc.cpp:3459 rc.cpp:4373 rc.cpp:5280 #, kde-format msgid "Unit plural long" msgstr "" #: rc.cpp:838 rc.cpp:1700 rc.cpp:2592 rc.cpp:3496 rc.cpp:4379 rc.cpp:5286 #, kde-format msgid "" "This step checks if the database schema version is sufficient for this " "version of Kraft. \n" "\n" "In case it is not, the schema is updated automatically.\n" msgstr "" #: rc.cpp:853 rc.cpp:1715 rc.cpp:2607 rc.cpp:3511 rc.cpp:4394 rc.cpp:5301 #, kde-format msgid "Upgrade not yet started" msgstr "" #: rc.cpp:856 rc.cpp:1718 rc.cpp:2471 rc.cpp:3387 rc.cpp:4397 rc.cpp:5304 #, kde-format msgid "

        Add a Wage group

        " msgstr "" #: rc.cpp:859 rc.cpp:1721 rc.cpp:2474 rc.cpp:3390 rc.cpp:4400 rc.cpp:5307 #, kde-format msgid "Group name" msgstr "" #: rc.cpp:862 rc.cpp:1724 rc.cpp:2477 rc.cpp:3393 rc.cpp:4403 rc.cpp:5310 #, kde-format msgid "Wage" msgstr "" #: rc.cpp:2109 rc.cpp:2118 rc.cpp:2995 rc.cpp:3019 rc.cpp:3025 rc.cpp:3565 #: rc.cpp:3589 rc.cpp:3595 rc.cpp:4469 rc.cpp:4493 rc.cpp:4499 #, kde-format msgid "select" msgstr "" #: rc.cpp:2112 rc.cpp:3016 rc.cpp:3586 rc.cpp:4490 #, kde-format msgid "&Watermark File:" msgstr "" #: rc.cpp:2130 rc.cpp:2992 rc.cpp:3562 rc.cpp:4466 #, kde-format msgid "&Template File:" msgstr "" #: rc.cpp:2507 rc.cpp:3145 rc.cpp:4406 rc.cpp:5313 #, kde-format msgid "Dialog" msgstr "" #: rc.cpp:2510 rc.cpp:3148 rc.cpp:4409 rc.cpp:5316 #, kde-format msgid "" "

        XRechnung Additional Data

        " msgstr "" #: rc.cpp:2513 rc.cpp:3151 rc.cpp:4412 rc.cpp:5319 #, kde-format msgid "Due Date:" msgstr "" #: rc.cpp:2516 rc.cpp:3154 rc.cpp:4415 rc.cpp:5322 #, kde-format msgid "Buyer Reference:" msgstr "" #: rc.cpp:2558 rc.cpp:3462 rc.cpp:4376 rc.cpp:5283 #, kde-format msgid "Unit ECE20" msgstr "" #: rc.cpp:2989 rc.cpp:3559 rc.cpp:4463 #, kde-format msgid "PDF Creation and Postprocessing" msgstr "" #: rc.cpp:3010 rc.cpp:3580 rc.cpp:4484 #, kde-format msgid "alternating (3 pages)" msgstr "" #: rc.cpp:3013 rc.cpp:3583 rc.cpp:4487 #, kde-format msgid "different first and last page (3 pages)" msgstr "" #: rc.cpp:3022 rc.cpp:3592 rc.cpp:4496 #, kde-format msgid "Append PDF:" msgstr "" #: rc.cpp:3277 rc.cpp:4139 rc.cpp:5043 #, kde-format msgid "Bank account name." msgstr "" #: rc.cpp:3280 rc.cpp:4142 rc.cpp:5046 #, kde-format msgid "Business Identifier Code\" (BIC) of the bank." msgstr "" #: rc.cpp:3283 rc.cpp:4145 rc.cpp:5049 #, kde-format msgid "IBAN of the bank account." msgstr "" #: rc.cpp:5070 #, kde-format msgid "Display the EPC Code as long as the doc sum is below this value." msgstr "" #: setupassistant.cpp:36 #, kde-format msgid "Welcome to the Kraft Setup Assistant" msgstr "" #: setupassistant.cpp:55 #, kde-format msgid "Select the Database Backend" msgstr "" #: setupassistant.cpp:92 #, kde-format msgid "Sqlite File Name" msgstr "" #: setupassistant.cpp:146 #, kde-format msgid "MySql Detail Information" msgstr "" #: setupassistant.cpp:188 #, kde-format msgid "Create Database" msgstr "" #: setupassistant.cpp:210 setupassistant.cpp:223 #, kde-format msgid "0/%1" msgstr "" #: setupassistant.cpp:242 setupassistant.cpp:252 setupassistant.cpp:290 #, kde-format msgid "%1/%2" msgstr "" #: setupassistant.cpp:265 #, kde-format msgid "Upgrade the Database" msgstr "" #: setupassistant.cpp:314 #, kde-format msgid "Your Company Address" msgstr "" #: setupassistant.cpp:319 #, kde-format msgid "" "Select your companies address either from the address book or enter it " "manually. It is set as a consigner on the documents." msgstr "" #: setupassistant.cpp:328 #, kde-format msgid "Select from Addressbook" msgstr "" #: setupassistant.cpp:418 #, kde-format msgid "Final Status" msgstr "" #: setupassistant.cpp:512 #, kde-format msgid "" "

        Can't connect to your database. Are you sure your credentials are correct " "and the database exists?

        " msgstr "" #: setupassistant.cpp:523 #, kde-format msgid "

        Can't open your database file, check the permissions and such." msgstr "" #: setupassistant.cpp:532 #, kde-format msgid "" "

        The database is already existing, no action needs to be taken here.

        Please hit next to proceed.

        " msgstr "" #: setupassistant.cpp:581 #, kde-format msgid "

        The database setup was successfully completed.

        " msgstr "" #: setupassistant.cpp:582 #, kde-format msgid "

        You can start to work with Kraft now. Please do not forget to

        " msgstr "" #: setupassistant.cpp:584 #, kde-format msgid "
      • adjust various settings in the Kraft Preferences dialog.
      • " msgstr "" #: setupassistant.cpp:585 #, kde-format msgid "
      • Check the Catalog chapter list.
      • " msgstr "" #: setupassistant.cpp:586 #, kde-format msgid "
      • Make your business and have fun.
      • " msgstr "" #: setupassistant.cpp:588 #, kde-format msgid "" "

        If you press Finish now, the new database configuration is stored " "in Krafts configuration.

        " msgstr "" #: setupassistant.cpp:604 #, kde-format msgid "" "The Database can not be connected. Please check the database credentials." msgstr "" #: setupassistant.cpp:610 #, kde-format msgid "The database core tables do not exist. Please check initial setup." msgstr "" #: setupassistant.cpp:617 #, kde-format msgid "Database is up to date. No upgrade is required." msgstr "" #: setupassistant.cpp:622 #, kde-format msgid "Parse Update Commands..." msgstr "" #: setupassistant.cpp:665 #, kde-format msgid "The Upgrade failed!" msgstr "" #: setupassistant.cpp:667 #, kde-format msgid "The Upgrade succeeded, the current schema version is %1!" msgstr "" #: setupassistant.cpp:680 #, kde-format msgid "" "The Database can not be connected. Please check the database credentials!" msgstr "" #: setupassistant.cpp:686 #, kde-format msgid "Parse Create Commands..." msgstr "" #: setupassistant.cpp:694 #, kde-format msgid "Parse database fillup commands..." msgstr "" #: setupassistant.cpp:707 #, kde-format msgid "Processing database creation commands..." msgstr "" #: setupassistant.cpp:724 #, kde-format msgid "Process database fillup commands..." msgstr "" #: setupassistant.cpp:734 #, kde-format msgid "Successfully finished commands." msgstr "" #: setupassistant.cpp:736 #, kde-format msgid "Failed to perform all commands." msgstr "" #: setupassistant.cpp:780 #, kde-format msgid "" "This assistant guides you through the basic settings of your Kraft " "installation." msgstr "" #: setupassistant.cpp:790 #, kde-format msgid "There was no database configuration found." msgstr "" #: setupassistant.cpp:792 #, kde-format msgid "A valid current database configuration file was found." msgstr "" #: setupassistant.cpp:814 #, kde-format msgid "The database schema version is too low. It will be updated." msgstr "" #: setupassistant.cpp:817 #, kde-format msgid "The current database schema version is too high. Leaving untouched! " msgstr "" #: setupassistant.cpp:824 #, kde-format msgid "" "

        The database can be opened, but does not contain valid content.

        A " "new database can be created automatically from scratch.

        " msgstr "" #: setupassistant.cpp:831 #, kde-format msgid "

        Kraft failed to connect to the configured database.

        " msgstr "" #: setupassistant.cpp:833 #, kde-format msgid "

        Please check the database server setup and restart Kraft to connect." msgstr "" #: setupassistant.cpp:835 #, kde-format msgid "

        Please check the database file." msgstr "" #: setupassistant.cpp:837 #, kde-format msgid "or create a new database by hitting next.

        " msgstr "" #: setupassistant.cpp:845 #, kde-format msgid "

        Please hit next and follow the instructions.

        " msgstr "" #: tagtemplatesdialog.cpp:47 #, kde-format msgid "Edit Tag Template" msgstr "" #: tagtemplatesdialog.cpp:54 #, kde-format msgid "Edit a Tag Template" msgstr "" #: tagtemplatesdialog.cpp:55 #, kde-format msgid "Adjust settings for name, color and description." msgstr "" #: tagtemplatesdialog.cpp:63 #, kde-format msgid "Description:" msgstr "" #: tagtemplatesdialog.cpp:69 #, kde-format msgid "Associated Color:" msgstr "" #: tagtemplatesdialog.cpp:141 #, kde-format msgid "Add, edit and remove tag templates for use in the documents." msgstr "" #: tagtemplatesdialog.cpp:165 #, kde-format msgid "Add..." msgstr "" #: tagtemplatesdialog.cpp:167 #, kde-format msgid "Edit..." msgstr "" #: tagtemplatesdialog.cpp:170 #, kde-format msgid "Delete..." msgstr "" #: tagtemplatesdialog.cpp:223 #, kde-format msgid "Do you really want to delete the template?" msgstr "" #: taxeditdialog.cpp:36 #, kde-format msgid "Edit Tax Rates" msgstr "" #: templkatalogview.cpp:101 #, kde-format msgid "" msgstr "" #: templkataloglistview.cpp:47 #, kde-format msgid "Calc. Type" msgstr "" #: templkataloglistview.cpp:54 #, kde-format msgid "Template Catalog" msgstr "" #: textselection.cpp:42 #, kde-format msgid "Template Collection" msgstr "" #: textselection.cpp:100 #, kde-format msgid "Template Actions" msgstr "" #: textselection.cpp:129 #, kde-format msgid "This is the standard text used in new documents." msgstr "" #: textselection.cpp:138 #, kde-format msgid "%1 Templates for %2" msgstr "" #: textselection.cpp:146 #, kde-format msgid "" "There is no %1 template text available for document type %2.
        Click the " "add-button below to create one." msgstr "" #: textselection.cpp:201 #, kde-format msgid "&Use in Document" msgstr "" #: texteditdialog.cpp:42 #, kde-format msgid "Edit Text Templates" msgstr "" #: texteditdialog.cpp:62 #, kde-format msgid "Edit %1 Template" msgstr "" #: texttemplate.cpp:103 #, kde-format msgid "Failed to open template source" msgstr "" #: texttemplateinterface.cpp:53 #, kde-format msgid "No file name given for template" msgstr "" #: texttemplateinterface.cpp:61 #, kde-format msgid "Could not find template file %1" msgstr "" #: timecalcpart.cpp:82 #, kde-format msgid "Minutes" msgstr "" #: timecalcpart.cpp:84 #, kde-format msgid "Hours" msgstr "" #: timecalcpart.cpp:86 #, kde-format msgid "Seconds" msgstr "" kraft-1.1/po/nl/000077500000000000000000000000001450127457600135245ustar00rootroot00000000000000kraft-1.1/po/nl/kraft.po000066400000000000000000003422531450127457600152040ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # # Translators: # Ronald Stroethoff , 2023 # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-09-10 18:34+0200\n" "PO-Revision-Date: 2018-10-31 21:56+0000\n" "Last-Translator: Ronald Stroethoff , 2023\n" "Language-Team: Dutch (Netherlands) (https://app.transifex.com/kraftproject/teams/93132/nl_NL/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: nl_NL\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: models/docbasemodel.cpp:32 docdigestdetailview.cpp:413 #, kde-format msgid "Date" msgstr "Datum" #: models/docbasemodel.cpp:33 #, kde-format msgid "Doc. Number" msgstr "Doc.nummer" #: models/docbasemodel.cpp:34 #, kde-format msgid "Doc. Type" msgstr "Doc.type" #: models/docbasemodel.cpp:35 docdigestdetailview.cpp:418 #, kde-format msgid "Whiteboard" msgstr "Whiteboard" #: models/docbasemodel.cpp:36 #, kde-format msgid "Client Id" msgstr "Klant ID" #: models/docbasemodel.cpp:37 #, kde-format msgid "Last modified" msgstr "Laatst wijziging" #: models/docbasemodel.cpp:38 #, kde-format msgid "Creation date" msgstr "Aanmaakdatum" #: models/docbasemodel.cpp:39 docdigestdetailview.cpp:423 #, kde-format msgid "Project" msgstr "Project" #: models/docbasemodel.cpp:40 #, kde-format msgid "Client Address" msgstr "Adres klant" #: models/docbasemodel.cpp:41 #, kde-format msgid "Client" msgstr "Klant" #: models/docbasemodel.cpp:109 #, kde-format msgid "Looking up address" msgstr "Bezig met het opzoeken van het adres" #: models/docbasemodel.cpp:111 #, kde-format msgid "Lookup started" msgstr "bezig met opzoeken" #: documentman.cpp:93 #, kde-format msgctxt "" "Text to be inserted into a doc, if the sum of another doc needs to be " "substracted ie. in a final invoice if there was a partial invoice before%1 " "is substited by the doc type, %2 by the id of the predecessor doc." msgid "Substract sum from %1 %2" msgstr "Bedrag te verminderen op %1 %2" #: katalog.cpp:137 #, kde-format msgid "not found" msgstr "Niet gevonden" #: addeditchapterdialog.cpp:35 #, kde-format msgid "Add/Edit Catalog Chapter" msgstr "Map in catalogus toevoegen/bewerken" #: addeditchapterdialog.cpp:41 #, kde-format msgid "Create a new Catalog Chapter" msgstr "Nieuwe map in de catalogus aanmaken" #: addeditchapterdialog.cpp:45 #, kde-format msgid "Chapter Name:" msgstr "Map-naam:" #: addeditchapterdialog.cpp:49 #, kde-format msgid "Chapter Description:" msgstr "Omschrijving van map:" #: addeditchapterdialog.cpp:76 #, kde-format msgid "Create new Catalog Chapter below chapter %1" msgstr "Een nieuwe catalogus-map in map %1 aanmaken" #: addeditchapterdialog.cpp:83 #, kde-format msgid "Edit name and description of chapter %1" msgstr "Naam en beschrijving van map %1 bewerken" #: kraftdoc.cpp:160 #, kde-format msgctxt "First argument is the doctype, like Invoice, followed by the ID" msgid "%1 (Id %2)" msgstr "%1 (Id %2)" #: kraftdoc.cpp:308 #, kde-format msgctxt "Document part header" msgid "Header" msgstr "Briefhoofd" #: kraftdoc.cpp:310 #, kde-format msgctxt "Document part footer" msgid "Footer" msgstr "Voettekst" #: kraftdoc.cpp:312 #, kde-format msgctxt "Document part containing the items" msgid "Items" msgstr "Items" #: kraftdoc.cpp:314 #, kde-format msgid "Unknown document part" msgstr "Onbekend documentgedeelte" #: defaultprovider.cpp:63 doctext.cpp:80 positionviewwidget.cpp:418 #, kde-format msgid "Unknown" msgstr "Onbekend" #: docassistant.cpp:52 #, kde-format msgid "Show &Templates" msgstr "Document tonen" #: docassistant.cpp:57 #, kde-format msgid "Show mask to create or select templates to be used in the document" msgstr "" "Filter tonen voor het creëren of selecteren van in dit document gebruikte \n" "sjablonen" #: docassistant.cpp:121 #, kde-format msgid "Add a template to the document" msgstr "Voeg een sjabloon toe aan het document" #: docassistant.cpp:128 #, kde-format msgid "Insert the template to the document" msgstr "Vervang tekst in document door sjabloon" #: docassistant.cpp:136 #, kde-format msgid "Create a new template" msgstr "Nieuw sjabloon aanmaken" #: docassistant.cpp:143 #, kde-format msgid "Edit the current template" msgstr "Dit sjabloon bewerken" #: docassistant.cpp:150 #, kde-format msgid "Delete the current template" msgstr "Dit sjabloon verwijderen" #: docassistant.cpp:319 #, kde-format msgid "" "Do you really want to delete the template permanently?\n" "It can not be recovered." msgstr "" "Wilt u het sjabloon permanent verwijderen? Er is geen methode om het " "sjabloon terug te halen!" #: addressselectorwidget.cpp:219 #, kde-format msgid "Name" msgstr "Naam" #: addressselectorwidget.cpp:221 #, kde-format msgid "Address" msgstr "Adres" #: addressselectorwidget.cpp:288 filterheader.cpp:40 #, kde-format msgid "&Search:" msgstr "&Zoeken:" #: addressselectorwidget.cpp:325 #, kde-format msgid "Edit Contact..." msgstr "Contactpersoon bewerken..." #: addressselectorwidget.cpp:326 #, kde-format msgid "Edit the currently selected contact" msgstr "Deze contactpersoon bewerken" #: addressselectorwidget.cpp:329 #, kde-format msgid "New Contact..." msgstr "Nieuw contactpersoon..." #: addressselectorwidget.cpp:330 #, kde-format msgid "Create a new Contact" msgstr "Nieuw contactpersoon aanmaken" #: docpostcard.cpp:33 #, kde-format msgid "Document Overview" msgstr "Overzicht documenten" #: docpostcard.cpp:125 #, kde-format msgid "Netto:" msgstr "Netto:" #: docpostcard.cpp:136 docpostcard.cpp:143 #, kde-format msgid "+ %1% Tax:" msgstr "+ %1% BTW:" #: docpostcard.cpp:149 #, kde-format msgid "Sum Tax:" msgstr "Totaal belasting:" #: docpostcard.cpp:154 #, kde-format msgid "Total:" msgstr "Totaal:" #: docpostcard.cpp:246 #, kde-format msgid "%1 Items" msgstr "%1 Items" #: docpostcard.cpp:248 #, kde-format msgid "%1 Items, netto %2" msgstr "%1 Items, netto %2" #: archdoc.cpp:65 #, kde-format msgid "%1 for %2 (Id %3)" msgstr "%1 voor %2 (ID %3)" #: doctext.cpp:61 #, kde-format msgid "Standard" msgstr "Standaard" #: doctext.cpp:76 #, kde-format msgid "Header Text" msgstr "Tekst in briefhoofd" #: doctext.cpp:77 #, kde-format msgid "Footer Text" msgstr "Voettekst" #: doctext.cpp:78 #, kde-format msgid "Items" msgstr "Items" #: alldocsview.cpp:64 #, kde-format msgid "All documents" msgstr "Alle documenten" #: alldocsview.cpp:65 #, kde-format msgid "Documents of last week" msgstr "Documenten van laatste week" #: alldocsview.cpp:66 #, kde-format msgid "Documents of last month" msgstr "Documenten van laatste maand" #: alldocsview.cpp:72 #, kde-format msgid "&Show: " msgstr "&Tonen" #: alldocsview.cpp:79 #, kde-format msgid "&Search: " msgstr "&Zoeken" #: alldocsview.cpp:134 portal.cpp:305 portal.cpp:306 rc.cpp:634 rc.cpp:1328 #: rc.cpp:2196 rc.cpp:3091 rc.cpp:4172 rc.cpp:5079 #, kde-format msgid "Document Actions" msgstr "Document acties" #: documenttemplate.cpp:113 #, kde-format msgctxt "Sequence number printed on the document" msgid "No." msgstr "Nee" #: documenttemplate.cpp:114 #, kde-format msgctxt "Document item printed on the document" msgid "Item" msgstr "Item" #: documenttemplate.cpp:115 #, kde-format msgctxt "Abbrev. of Quantity printed on the document" msgid "Qty." msgstr "Aantal" #: documenttemplate.cpp:116 #, kde-format msgctxt "Unit printed on the document" msgid "Unit" msgstr "Eenheid" #: documenttemplate.cpp:117 #, kde-format msgctxt "Price of an item printed on the document" msgid "Price" msgstr "Prijs" #: documenttemplate.cpp:118 #, kde-format msgctxt "Printed on the document" msgid "Sum" msgstr "Totaal" #: documenttemplate.cpp:119 #, kde-format msgctxt "printed on the document" msgid "Net" msgstr "Netto" #: documenttemplate.cpp:120 #, kde-format msgctxt "Printed on the document" msgid "VAT" msgstr "BTW" #: documenttemplate.cpp:121 #, kde-format msgctxt "Document type, printed on the document" msgid "Type" msgstr "Type" #: documenttemplate.cpp:123 #, kde-format msgctxt "Printed on the document" msgid "Phone" msgstr "Tel." #: documenttemplate.cpp:124 #, kde-format msgctxt "Printed on the document" msgid "FAX" msgstr "FAX" #: documenttemplate.cpp:125 #, kde-format msgctxt "Printed on the document" msgid "Mobile" msgstr "GSM" #: documenttemplate.cpp:126 #, kde-format msgctxt "Printed on the document" msgid "Email" msgstr "Email" #: documenttemplate.cpp:127 #, kde-format msgctxt "Printed on the document" msgid "Website" msgstr "Website" #: documenttemplate.cpp:129 #, kde-format msgctxt "Printed on the document" msgid "Page" msgstr "Pagina" #: documenttemplate.cpp:130 #, kde-format msgctxt "Label of Predecessor document number" msgid "Predecessor-Doc" msgstr "Predecessor-Doc" #: documenttemplate.cpp:131 #, kde-format msgctxt "the 'of' in page X of Y" msgid "of" msgstr "van" #: documenttemplate.cpp:132 #, kde-format msgctxt "Document number on document" msgid "Document No." msgstr "Document Nr." #: documenttemplate.cpp:133 #, kde-format msgctxt "Date on document" msgid "Date" msgstr "Datum" #: documenttemplate.cpp:134 #, kde-format msgctxt "Project label" msgid "Project" msgstr "Project" #: documenttemplate.cpp:135 #, kde-format msgctxt "Customer ID on document" msgid "Customer Id" msgstr "Klant nummer" #: documenttemplate.cpp:200 #, kde-format msgctxt "" "Credit Transfer reason string, 1=DocType, 2=DocIdent, 3=Date, ie. Invoice " "2022-183 dated 2022-03-22" msgid "%1 %2 dated %3" msgstr "%1 %2 gedateerd %3" #: documenttemplate.cpp:321 #, kde-format msgid "" "Please note: This offer contains %1 alternative or demand positions, printed" " in italic font. These do not add to the overall sum." msgstr "" "Opmerking: in deze offerte komen %1 alternatieven of meerwerk-posten voor, " "deze zijn cursief gedrukt. Deze zijn niet bij het totaal bedrag opgeteld." #: documenttemplate.cpp:332 #, kde-format msgid "tax free items (%1 pcs.)" msgstr "belastingvrije items (%1 stuks.)" #: documenttemplate.cpp:338 #, kde-format msgid "items with reduced tax of %1% (%2 pcs.)" msgstr "items met het lage BTW van %1% (%2 stuks.)" #: documenttemplate.cpp:347 #, kde-format msgid "No label: items with full tax of %1% (%2 pcs.)" msgstr "Geen label: items zonder het hoge BTW van %1% (%2 stuks.)" #: documenttemplate.cpp:377 kraftview_ro.cpp:225 #, kde-format msgid "reduced VAT" msgstr "Hoge BTW" #: documenttemplate.cpp:385 kraftview_ro.cpp:197 kraftview_ro.cpp:234 #: rc.cpp:21 rc.cpp:931 rc.cpp:1769 rc.cpp:2652 rc.cpp:3703 rc.cpp:4607 #, kde-format msgid "VAT" msgstr "BTW" #: documenttemplate.cpp:439 #, kde-format msgid "Template to convert is not existing!" msgstr "Het te converteren sjabloon bestaat niet!" #: documenttemplate.cpp:442 #, kde-format msgid "Can not read template file!" msgstr "Kan het sjabloon niet openen!" #: flostempldialog.cpp:71 #, kde-format msgid "Create or Edit Template Items" msgstr "Wijzig of maak sjablonen aan" #: flostempldialog.cpp:213 flostempldialog.cpp:604 #, kde-format msgid "No" msgstr "Nee" #: flostempldialog.cpp:214 flostempldialog.cpp:604 #, kde-format msgid "Yes" msgstr "Ja" #: flostempldialog.cpp:251 #, kde-format msgid "Calculated Price: " msgstr "Berekende prijs: " #: flostempldialog.cpp:255 #, kde-format msgid "Manual Price: " msgstr "Handmatige prijs:" #: flostempldialog.cpp:260 #, kde-format msgid "(+%1%)" msgstr "(+%1%)" #: flostempldialog.cpp:264 #, kde-format msgid "%1%" msgstr "%1%" #: flostempldialog.cpp:266 #, kde-format msgid ": " msgstr ": " #: flostempldialog.cpp:388 #, kde-format msgid "Template Error" msgstr "Fout in sjabloon" #: flostempldialog.cpp:388 #, kde-format msgid "Saving of this template failed, sorry" msgstr "Opslaan van dit sjabloon is mislukt." #: flostempldialog.cpp:416 #, kde-format msgid "The template has been modified." msgstr "Sjabloon is gewijzigd" #: flostempldialog.cpp:417 #, kde-format msgid "Do you want to discard your changes?" msgstr "Wilt u echt uw wijzigingen annuleren?" #: flostempldialog.cpp:446 #, kde-format msgid "" "The catalog chapter was changed for this template.\n" "Do you really want to move the template to the new chapter?" msgstr "" "Voor deze sjabloon is de map in de catalogus gewijzigd.\n" "Wilt u de sjabloon naar de nieuwe map verplaatsen?" #: flostempldialog.cpp:448 #, kde-format msgid "Chapter Change" msgstr "Gewijzigde map" #: flostempldialog.h:104 #, kde-format msgid "Calculated material" msgstr "Berekende materialen" #: calcpart.cpp:98 #, kde-format msgid "Base" msgstr "Stam" #: catalogselection.cpp:50 #, kde-format msgid "Selected &Catalog: " msgstr "Geselecteerde &Catalogus: " #: catalogselection.cpp:159 #, kde-format msgid "Append to Document" msgstr "Achter document voegen" #: fixcalcdialog.cpp:36 #, kde-format msgid "Calculation Fix Item" msgstr "Vaste kosten berekenen" #: catalogtemplate.cpp:52 #, kde-format msgid "Manual Price" msgstr "Handmatige prijs" #: catalogtemplate.cpp:54 #, kde-format msgid "Calculated" msgstr "Berekend" #: catalogtemplate.cpp:56 #, kde-format msgid "AutoCalc" msgstr "AutoCalc" #: catalogtemplate.cpp:57 #, kde-format msgid "Err: Unknown type %d" msgstr "Fout: onbekend type %d" #: main.cpp:58 #, kde-format msgid "Open document with arch doc number " msgstr "Open document met arch doc nummer " #: main.cpp:59 #, kde-format msgid "Open Kraft in read only mode - document changes prohibited" msgstr "" "Open Kraft in alleen lezen modus - document wijzigen is niet toegestaan." #: templtopositiondialogbase.cpp:35 rc.cpp:460 rc.cpp:1331 rc.cpp:2220 #: rc.cpp:3115 rc.cpp:3989 rc.cpp:4893 #, kde-format msgid "Create Item from Template" msgstr "Item van sjabloon creëren" #: templtopositiondialogbase.cpp:51 #, kde-format msgid "the Header of the Document as first item" msgstr "Het briefhoofd van het document als eerste item" #: templtopositiondialogbase.cpp:58 importitemdialog.cpp:125 #, kde-format msgid "..." msgstr "..." #: portal.cpp:105 #, kde-format msgid "&Quit" msgstr "&Afsluiten" #: portal.cpp:110 #, kde-format msgid "&Cut" msgstr "K&nippen" #: portal.cpp:115 #, kde-format msgid "C&opy" msgstr "&Kopiëeren" #: portal.cpp:120 #, kde-format msgid "&Paste" msgstr "&Plakken" #: portal.cpp:125 #, kde-format msgid "&Settings" msgstr "&Instellingen" #: portal.cpp:130 #, kde-format msgid "&Create Document" msgstr "&Nieuw document" #: portal.cpp:135 #, kde-format msgid "&Copy Document" msgstr "&Kopieer document" #: portal.cpp:140 #, kde-format msgid "Create &Followup Document" msgstr "Creëer &opvolg document" #: portal.cpp:145 #, kde-format msgid "Print Document" msgstr "Document afdrukken" #: portal.cpp:150 #, kde-format msgid "Show Document" msgstr "Document tonen" #: portal.cpp:155 #, kde-format msgid "Edit Document" msgstr "Document bewerken" #: portal.cpp:160 #, kde-format msgid "Open Archived Document" msgstr "Open gearchiveerd document" #: portal.cpp:165 #, kde-format msgid "Mail Document" msgstr "Verzend document" #: portal.cpp:170 #, kde-format msgid "Export XRechnung" msgstr "XRechnung exporteren" #: portal.cpp:175 tagtemplatesdialog.cpp:135 tagtemplatesdialog.cpp:140 #, kde-format msgid "Edit Tag Templates" msgstr "Tag sjabloon bewerken" #: portal.cpp:180 #, kde-format msgid "Redo Initial Setup..." msgstr "De initiële aanmaak opnieuw uitvoeren..." #: portal.cpp:185 #, kde-format msgid "Kraft Handbook..." msgstr "Kraft Handboek.." #: portal.cpp:190 #, kde-format msgid "About Qt..." msgstr "Over Qt..." #: portal.cpp:195 #, kde-format msgid "About Kraft..." msgstr "Over Kraft..." #: portal.cpp:199 #, kde-format msgid "Quits the application" msgstr "Sluit het programma af" #: portal.cpp:201 #, kde-format msgid "Cuts the selected section and puts it to the clipboard" msgstr "Knipt de geselecteerde sectie uit en plaatst deze op het klembord" #: portal.cpp:202 #, kde-format msgid "Copies the selected section to the clipboard" msgstr "Kopieert de geselecteerde sectie naar het klembord" #: portal.cpp:203 #, kde-format msgid "Pastes the clipboard contents to current position" msgstr "Plakt de inhoud van het klembord op de huidige positie" #: portal.cpp:205 #, kde-format msgid "Creates a new Document" msgstr "Maakt een nieuw document aan" #: portal.cpp:206 #, kde-format msgid "Print and archive this Document" msgstr "Dit document afdrukken en archiveren" #: portal.cpp:207 #, kde-format msgid "Creates a new document which is a copy of the selected document" msgstr "Een nieuw document creëren als kopie van het geselecteerde document " #: portal.cpp:208 #, kde-format msgid "Create a followup document for the current document" msgstr "Creëert een opvolg document voor het huidige document" #: portal.cpp:209 #, kde-format msgid "Opens the document for editing" msgstr "Opent het document voor bewerken" #: portal.cpp:210 #, kde-format msgid "Opens a read only view on the document." msgstr "Opent het document alleen-lezen." #: portal.cpp:211 #, kde-format msgid "Send document per mail" msgstr "Document per email verzenden" #: portal.cpp:212 #, kde-format msgid "Export invoice in XRechnung XML format." msgstr "Exporteert rekening in XRechnung XML formaat." #: portal.cpp:213 #, kde-format msgid "" "Edit the available tag templates which can be assigned to document items." msgstr "De aan de documenten te koppelen beschikbare tags bewerken." #: portal.cpp:214 #, kde-format msgid "Configure the Database Kraft is working on." msgstr "Stel de database in waarmee Kraft werkt." #: portal.cpp:215 #, kde-format msgid "Open a viewer on an archived document" msgstr "Gearchiveerd document weergeven" #: portal.cpp:229 rc.cpp:484 rc.cpp:1355 rc.cpp:2244 rc.cpp:3139 rc.cpp:4013 #: rc.cpp:4917 #, kde-format msgid "&File" msgstr "Bestand" #: portal.cpp:233 #, kde-format msgid "&Edit" msgstr "Be&werken" #: portal.cpp:238 rc.cpp:628 rc.cpp:1322 rc.cpp:2190 rc.cpp:3085 rc.cpp:4166 #: rc.cpp:5073 #, kde-format msgid "&Document" msgstr "&Document" #: portal.cpp:253 #, kde-format msgid "Kraft" msgstr "Kraft" #: portal.cpp:256 #, kde-format msgid "&Preferences" msgstr "&Voorkeuren" #: portal.cpp:260 #, kde-format msgid "Toolbars" msgstr "Werkbalken" #: portal.cpp:266 #, kde-format msgid "&Help" msgstr "&Help" #: portal.cpp:354 #, kde-format msgid "Database not running" msgstr "Database is niet gestart." #: portal.cpp:355 #, kde-format msgid "" "Kraft was started in readonly mode, but the configured database can not be connected.\n" "\n" "Kraft will abort." msgstr "" "Kraft is gestart in alleen lezen modus, maar een verbinding met de gekozen database is niet mogelijk.\n" "\n" "Kraft zal stoppen." #: portal.cpp:371 #, kde-format msgid "" "Kraft can not connect to the specified MySQL server. Please check the Kraft " "database settings, check if the server is running and verify if a database " "with the name %1 exits!" msgstr "" "Kraft kon geen verbinding met de opgegeven MySQL-server maken. Controleer de" " database-instellingen van Kraft, controleer of de server is gestart en of " "een database met de naam %1 bestaat!" #: portal.cpp:375 #, kde-format msgid "" "The database with the name %1 does not exist on the database server. Please " "make sure the database exists and is accessible by the user running Kraft." msgstr "" "De database met de naam %1 is bij deze database server niet te vinden.\n" "Controleer of deze database bestaat en door de gebruiker die Kraft gebruikt, geopend kan worden." #: portal.cpp:379 #, kde-format msgid "" "The Qt database driver could not be loaded. That probably means, that they " "are not installed. Please make sure the Qt database packages are installed " "and try again." msgstr "" "De Qt database driver kon niet worden geladen. Dit houd waarschijnlijk in dat het niet is geïnstalleerd. Controleer of de Qt database pakketten zijn \n" "geïnstalleerd en probeer het daarna opnieuw." #: portal.cpp:383 #, kde-format msgid "There is a database problem: %1" msgstr "Er is een probleem met de database: %1" #: portal.cpp:401 #, kde-format msgid "Database Problem." msgstr "Probleem met de database." #: portal.cpp:413 #, kde-format msgid "Check commandline actions" msgstr "Opdrachten op de commando controleren" #: portal.cpp:503 #, kde-format msgid "Welcome to Kraft, %1" msgstr "Welkom bij Kraft, %1" #: portal.cpp:532 #, kde-format msgid "Creating new document..." msgstr "Bezig met het aanmaken van een nieuw document..." #: portal.cpp:558 #, kde-format msgctxt "" "Dialog title of the followup doc dialog, followed by the id of the source " "doc" msgid "Create follow up document for %1" msgstr "Creëer &opvolg document voor %1" #: portal.cpp:603 #, kde-format msgctxt "Title of the new doc dialog, %1 is the source doc id" msgid "Create new Document as Copy of %1" msgstr "Kopie van %1 als nieuw document creëren" #: portal.cpp:638 #, kde-format msgid "Opening document to view..." msgstr "Bezig met het openen van document om deze weer te geven..." #: portal.cpp:665 #, kde-format msgid "" "XRechnung Template file not set. Please check the application settings!" msgstr "" "XRechnung sjabloonbestand niet ingesteld. Controleer de instellingen van het" " programma!" #: portal.cpp:669 #, kde-format msgid "The XRechnung template file can not be read!" msgstr "Kan het XRechnung sjabloonbestand niet openen!" #: portal.cpp:674 #, kde-format msgid "XRechnung Export" msgstr "XRechnung exporteren" #: portal.cpp:694 #, kde-format msgid "Save XRechnung" msgstr "XRechnung opslaan" #: portal.cpp:696 #, kde-format msgid "Saved XRechnung to %1" msgstr "Xrechnung opgeslagen naar %1" #: portal.cpp:730 #, kde-format msgid "Generating PDF..." msgstr "Bezig met generen van PDF..." #: portal.cpp:744 portal.cpp:767 portal.cpp:1093 katalogview.cpp:236 #: katalogview.cpp:302 katalogview.cpp:316 katalogview.cpp:325 #: katalogview.cpp:334 #, kde-format msgid "Ready." msgstr "Gereed." #: portal.cpp:753 #, kde-format msgid "Generating PDF for EMail" msgstr "Bezig met generen van PDF voor de email" #: portal.cpp:772 #, kde-format msgid "Doc Generation Error" msgstr "Fout bij generen van document" #: portal.cpp:828 #, kde-format msgid "Printing archived document..." msgstr "Bezig met afdrukken gearchiveerd document..." #: portal.cpp:880 #, kde-format msgid "Opening document %1" msgstr "Bezig met het openen van document %1" #: portal.cpp:1037 katalogview.cpp:241 #, kde-format msgid "Exiting..." msgstr "Bezig met afsluiten..." #: portal.cpp:1064 #, kde-format msgid "Cutting selection..." msgstr "Bezig met het knippen van de selectie..." #: portal.cpp:1071 #, kde-format msgid "Copying selection to clipboard..." msgstr "Bezig met het kopiëren van de selectie naar het klembord..." #: portal.cpp:1078 #, kde-format msgid "Inserting clipboard contents..." msgstr "Bezig met plakken van de inhoud van het klembord..." #: portal.cpp:1091 #, kde-format msgid "" "Ready. Kraft is running in read only mode. Document editing is prohibited." msgstr "" "Gereed, Kraft is in alleen lezen modus - document wijzigen is niet " "toegestaan." #: doctypeedit.cpp:49 #, kde-format msgid "" msgstr "" #: doctypeedit.cpp:50 #, kde-format msgid "
        " msgstr "
        " #: doctypeedit.cpp:85 #, kde-format msgid "Select template file from harddisk" msgstr "Selecteer het sjabloonbestand op harde schijf" #: doctypeedit.cpp:86 #, kde-format msgid "Select watermark file from harddisk" msgstr "Selecteer het watermerk-bestand op harde schijf" #: doctypeedit.cpp:87 #, kde-format msgid "Select PDF file to append to documents from harddisk" msgstr "Selecteer PDF-bestand op harde schijf om bij te sluiten" #: doctypeedit.cpp:91 prefsdialog.cpp:409 #, kde-format msgid "Find Template File" msgstr "Zoek sjabloonbestand" #: doctypeedit.cpp:92 #, kde-format msgid "Kraft Templates (*.trml *.gtmpl)" msgstr "Kraft sjablonen (*.trml *.gtmpl)" #: doctypeedit.cpp:100 #, kde-format msgid "Find Watermark File" msgstr "Zoek watermerk-bestand" #: doctypeedit.cpp:101 doctypeedit.cpp:111 #, kde-format msgid "PDF file (*.pdf)" msgstr "PDF bestand (*.pdf)" #: doctypeedit.cpp:110 #, kde-format msgid "Find Append PDF File" msgstr "Zoek PDF-bestand om bij te sluiten" #: doctypeedit.cpp:171 doctypeedit.cpp:197 #, kde-format msgid "Add Document Type" msgstr "Documenttype toevoegen" #: doctypeedit.cpp:172 #, kde-format msgid "Enter the name of a new document type" msgstr "Voer de naam in van een nieuw documenttype" #: doctypeedit.cpp:198 #, kde-format msgid "Edit the name of a document type" msgstr "Bewerk de naam van een documenttype" #: docdigestdetailview.cpp:230 rc.cpp:78 rc.cpp:120 rc.cpp:988 rc.cpp:1030 #: rc.cpp:1826 rc.cpp:1868 rc.cpp:2709 rc.cpp:2751 rc.cpp:3760 rc.cpp:3802 #: rc.cpp:4664 rc.cpp:4706 #, kde-format msgid "Amount" msgstr "Aantal" #: docdigestdetailview.cpp:231 #, kde-format msgid "Type" msgstr "Type" #: docdigestdetailview.cpp:232 #, kde-format msgid "Sum" msgstr "Totaal" #: docdigestdetailview.cpp:261 #, kde-format msgid "Results in %1 %2" msgstr "Resultaten in %1 %2" #: docdigestdetailview.cpp:262 docdigestdetailview.cpp:295 #, kde-format msgid "Year" msgstr "Jaar" #: docdigestdetailview.cpp:264 #, kde-format msgid "Month" msgstr "Maand" #: docdigestdetailview.cpp:297 #, kde-format msgid "Results in Year %1" msgstr "Resultaten in jaar %1" #: docdigestdetailview.cpp:316 docdigestdetailview.cpp:325 #, kde-format msgid "Customer" msgstr "Klant" #: docdigestdetailview.cpp:320 #, kde-format msgid "not set" msgstr "niet ingesteld" #: docdigestdetailview.cpp:336 #, kde-format msgid "The address is not listed in an address book." msgstr "Het adres komt niet voor in de adresboeken." #: docdigestdetailview.cpp:338 #, kde-format msgid "" "The client has the address book id %1 but can not found in our address " "books." msgstr "" "De klant heeft het adresboek-ID %1 maar kan niet gevonden worden in onze " "adresboeken." #: docdigestdetailview.cpp:341 #, kde-format msgid "The client can be found in our address books." msgstr "De klant is gevonden in onze adresboeken." #: docdigestdetailview.cpp:352 prefsdialog.cpp:744 #, kde-format msgid "preferred address" msgstr "voorkeur-adres" #: docdigestdetailview.cpp:356 prefsdialog.cpp:748 #, kde-format msgid "home address" msgstr "Privé-adres" #: docdigestdetailview.cpp:360 prefsdialog.cpp:752 #, kde-format msgid "work address" msgstr "Werk-adres" #: docdigestdetailview.cpp:364 prefsdialog.cpp:756 #, kde-format msgid "postal address" msgstr "Post-adres" #: docdigestdetailview.cpp:368 prefsdialog.cpp:760 #, kde-format msgid "international address" msgstr "internationaal adres" #: docdigestdetailview.cpp:372 prefsdialog.cpp:764 #, kde-format msgid "domestic address" msgstr "adres in eigen land" #: docdigestdetailview.cpp:376 prefsdialog.cpp:768 #, kde-format msgid "unknown" msgstr "onbekend" #: docdigestdetailview.cpp:433 #, kde-format msgid "This document was never printed." msgstr "Dit document is nog nooit afgedrukt." #: docdigestdetailview.cpp:440 #, kde-format msgid "Last printed" msgstr "Laatst afgedrukt" #: docdigestdetailview.cpp:441 #, kde-format msgid "Opens last created PDF document" msgstr "Opent het laatst gemaakte PDF document" #: docdigestdetailview.cpp:442 #, kde-format msgid "open" msgstr "Openen" #: docdigestdetailview.cpp:447 #, kde-format msgid "One older print" msgstr "Een oudere afdruk" #: docdigestdetailview.cpp:449 #, kde-format msgid "%1 older prints" msgstr "%1 oudere afdrukken" #: docdigestdetailview.cpp:453 #, kde-format msgid "Archived documents can not be found. Check PDF Output dir." msgstr "" "De documenten zijn niet in het archief te vinden. Controleer de PDF uitvoer " "map." #: docdigestdetailview.cpp:457 #, kde-format msgid "Export the invoice in XRechnung file format" msgstr "Exporteert de rekening in het XRechnung bestandsformaat" #: docdigestdetailview.cpp:458 #, kde-format msgid "XRechnung" msgstr "XRechnung" #: importfilter.cpp:50 #, kde-format msgid "Unable to find filter called %1" msgstr "Kon filter genaamd %1 niet vinden" #: importfilter.cpp:58 #, kde-format msgid "Could not open the definition file!" msgstr "Kon het definitiebestand niet openen!" #: importfilter.cpp:143 #, kde-format msgid "Unknown tags: " msgstr "Onbekende tags: " #: importfilter.cpp:184 #, kde-format msgid "Could not recode input file!" msgstr "Kon invoerbestand niet opnieuw indelen!" #: importfilter.cpp:192 #, kde-format msgid "Unable to open temp file " msgstr "Kon tijdelijk bestand niet openen " #: importfilter.cpp:198 #, kde-format msgid "Could not open the import source file!" msgstr "Kon het importbestand niet openen!" #: importitemdialog.cpp:47 #, kde-format msgid "Import Items From File" msgstr "Items vanuit bestand importeren" #: importitemdialog.cpp:116 #, kde-format msgid "the Header of the Document" msgstr "het briefhoofd van het document" #: inserttempldialog.cpp:105 #, kde-format msgid "Create a new Item" msgstr "Nieuw item aanmaken" #: inserttempldialog.cpp:107 #, kde-format msgid "Create a new Item from Template" msgstr "Van sjabloon nieuw item aanmaken" #: itemtagdialog.cpp:82 #, kde-format msgid "Edit Item Tags" msgstr "Item Tags bewerken" #: itemtagdialog.cpp:89 #, kde-format msgid "Item Tags" msgstr "Item Tags" #: itemtagdialog.cpp:90 #, kde-format msgid "Select all tags for the item should be tagged with." msgstr "Selecteer alle tags waarmee u het item wilt markeren." #: itemtagdialog.cpp:105 tagtemplatesdialog.cpp:150 #, kde-format msgid "Tag" msgstr "Tag" #: itemtagdialog.cpp:106 tagtemplatesdialog.cpp:151 #, kde-format msgid "Color" msgstr "Kleur" #: itemtagdialog.cpp:107 tagtemplatesdialog.cpp:152 #, kde-format msgid "Description" msgstr "Beschrijving" #: kataloglistview.cpp:355 #, kde-format msgid "A catalog chapter can not be deleted as long it has children." msgstr "Kan map niet uit catalogus verwijderen zolang het niet leeg is." #: kataloglistview.cpp:356 #, kde-format msgid "Chapter can not be deleted" msgstr "Kan map niet verwijderen" #: katalogview.cpp:164 #, kde-format msgid "Edit Sub chapter" msgstr "Submap wijzigen" #: katalogview.cpp:166 #, kde-format msgid "Edit a catalog sub chapter" msgstr "Submap in catalogus wijzigen" #: katalogview.cpp:170 #, kde-format msgid "Add a sub chapter" msgstr "Submap toevoegen" #: katalogview.cpp:172 #, kde-format msgid "Add a sub chapter below the selected one" msgstr "In deze map een submap toevoegen" #: katalogview.cpp:176 katalogview.cpp:178 #, kde-format msgid "Remove a sub chapter" msgstr "Submap verwijderen" #: katalogview.cpp:182 rc.cpp:3 rc.cpp:913 rc.cpp:1751 rc.cpp:2634 rc.cpp:3685 #: rc.cpp:4589 #, kde-format msgid "Edit Template" msgstr "Sjabloon bewerken" #: katalogview.cpp:184 #, kde-format msgid "Opens the editor window for templates to edit the selected one" msgstr "Opent het bewerkingsvenster om het geselecteerde sjabloon te bewerken" #: katalogview.cpp:189 #, kde-format msgid "New template" msgstr "Nieuw sjabloon" #: katalogview.cpp:191 #, kde-format msgid "Opens the editor window for templates to enter a new template" msgstr "" "Opent het bewerkingsvenster voor sjablonen om een nieuw sjabloon in te " "voeren" #: katalogview.cpp:196 #, kde-format msgid "Delete template" msgstr "Sjabloon verwijderen" #: katalogview.cpp:198 #, kde-format msgid "Deletes the template" msgstr "Verwijdert het sjabloon " #: katalogview.cpp:203 #, kde-format msgid "Export catalog" msgstr "Catalogus exporteren" #: katalogview.cpp:205 #, kde-format msgid "Export the whole catalog as XML encoded file" msgstr "De hele catalogus als XML-gecodeerd bestand exporteren" #: katalogview.cpp:210 #, kde-format msgid "Import catalog" msgstr "Catalogus importeren" #: katalogview.cpp:212 #, kde-format msgid "Import a catalog from a XML file" msgstr "Catalogus uit een XML-bestand importeren" #: katalogview.cpp:216 rc.cpp:487 rc.cpp:1358 rc.cpp:2247 rc.cpp:3142 #: rc.cpp:4016 rc.cpp:4920 #, kde-format msgid "&Catalog" msgstr "&Catalogus" #: katalogview.cpp:234 #, kde-format msgid "Opening file..." msgstr "Bestand wordt geopend..." #: katalogview.cpp:298 #, kde-format msgid "Exporting file..." msgstr "Exporteren van bestand..." #: katalogview.cpp:307 #, kde-format msgid "Importfile... (not yet implemented)" msgstr "Importbestand...(nog niet geïmplementeerd)" #: katalogview.cpp:312 #, kde-format msgid "Creating a new sub chapter..." msgstr "Bezig met het aanmaken van een submap..." #: katalogview.cpp:321 #, kde-format msgid "Editing a sub chapter..." msgstr "Bezig met het bewerken van een submap..." #: katalogview.cpp:330 #, kde-format msgid "Removing a sub chapter..." msgstr "Bezig met het verwijderen van een submap..." #: katalogview.cpp:363 #, kde-format msgid "Created at %1 " msgstr "Aangemaakt op %1 " #: katalogview.cpp:367 #, kde-format msgid ", last modified at %1" msgstr ", laatste keer gewijzigd op %1" #: katalogview.cpp:373 #, kde-format msgid "%1 times used, last at %2" msgstr "%1 keer gebruikt, laatste keer op %2" #: kraftdocheaderedit.cpp:57 #, kde-format msgid "Document Header" msgstr "Briefhoofd van document" #: kraftdocheaderedit.cpp:65 #, kde-format msgid "Manually set in address field." msgstr "Handmatig het adresveld instellen." #: kraftview.cpp:89 kraftview_ro.cpp:60 #, kde-format msgid "Document" msgstr "Document" #: kraftview.cpp:257 #, kde-format msgid "Successor of %1" msgstr "Vervolg van %1" #: kraftview.cpp:395 kraftview.cpp:847 #, kde-format msgid "" "The address label is not empty and different from the selected one.
        Do " "you really want to replace it with the text shown below?
        %1
        " msgstr "" "Het adreslabel is niet leeg en verschilt van de geselecteerde.
        Wilt u \n" "het vervangen door de onderstaande tekst?
        %1
        " #: kraftview.cpp:442 #, kde-format msgid "" "

        The Document Items List is still empty, but Items can be added " "now.

        To add items to the document either
        • Press the 'Add item' " "button above.
        • Open the template catalog by clicking on the 'show " "Template' button on the right and pick one of the available " "templates.
        " msgstr "" "

        De lijst met items in het documenten is nog leeg, maar u kunt vanaf nu items toevoegen.

        om items aan het document toe te voegen, kunt u naar keuze
        • op de \n" "knop \"toevoegen\" erboven drukken.
        • het dialoog met de catalogus met \n" "sjablonen openen door op de 'Sjabloon weergeven' knop rechts te klikken en een van de \n" "beschikbare sjablonen te selecteren.
        " #: kraftview.cpp:634 prefsdialog.cpp:329 #, kde-format msgid "Display no tax at all" msgstr "Helemaal geen belasting tonen" #: kraftview.cpp:635 prefsdialog.cpp:330 #, kde-format msgid "Calculate reduced tax for all items" msgstr "Bereken lage BTW voor alle items" #: kraftview.cpp:636 prefsdialog.cpp:331 #, kde-format msgid "Calculate full tax for all items" msgstr "Bereken hoge BTW voor alle items" #: kraftview.cpp:637 #, kde-format msgid "Calculate individual tax for each item" msgstr "Bereken voor elk item de belasting apart" #: kraftview.cpp:694 #, kde-format msgid "Tax Settings Overwrite" msgstr "belastinginstellingen overschrijven" #: kraftview.cpp:695 #, kde-format msgid "Really overwrite all individual tax settings of the items?" msgstr "" "Wilt u alle individuele belastinginstellingen van de items overschrijven? " #: kraftview.cpp:846 #, kde-format msgid "Address Overwrite" msgstr "Overschrijven van adres" #: kraftview.cpp:1111 #, kde-format msgid "Discount" msgstr "Korting" #: kraftview.cpp:1351 #, kde-format msgid "The document has been modified." msgstr "Het document is gewijzigd." #: kraftview.cpp:1352 #, kde-format msgid "Do you want to save your changes?" msgstr "Wilt u alle wijzigingen verwerpen?" #: kraftdocfooteredit.cpp:52 #, kde-format msgid "Document Footer" msgstr "Voettekst van document" #: kraftdocpositionsedit.cpp:94 #, kde-format msgid "Add Item..." msgstr "Item toevoegen..." #: kraftdocpositionsedit.cpp:96 #, kde-format msgid "Add a normal item to the document manually." msgstr "Een normaal item handmatig aan het document toevoegen." #: kraftdocpositionsedit.cpp:100 #, kde-format msgid "Add Discount Item" msgstr "Korting geven" #: kraftdocpositionsedit.cpp:103 #, kde-format msgid "" "Adds an item to the document that allows discounts on other items in the " "document" msgstr "" "Voegt een item aan het document toe dat kortingen op andere items in het " "document toestaat" #: kraftdocpositionsedit.cpp:106 #, kde-format msgid "Import Items..." msgstr "Items importeren..." #: kraftdocpositionsedit.cpp:109 #, kde-format msgid "Opens a dialog where multiple items can be imported from a text file." msgstr "" "Opent een dialoog waar meerdere items geïmporteerd kunnen worden uit een " "tekstbestand." #: kraftdocpositionsedit.cpp:118 #, kde-format msgid "Document Items" msgstr "Document-items" #: kraftview_ro.cpp:198 #, kde-format msgid "Reduced TAX" msgstr "Lage BTW" #: materialkataloglistview.cpp:40 rc.cpp:108 rc.cpp:643 rc.cpp:1018 #: rc.cpp:1675 rc.cpp:1856 rc.cpp:2567 rc.cpp:2739 rc.cpp:3471 rc.cpp:3790 #: rc.cpp:4181 rc.cpp:4694 rc.cpp:5088 #, kde-format msgid "Material" msgstr "Materiaal" #: materialkataloglistview.cpp:41 #, kde-format msgid "Pack" msgstr "Verpakt per" #: materialkataloglistview.cpp:42 rc.cpp:123 rc.cpp:1033 rc.cpp:1871 #: rc.cpp:2754 rc.cpp:3805 rc.cpp:4709 #, kde-format msgid "Unit" msgstr "Eenheid" #: materialkataloglistview.cpp:43 #, kde-format msgid "Purchase" msgstr "Inkoop" #: materialkataloglistview.cpp:44 #, kde-format msgid "Sale" msgstr "Verkoop" #: materialkataloglistview.cpp:45 #, kde-format msgid "Last Modified" msgstr "Laatst gewijzigd" #: materialkataloglistview.cpp:51 #, kde-format msgid "Material Catalog" msgstr "Materiaalcatalogus" #: materialkatalogview.cpp:106 #, kde-format msgid "" msgstr "" #: materialkatalogview.cpp:136 templkatalogview.cpp:139 #, kde-format msgid "Do you really want to delete the template from the catalog?" msgstr "Wilt u het sjabloon uit de catalogus verwijderen?" #: prefsdialog.cpp:64 #, kde-format msgid "Configure Kraft" msgstr "Kraft instellen" #: prefsdialog.cpp:98 #, kde-format msgid "Document Defaults" msgstr "Standaarddocument" #: prefsdialog.cpp:99 #, kde-format msgid "Taxes" msgstr "Belastingen" #: prefsdialog.cpp:100 #, kde-format msgid "Document Types" msgstr "Documenttypes" #: prefsdialog.cpp:102 #, kde-format msgid "Wages" msgstr "Salarissen" #: prefsdialog.cpp:104 #, kde-format msgid "Units" msgstr "Eenheden" #: prefsdialog.cpp:105 #, kde-format msgid "Own Identity" msgstr "Uw eigen identiteit" #: prefsdialog.cpp:152 #, kde-format msgid "Tax rates beginning at date:" msgstr "Belastingtarieven beginnend op de datum:" #: prefsdialog.cpp:160 prefswages.cpp:51 prefsunits.cpp:53 #, kde-format msgid "ID" msgstr "ID" #: prefsdialog.cpp:161 #, kde-format msgid "Full Tax [%]" msgstr "Hoog BTW [%]" #: prefsdialog.cpp:162 #, kde-format msgid "Reduced Tax [%]" msgstr "Laag BTW [%]" #: prefsdialog.cpp:163 #, kde-format msgid "Start Date" msgstr "Startdatum" #: prefsdialog.cpp:182 prefswages.cpp:90 prefsunits.cpp:80 rc.cpp:307 #: rc.cpp:1160 rc.cpp:2064 rc.cpp:2947 rc.cpp:3517 rc.cpp:4421 #, kde-format msgid "Add" msgstr "Toevoegen" #: prefsdialog.cpp:186 prefswages.cpp:99 prefsunits.cpp:89 rc.cpp:319 #: rc.cpp:1172 rc.cpp:2076 rc.cpp:2959 rc.cpp:3529 rc.cpp:4433 #, kde-format msgid "Remove" msgstr "Verwijderen" #: prefsdialog.cpp:203 #, kde-format msgid "" "Select the identity of the sending entity of documents. That's your " "companies address." msgstr "" "Selecteer de identiteit van de document-verzender. Dat is het adres van " "uw bedrijf." #: prefsdialog.cpp:219 #, kde-format msgid "Select Identity..." msgstr "Identiteit selecteren..." #: prefsdialog.cpp:225 #, kde-format msgid "From AddressBook" msgstr "Uit adresboek" #: prefsdialog.cpp:230 setupassistant.cpp:342 #, kde-format msgid "Manual Entry" msgstr "Handmatig toevoegen" #: prefsdialog.cpp:242 #, kde-format msgid "Manual Address" msgstr "Handmatige adres" #: prefsdialog.cpp:245 #, kde-format msgid "Bank Account Information" msgstr "Informatie bankrekening" #: prefsdialog.cpp:309 #, kde-format msgid "&Default document type on creation:" msgstr "Stan&daard documenttype bij aanmaken:" #: prefsdialog.cpp:314 #, kde-format msgid "New documents default to the selected type." msgstr "Nieuwe documenten hebben standaard het geselecteerde type." #: prefsdialog.cpp:323 #, kde-format msgid "Default &Tax for Documents:" msgstr "Standaard &belastingtarief voor documenten:" #: prefsdialog.cpp:328 #, kde-format msgid "The default tax setting for all documents." msgstr "" "De standaard instelling voor het belastingtarief te gebruiken in alle " "documenten." #: prefsdialog.cpp:340 #, kde-format msgid "Document Date Format:" msgstr "Datum instelling van document:" #: prefsdialog.cpp:346 #, kde-format msgid "The default date format for documents." msgstr "De standaard datum-instelling voor documenten." #: prefsdialog.cpp:348 #, kde-format msgid "ISO-Format: %1" msgstr "ISO-opmaak: %1" #: prefsdialog.cpp:350 #, kde-format msgid "Short-Date: %1" msgstr "Korte-datum: %1" #: prefsdialog.cpp:352 #, kde-format msgid "Long-Date: %1" msgstr "Lange-datum: %1" #: prefsdialog.cpp:354 #, kde-format msgid "RFC 2822-Format: %1" msgstr "RFC 2822-Opmaak: %1" #: prefsdialog.cpp:356 #, kde-format msgid "\"German Format\": %1" msgstr "\"Duitse Opmaak\": %1" #: prefsdialog.cpp:357 #, kde-format msgid "Custom Setting in Settingsfile" msgstr "Aangepaste instelling in het instellingenbestand" #: prefsdialog.cpp:366 #, kde-format msgid "Prefix text for Demand items:" msgstr "voorvoegsel voor posten op verzoek" #: prefsdialog.cpp:371 #, kde-format msgid "This text is automatically prepended to new 'on demand' items." msgstr "Deze tekst is automatisch geplaatst voor nieuwe posten 'op verzoek'." #: prefsdialog.cpp:375 #, kde-format msgid "Prefix text for Alternative items:" msgstr "Voorvoegsel voor alternatieve posten" #: prefsdialog.cpp:380 #, kde-format msgid "This text is automatically prepended to new 'alternative' items." msgstr "" "Deze tekst is automatisch geplaatst voor nieuwe posten 'alternatief'." #: prefsdialog.cpp:391 #, kde-format msgid "XRechnung Template File:" msgstr "XRechnung sjabloonbestand:" #: prefsdialog.cpp:397 #, kde-format msgid "Select..." msgstr "Selecteren..." #: prefsdialog.cpp:405 #, kde-format msgid "Select template file for XRechnung" msgstr "Selecteer sjabloonbestand voor XRechnung" #: prefsdialog.cpp:410 #, kde-format msgid "XRechnung Templates (*.xrtmpl)" msgstr "XRechnung Sjablonen (*.xrtmpl)" #: prefsdialog.cpp:450 #, kde-format msgid "" "The old default doc type for new documents was just deleted.Please check the" " setting in the Document Defaults in the Kraft preferences Dialog." msgstr "" "Het oude standaarddocument type voor nieuwe documenten is zojuist verwijderd. Controleer de instellingen voor document types in het \n" "configuratiedialoog van Kraft." #: prefsdialog.cpp:453 #, kde-format msgid "Document Default Change" msgstr "Wijzigen standaarddocument" #: prefsdialog.cpp:701 #, kde-format msgid "The identity can not be found." msgstr "De identiteit is niet te vinden." #: prefsdialog.cpp:703 #, kde-format msgid "" "

        Kraft Addressbook Integration down.

        The address book backend" " is not up and running.

        Please check your addressbook integration " "setup.

        " msgstr "" "

        Kraft adresboek Integratie werkt niet.

        De backend van het " "adresboek is niet opgestart.

        Controleer de instellingen de integratie " "van uw adresboek.

        " #: prefsdialog.cpp:709 #, kde-format msgid "The identity is not listed in an address book." msgstr "Deze identiteit komt niet in een adresboek voor." #: prefsdialog.cpp:711 #, kde-format msgid "" "

        Kraft does not know your identity.

        Please pick one from the " "address books by clicking on the Button below.

        Not having an identity " "selected can make your documents look incomplete.

        " msgstr "" "

        Kraft weet uw identiteit niet.

        Selecteer een uit het adres " "boek door te klikken op de knop eronder.

        Uw documenten kunnen " "incompleet er uit zien als u geen identiteit heeft geselecteerd.

        " #: prefsdialog.cpp:728 #, kde-format msgid "Your identity can be found in the address books." msgstr "Uw identiteit is te vinden in de adresboeken." #: prefsdialog.cpp:739 #, kde-format msgid "Work Phone" msgstr "Telefoon werk" #: prefsdialog.cpp:740 #, kde-format msgid "Fax" msgstr "Fax" #: prefsdialog.cpp:741 #, kde-format msgid "Cell Phone" msgstr "Mobiele telefoon" #: materialselectdialog.cpp:39 #, kde-format msgid "Add Material to Calculation" msgstr "Materiaal toevoegen aan de berekening" #: materialselectdialog.cpp:44 #, kde-format msgid "

        Add Material to Calculation

        " msgstr "

        Materiaal toevoegen aan de berekening

        " #: newdocassistant.cpp:52 newdocassistant.cpp:96 #, kde-format msgid "New Document Settings" msgstr "Instellingen voor nieuwe documenten" #: newdocassistant.cpp:55 #, kde-format msgid "" "Please select a customer as addressee for the document. If there is no entry" " for the customer in the addressbook yet, it can be opened by clicking on " "the button below." msgstr "" "Selecteer een klant als geadresseerde voor het document. Als er voor de " "klant nog geen item in het adresboek is, dan kunt u deze openen door op de " "knop eronder te klikken." #: newdocassistant.cpp:100 #, kde-format msgid "" "Select a document type and a date. A comment on the whiteboard helps to " "classify the document." msgstr "" "Selecteer een documenttype en een datum. Een omschrijving op het whiteboard " "helpt bij het classificeren van het document." #: newdocassistant.cpp:107 #, kde-format msgid "Customer: Not yet selected!" msgstr "Klant: niet geselecteerd!" #: newdocassistant.cpp:116 #, kde-format msgid "Document &Type:" msgstr "Document &type:" #: newdocassistant.cpp:120 #, kde-format msgid "Document Date: " msgstr "Datum document:" #: newdocassistant.cpp:123 #, kde-format msgid "Whiteboard Content:" msgstr "Inhoud Whiteboard:" #: newdocassistant.cpp:127 #, kde-format msgid "Copy document items from predecessor document" msgstr "Kopieer items uit voorgaande document" #: newdocassistant.cpp:175 #, kde-format msgid "Create a new Kraft Document" msgstr "Nieuw Kraft document aanmaken" #: newdocassistant.cpp:265 #, kde-format msgid "Followup Document for %1" msgstr "Opvolg document voor %1" #: numbercycledialog.cpp:52 #, kde-format msgid "Edit Number Cycles" msgstr "Volgnummersysteem bewerken" #: numbercycledialog.cpp:67 #, kde-format msgid "" "The template may contain the following tags:
        • %y or %yyyy - the year " "of the documents date.
        • %yy - the year of the document (two " "digits).
        • %w - the week number of the documents date.
        • %ww - " "the week number of the documents date with leading zero.
        • %d - the " "day number of the documents date.
        • %dd - the day number of the " "documents date with leading zero.
        • %m or %M - the month number of the" " documents date.
        • %MM - the month number with leading " "zero.
        • %c - the customer id from kaddressbook
        • %i - the unique" " counter
        • %ii .. %iiiiii - the counter padded with leading 0, ie. " "012
        • %n - a day based counter, resets every day. Combined with date, " "it makes the number unique.
        • %nn .. %nnnnnn - the day based counter " "padded with leading 0.
        • %type - the localised doc type (offer, " "invoice etc.)
        • %uid - the contact id of the client.
        %i or %n" " need to be part of the template." msgstr "" " 74% match \n" "In het sjabloon mogen de volgende tags voorkomen:
        • %y of %yyyy - het jaar van het document datum.
        • %yy - thet jaar van het document (twee cijfers).
        • %w - het weeknummer van het document datum.
        • %ww - het week nummer van het document datum (twee cijfers).
        • %d - het dagnummer van het document.
        • %dd - het dagnummer van het document (twee cijfers).
        • %m of %M - de maand als nummer van het document.
        • %MM - de maand als nummer met twee cijfers.
        • %c - de klanten ID van kaddressbook
        • %i - het volgnummer
        • %ii .. %iiiiii - het volgnummer met het cijfer 0 er voor, b.v.. 012
        • %n - een volgnummer dat iedere dag gereset wordt. Gecombineerd met de datum, zorg dit dat het nummer uniek is.
        • %nn .. %nnnnnn - een volgnummer dat iedere dag gereset wordt met het cijfer 0 er voor.
        • %type - het gelokaliseerde doc type (offerte, rekening enz.)
        • %uid - het contact ID van de klant.
        %i of %n moet onderdeel zijn van het sjabloon." #: numbercycledialog.cpp:141 #, kde-format msgid "Doc-Type" msgstr "Doc-type" #: numbercycledialog.cpp:154 #, kde-format msgctxt "do not translate %i, it is a template variable." msgid "(%i added)" msgstr "(%i toegevoegd)" #: numbercycledialog.cpp:227 #, kde-format msgid "Add Number Cycle" msgstr "Volgnummersysteem toevoegen" #: numbercycledialog.cpp:228 #, kde-format msgid "Enter the name of a new number cycle." msgstr "Voer de naam in van een nieuw volgnummersysteem." #: numbercycledialog.cpp:286 #, kde-format msgid "The numbercycle %1 is still assigned to a document type." msgstr "Het Volgnummersysteem %1 wordt nog in een documenttype gebruikt." #: numbercycledialog.cpp:287 #, kde-format msgid "" "The number cycle can not be deleted as long as it is assigned to a document " "type." msgstr "" "Het volgnummersysteem kan niet worden verwijdert zolang het nog in een\n" "documenttype wordt gebruikt." #: numbercycledialog.cpp:346 #, kde-format msgid "Dangerous Counter Change" msgstr "Gevaarlijke wijziging stappen" #: numbercycledialog.cpp:347 #, kde-format msgid "The new counter is lower than the old one. " msgstr "De nieuwe stappen zijn kleiner dan de oude." #: numbercycledialog.cpp:348 #, kde-format msgid "" "That has potential to create duplicate document numbers. Do you really want " "to decrease it?" msgstr "" "Hierdoor kunnen documentnummers meerdere keren voorkomen. Wilt u het echt " "verkleinen?" #: portalview.cpp:68 #, kde-format msgid "About Kraft" msgstr "Info of Kraft" #: portalview.cpp:98 #, kde-format msgid "Documents" msgstr "Documenten" #: portalview.cpp:105 #, kde-format msgid "Timeline" msgstr "Tijdlijn" #: portalview.cpp:113 #, kde-format msgid "Catalogs" msgstr "Catalogi" #: portalview.cpp:152 #, kde-format msgid "Kraft Document Overview" msgstr "Overzicht documenten in Kraft" #: portalview.cpp:159 portalview.cpp:178 #, kde-format msgid "Available Catalogs" msgstr "Beschikbare catalogi" #: portalview.cpp:161 #, kde-format msgid "No catalogs available." msgstr "Geen catalogi beschikbaar." #: portalview.cpp:210 #, kde-format msgid "Open" msgstr "Openen" #: portalview.cpp:221 #, kde-format msgid "No templates yet." msgstr "Nog geen sjablonen." #: portalview.cpp:225 #, kde-format msgid "%1 templates in %2 chapters
        last modified at %3" msgstr "%1 sjablonen in %2 mappen
        gewijzigd op %3" #: portalview.cpp:276 #, kde-format msgid "Kraft Website" msgstr "Kraft Website" #: portalview.cpp:279 #, kde-format msgctxt "The string is followed by a link to the GPL2 text" msgid "Kraft is free software licensed under the" msgstr "Kraft is vrije software met een licentie onder de" #: portalview.cpp:280 #, kde-format msgctxt "The string is followed by the link to github" msgid "Kraft is maintained on " msgstr "Kraft wordt onderhouden op" #: portalview.cpp:281 #, kde-format msgid "Authors" msgstr "Auteurs" #: portalview.cpp:282 #, kde-format msgid "Developer and Maintainer" msgstr "Ontwikkelaar en onderhouder" #: portalview.cpp:283 #, kde-format msgid "Developer" msgstr "Ontwikkelaar" #: portalview.cpp:284 #, kde-format msgctxt "The person who provided the logo graphics" msgid "Logo design" msgstr "Logo ontwerp" #: portalview.cpp:285 #, kde-format msgctxt "The person who provided the user manual" msgid "User Manual" msgstr "Gebruikershandleiding" #: portalview.cpp:287 #, kde-format msgid "" "Kraft helps you to handle documents like quotes and invoices in your small " "business." msgstr "" "Kraft is bedoelt voor kleine bedrijven voor hulp bij het beheer van " "documenten zoals offertes en rekeningen." #: portalview.cpp:288 #, kde-format msgid "Welcome to Kraft" msgstr "Welkom bij Kraft" #: portalview.cpp:289 #, kde-format msgid "Kraft Version" msgstr "Kraft versie" #: portalview.cpp:291 #, kde-format msgid "Codename" msgstr "Codenaam" #: portalview.cpp:300 #, kde-format msgid "Git Information" msgstr "Git Information" #: portalview.cpp:308 #, kde-format msgid "Country Setting" msgstr "Ingesteld land:" #: portalview.cpp:311 #, kde-format msgid "Language Setting" msgstr "Ingestelde taal:" #: portalview.cpp:315 #, kde-format msgid "Kraft Initialisation Problem" msgstr "Kraft Initialisatie probleem" #: portalview.cpp:316 #, kde-format msgid "" "There is a initialisation error on your system. Kraft will not work that " "way." msgstr "" "Er is een initialisatie fout op uw systeem. Kraft zal op die manier niet " "werken." #: portalview.cpp:323 #, kde-format msgid "Database Information" msgstr "Database-informatie" #: portalview.cpp:324 #, kde-format msgid "Kraft database name" msgstr "Kraft database naam:" #: portalview.cpp:329 #, kde-format msgid "Required Version" msgstr "Vereiste versie" #: portalview.cpp:332 #, kde-format msgid "Database schema version" msgstr "Database-schemaversie:" #: portalview.cpp:334 #, kde-format msgid "Qt database driver" msgstr "Databasestuurprogramma voor Qt:" #: portalview.cpp:338 #, kde-format msgid "established" msgstr "tot stand gebracht" #: portalview.cpp:338 #, kde-format msgid "NOT AVAILABLE!" msgstr "NIET BESCHIKBAAR!" #: portalview.cpp:339 #, kde-format msgid "Database connection" msgstr "Databaseverbinding" #: portalview.cpp:348 #, kde-format msgid "Database Version" msgstr "Databaseversie" #: portalview.cpp:356 #, kde-format msgid "Addressbook Backend" msgstr "Addressbook Backend" #: portalview.cpp:357 #, kde-format msgid "Backend type" msgstr "Backend type" #: portalview.cpp:359 #, kde-format msgid "running" msgstr "Gestart" #: portalview.cpp:359 #, kde-format msgid "not running" msgstr "Niet gestart" #: portalview.cpp:363 #, kde-format msgid "External Tools" msgstr "Externe hulpprogramma's" #: portalview.cpp:365 #, kde-format msgid "RML to PDF conversion tool" msgstr "Hulpprogramma voor conversie van RML naar PDF:" #: portalview.cpp:367 #, kde-format msgid "not found!" msgstr "niet gevonden!" #: portalview.cpp:370 #, kde-format msgid "iconv tool for text import" msgstr "iconv hulpmiddel voor importeren van tekst" #: portalview.cpp:373 #, kde-format msgid "weasyprint for PDF generation" msgstr "weasyprint voor creatie van PDF" #: portalview.cpp:377 #, kde-format msgid "not available" msgstr "niet beschikbaar" #: portalview.cpp:382 #, kde-format msgid "Some Icons are made by" msgstr "Enkele pictogrammen zijn gemaakt door" #: portalview.cpp:383 #, kde-format msgid "Acknowledgements" msgstr "Met dank aan" #: positionviewwidget.cpp:90 #, kde-format msgid "Item Actions" msgstr "Item Acties" #: positionviewwidget.cpp:93 #, kde-format msgid "Item Kind" msgstr "Soort item:" #: positionviewwidget.cpp:94 positionviewwidget.cpp:687 #, kde-format msgid "Normal" msgstr "Normaal" #: positionviewwidget.cpp:96 positionviewwidget.cpp:695 #, kde-format msgid "Alternative" msgstr "Alternatief" #: positionviewwidget.cpp:98 #, kde-format msgid "On Demand" msgstr "Op verzoek" #: positionviewwidget.cpp:103 rc.cpp:265 rc.cpp:874 rc.cpp:1745 rc.cpp:2628 #: rc.cpp:3926 rc.cpp:4830 #, kde-format msgid "Tax" msgstr "Belasting" #: positionviewwidget.cpp:106 #, kde-format msgid "Taxfree Item" msgstr "Belastingvrije item" #: positionviewwidget.cpp:112 #, kde-format msgid "Reduced Tax" msgstr "Laag tarief BTW" #: positionviewwidget.cpp:118 #, kde-format msgid "Full Tax" msgstr "Hoog tarief BTW" #: positionviewwidget.cpp:127 #, kde-format msgid "Move Up" msgstr "Omhoog verplaatsen" #: positionviewwidget.cpp:129 #, kde-format msgid "Move Down" msgstr "Omlaag verplaatsen" #: positionviewwidget.cpp:131 #, kde-format msgid "Lock Item" msgstr "Item vastzetten" #: positionviewwidget.cpp:133 #, kde-format msgid "Unlock Item" msgstr "Item ontgrendelen" #: positionviewwidget.cpp:135 #, kde-format msgid "Delete Item" msgstr "Verwijder item" #: positionviewwidget.cpp:226 #, kde-format msgid "All items" msgstr "Alle items" #: positionviewwidget.cpp:236 #, kde-format msgid "%1-tagged items" msgstr "%1-gemarkeerde items" #: positionviewwidget.cpp:268 #, kde-format msgid "Tag: %1" msgstr "Tag: %1" #: positionviewwidget.cpp:270 #, kde-format msgid "Tags:
          " msgstr "Tags:
            " #: positionviewwidget.cpp:281 #, kde-format msgid "No tags assigned yet." msgstr "Nog geen tags toegewezen." #: positionviewwidget.cpp:410 #, kde-format msgid "Active" msgstr "Actief" #: positionviewwidget.cpp:412 #, kde-format msgid "New" msgstr "Nieuw" #: positionviewwidget.cpp:414 #, kde-format msgid "Deleted" msgstr "Verwijdert" #: positionviewwidget.cpp:416 #, kde-format msgid "Locked" msgstr "Vastgezet" #: positionviewwidget.cpp:613 #, kde-format msgid "" "This item is either completely optional or its amount varies depending on " "the needs.

            Use the item toolbox to change the item type." msgstr "" "Dit item is compleet optioneel of het aantal is afhankelijk van het \n" "gebruik.

            Bij de knoppen voor positie is een knop waar u het type \n" "item kunt wijzigen." #: positionviewwidget.cpp:619 #, kde-format msgid "" "This is an alternative item.

            Use the position toolbox to change " "the item type." msgstr "" "Dit item is een alternatief.

            Bij de knoppen voor positie is een \n" "knop waar u het item-type kunt wijzigen." #: positionviewwidget.cpp:691 #, kde-format msgid "Demand" msgstr "Op verzoek" #: prefswages.cpp:52 #, kde-format msgid "Code" msgstr "Code" #: prefswages.cpp:53 rc.cpp:126 rc.cpp:1036 rc.cpp:1874 rc.cpp:2757 #: rc.cpp:3808 rc.cpp:4712 templkataloglistview.cpp:46 #, kde-format msgid "Price" msgstr "Prijs" #: prefswages.cpp:54 #, kde-format msgid "Sortkey" msgstr "Sneltoets" #: prefswages.cpp:80 #, kde-format msgid "Up" msgstr "Omhoog" #: prefswages.cpp:85 #, kde-format msgid "Down" msgstr "Omlaag" #: prefswages.cpp:94 prefsunits.cpp:84 rc.cpp:313 rc.cpp:1166 rc.cpp:2070 #: rc.cpp:2953 rc.cpp:3523 rc.cpp:4427 #, kde-format msgid "Edit" msgstr "Bewerken" #: prefswages.cpp:201 #, kde-format msgid "Edit a wage group" msgstr "Salarisgroep bewerken" #: prefswages.cpp:241 #, kde-format msgid "

            Edit wage group

            " msgstr "

            Salarisgroep bewerken

            " #: prefsunits.cpp:54 #, kde-format msgid "Short" msgstr "Afgekort" #: prefsunits.cpp:55 #, kde-format msgid "Long" msgstr "Compleet" #: prefsunits.cpp:56 #, kde-format msgid "Short plural" msgstr "Kort meervoud" #: prefsunits.cpp:57 #, kde-format msgid "Long plural" msgstr "Compleet meervoud" #: prefsunits.cpp:58 #, kde-format msgid "ECE20" msgstr "ECE20" #: prefsunits.cpp:153 #, kde-format msgid "Edit a unit" msgstr "Bewerk eenheid" #: prefsunits.cpp:197 #, kde-format msgid "

            Edit unit

            " msgstr "

            Bewerk eenheid

            " #: reportgenerator.cpp:113 #, kde-format msgid "Document generation process is still running." msgstr "Ben nog bezig met het generen van documenten." #: reportgenerator.cpp:168 #, kde-format msgid "Template file is not accessible." msgstr "Kan sjabloon niet vinden." #: reportgenerator.cpp:193 #, kde-format msgid "The template conversion failed." msgstr "De conversie van het sjabloon is mislukt." #: reportgenerator.cpp:201 #, kde-format msgid "Saving to temporar file failed." msgstr "Opslaan naar tijdelijk bestand is mislukt." #: reportgenerator.cpp:332 #, kde-format msgid "No converter error." msgstr "Geen problemen bij de conversie." #: reportgenerator.cpp:335 #, kde-format msgid "The ReportLab based converter script can not be executed." msgstr "" "Het op ReportLab gebaseerde conversie script kon niet worden uitgevoerd." #: reportgenerator.cpp:338 #, kde-format msgid "An unknown error happened." msgstr "Een onbekend probleem trad op." #: reportgenerator.cpp:341 #, kde-format msgid "The ReportLab python module is not installed." msgstr "De ReportLab python module is niet geïnstalleerd." #: reportgenerator.cpp:344 #, kde-format msgid "The PyPDF2 python module is not installed." msgstr "De PyPDF2 python module is niet geïnstalleerd." #: reportgenerator.cpp:347 #, kde-format msgid "The source file can not be read." msgstr "Kan het bronbestand niet openen." #: reportgenerator.cpp:350 #, kde-format msgid "The target can not be opened to write." msgstr "Het doelbestand kon niet worden geopend." #: reportgenerator.cpp:353 #, kde-format msgid "The target file does not exist." msgstr "Het doelbestand is niet te vinden." #: reportgenerator.cpp:356 #, kde-format msgid "The WeasyPrint tool is not installed." msgstr "Het WeasyPrint onderdeel is niet geïnstalleerd." #: reportgenerator.cpp:359 #, kde-format msgid "The PDF merger utility failed." msgstr "Het samenvoegen van PDF mislukte." #: reportgenerator.cpp:378 #, kde-format msgid "There is not template defined for %1." msgstr "Er is geen sjabloon gedefinieerd voor %1." #: reportgenerator.cpp:383 #, kde-format msgid "The template file %1 for document type %2 does not exist." msgstr "Het sjabloonbestand %1 voor documenttype %2 bestaat niet." #: reportgenerator.cpp:387 #, kde-format msgid "The template file %1 for document type %2 can not be read." msgstr "Kan het sjabloonbestand %1 voor documenttype %2 niet openen." #: rc.cpp:6 rc.cpp:916 rc.cpp:1754 rc.cpp:2637 rc.cpp:3688 rc.cpp:4592 #: templkataloglistview.cpp:45 texteditdialog.cpp:76 #, kde-format msgid "Template" msgstr "Sjabloon" #: rc.cpp:9 rc.cpp:919 rc.cpp:1757 rc.cpp:2640 rc.cpp:3691 rc.cpp:4595 #, kde-format msgid "Text:" msgstr "Tekst:" #: rc.cpp:12 rc.cpp:922 rc.cpp:1760 rc.cpp:2643 rc.cpp:3694 rc.cpp:4598 #, kde-format msgid "&Store in Chapter" msgstr "Opge&slagen in map" #: rc.cpp:15 rc.cpp:925 rc.cpp:1763 rc.cpp:2646 rc.cpp:3697 rc.cpp:4601 #, kde-format msgid "&Unit" msgstr "&Eenheid" #: rc.cpp:18 rc.cpp:928 rc.cpp:1766 rc.cpp:2649 rc.cpp:3700 rc.cpp:4604 #, kde-format msgid "&Count Time for Overalltime" msgstr "Meetellen voor totaaltijd" #: rc.cpp:24 rc.cpp:934 rc.cpp:1772 rc.cpp:2655 rc.cpp:3706 rc.cpp:4610 #, kde-format msgid "full" msgstr "Hoog" #: rc.cpp:27 rc.cpp:937 rc.cpp:1775 rc.cpp:2658 rc.cpp:3709 rc.cpp:4613 #, kde-format msgid "half" msgstr "Laag" #: rc.cpp:30 rc.cpp:940 rc.cpp:1778 rc.cpp:2661 rc.cpp:3712 rc.cpp:4616 #, kde-format msgid "Time Calculation" msgstr "Post arbeid" #: rc.cpp:33 rc.cpp:72 rc.cpp:111 rc.cpp:943 rc.cpp:982 rc.cpp:1021 #: rc.cpp:1781 rc.cpp:1820 rc.cpp:1859 rc.cpp:2664 rc.cpp:2703 rc.cpp:2742 #: rc.cpp:3715 rc.cpp:3754 rc.cpp:3793 rc.cpp:4619 rc.cpp:4658 rc.cpp:4697 #, kde-format msgid "text" msgstr "tekst" #: rc.cpp:36 rc.cpp:946 rc.cpp:1784 rc.cpp:2667 rc.cpp:3718 rc.cpp:4622 #, kde-format msgid "Time measureable effort for this template:" msgstr "De voor dit sjabloon nodige tijd:" #: rc.cpp:39 rc.cpp:81 rc.cpp:117 rc.cpp:949 rc.cpp:991 rc.cpp:1027 #: rc.cpp:1787 rc.cpp:1829 rc.cpp:1865 rc.cpp:2670 rc.cpp:2712 rc.cpp:2748 #: rc.cpp:3721 rc.cpp:3763 rc.cpp:3799 rc.cpp:4625 rc.cpp:4667 rc.cpp:4703 #, kde-format msgid "Label" msgstr "Label" #: rc.cpp:42 rc.cpp:952 rc.cpp:1790 rc.cpp:2673 rc.cpp:3724 rc.cpp:4628 #, kde-format msgid "Duration" msgstr "Tijdsduur" #: rc.cpp:45 rc.cpp:955 rc.cpp:1793 rc.cpp:2676 rc.cpp:3727 rc.cpp:4631 #, kde-format msgid "Hourly Rate" msgstr "Uurtarief" #: rc.cpp:48 rc.cpp:958 rc.cpp:1796 rc.cpp:2679 rc.cpp:3730 rc.cpp:4634 #, kde-format msgid "Glob. Rate" msgstr "Project-tarief" #: rc.cpp:51 rc.cpp:961 rc.cpp:1799 rc.cpp:2682 rc.cpp:3733 rc.cpp:4637 #, kde-format msgid "Adds a new time calculation part to the template" msgstr "Voeg nieuwe post tijd aan het sjabloon toe" #: rc.cpp:54 rc.cpp:93 rc.cpp:132 rc.cpp:964 rc.cpp:1003 rc.cpp:1042 #: rc.cpp:1802 rc.cpp:1841 rc.cpp:1880 rc.cpp:2685 rc.cpp:2724 rc.cpp:2763 #: rc.cpp:3736 rc.cpp:3775 rc.cpp:3814 rc.cpp:4640 rc.cpp:4679 rc.cpp:4718 #, kde-format msgid "new..." msgstr "Nieuw..." #: rc.cpp:57 rc.cpp:967 rc.cpp:1805 rc.cpp:2688 rc.cpp:3739 rc.cpp:4643 #, kde-format msgid "Edits the current time calculation part" msgstr "Bewerk de geselecteerde post tijd" #: rc.cpp:60 rc.cpp:99 rc.cpp:138 rc.cpp:970 rc.cpp:1009 rc.cpp:1048 #: rc.cpp:1808 rc.cpp:1847 rc.cpp:1886 rc.cpp:2691 rc.cpp:2730 rc.cpp:2769 #: rc.cpp:3742 rc.cpp:3781 rc.cpp:3820 rc.cpp:4646 rc.cpp:4685 rc.cpp:4724 #, kde-format msgid "edit..." msgstr "bewerken..." #: rc.cpp:63 rc.cpp:973 rc.cpp:1811 rc.cpp:2694 rc.cpp:3745 rc.cpp:4649 #, kde-format msgid "Deletes the current time calculation part" msgstr "Verwijder de geselecteerde post tijd" #: rc.cpp:66 rc.cpp:105 rc.cpp:144 rc.cpp:976 rc.cpp:1015 rc.cpp:1054 #: rc.cpp:1814 rc.cpp:1853 rc.cpp:1892 rc.cpp:2697 rc.cpp:2736 rc.cpp:2775 #: rc.cpp:3748 rc.cpp:3787 rc.cpp:3826 rc.cpp:4652 rc.cpp:4691 rc.cpp:4730 #, kde-format msgid "delete" msgstr "verwijderen" #: rc.cpp:69 rc.cpp:979 rc.cpp:1817 rc.cpp:2700 rc.cpp:3751 rc.cpp:4655 #, kde-format msgid "Fix Costs" msgstr "Vaste kosten" #: rc.cpp:75 rc.cpp:985 rc.cpp:1823 rc.cpp:2706 rc.cpp:3757 rc.cpp:4661 #, kde-format msgid "Fix costs for this template per one unit:" msgstr "Vaste kosten in dit sjabloon per eenheid:" #: rc.cpp:84 rc.cpp:994 rc.cpp:1832 rc.cpp:2715 rc.cpp:3766 rc.cpp:4670 #, kde-format msgid "Single Price" msgstr "Stuksprijs" #: rc.cpp:87 rc.cpp:997 rc.cpp:1835 rc.cpp:2718 rc.cpp:3769 rc.cpp:4673 #, kde-format msgid "Overall Price" msgstr "Totale prijs" #: rc.cpp:90 rc.cpp:1000 rc.cpp:1838 rc.cpp:2721 rc.cpp:3772 rc.cpp:4676 #, kde-format msgid "adds a new fix calculation part" msgstr "Voeg nieuwe post vaste kosten toe" #: rc.cpp:96 rc.cpp:1006 rc.cpp:1844 rc.cpp:2727 rc.cpp:3778 rc.cpp:4682 #, kde-format msgid "edits the current fix calculation part" msgstr "Bewerk de geselecteerde post vaste kosten" #: rc.cpp:102 rc.cpp:1012 rc.cpp:1850 rc.cpp:2733 rc.cpp:3784 rc.cpp:4688 #, kde-format msgid "deletes the current fix calculation part" msgstr "Verwijder de geselecteerde post vaste kosten" #: rc.cpp:114 rc.cpp:1024 rc.cpp:1862 rc.cpp:2745 rc.cpp:3796 rc.cpp:4700 #, kde-format msgid "Needed materials for one unit of this template:" msgstr "Benodigde materiaal voor een exemplaar van dit sjabloon:" #: rc.cpp:129 rc.cpp:1039 rc.cpp:1877 rc.cpp:2760 rc.cpp:3811 rc.cpp:4715 #, kde-format msgid "adds a new material calculation part" msgstr "Voeg nieuwe post materiaal toe" #: rc.cpp:135 rc.cpp:1045 rc.cpp:1883 rc.cpp:2766 rc.cpp:3817 rc.cpp:4721 #, kde-format msgid "edits the current material part" msgstr "Bewerk de geselecteerde post materiaal" #: rc.cpp:141 rc.cpp:1051 rc.cpp:1889 rc.cpp:2772 rc.cpp:3823 rc.cpp:4727 #, kde-format msgid "deletes the current material calculation part" msgstr "Verwijdert de geselecteerde post materiaal" #: rc.cpp:147 rc.cpp:1057 rc.cpp:1895 rc.cpp:2778 rc.cpp:3829 rc.cpp:4733 #, kde-format msgid "Overall Price per Unit" msgstr "Totale prijs per eenheid" #: rc.cpp:150 rc.cpp:1060 rc.cpp:1898 rc.cpp:2781 rc.cpp:3832 rc.cpp:4736 #, kde-format msgid "&Manual Price" msgstr "Hand&matige prijs" #: rc.cpp:153 rc.cpp:1063 rc.cpp:1901 rc.cpp:2784 rc.cpp:3835 rc.cpp:4739 #, kde-format msgid "Calculated Price" msgstr "Berekende prijs" #: rc.cpp:156 rc.cpp:1066 rc.cpp:1904 rc.cpp:2787 rc.cpp:3838 rc.cpp:4742 #, kde-format msgid "Fix Costs Part:" msgstr "Post vaste kosten:" #: rc.cpp:159 rc.cpp:1069 rc.cpp:1907 rc.cpp:2790 rc.cpp:3841 rc.cpp:4745 #, kde-format msgid "Material Part:" msgstr "Post materiaal:" #: rc.cpp:162 rc.cpp:1072 rc.cpp:1910 rc.cpp:2793 rc.cpp:3844 rc.cpp:4748 #, kde-format msgid "Profit:" msgstr "Winst:" #: rc.cpp:166 rc.cpp:1076 rc.cpp:1914 rc.cpp:2797 rc.cpp:3848 rc.cpp:4752 #, no-c-format, kde-format msgid " %" msgstr " %" #: rc.cpp:169 rc.cpp:1079 rc.cpp:1917 rc.cpp:2800 rc.cpp:3851 rc.cpp:4755 #, kde-format msgid "Time Calculation Part:" msgstr "Post arbeid:" #: rc.cpp:172 rc.cpp:1082 rc.cpp:1920 rc.cpp:2803 rc.cpp:3854 rc.cpp:4758 #, kde-format msgid "Calculated Price:" msgstr "Berekende prijs: " #: rc.cpp:175 rc.cpp:1085 rc.cpp:1923 rc.cpp:2806 rc.cpp:3857 rc.cpp:4761 #, kde-format msgid "88.888,88 €" msgstr "88.888,88 €" #: rc.cpp:178 rc.cpp:1088 rc.cpp:1959 rc.cpp:2842 rc.cpp:3860 rc.cpp:4764 #, kde-format msgid "Database creation and initial schema setup:" msgstr "Database aanmaken en de initiële aanmaak opnieuw uitvoeren." #: rc.cpp:181 rc.cpp:190 rc.cpp:844 rc.cpp:1091 rc.cpp:1100 rc.cpp:1706 #: rc.cpp:1962 rc.cpp:1971 rc.cpp:2598 rc.cpp:2845 rc.cpp:2854 rc.cpp:3502 #: rc.cpp:3863 rc.cpp:3872 rc.cpp:4385 rc.cpp:4767 rc.cpp:4776 rc.cpp:5292 #, kde-format msgid "0 / 129" msgstr "0 / 129" #: rc.cpp:184 rc.cpp:193 rc.cpp:847 rc.cpp:1094 rc.cpp:1103 rc.cpp:1709 #: rc.cpp:1965 rc.cpp:1974 rc.cpp:2601 rc.cpp:2848 rc.cpp:2857 rc.cpp:3505 #: rc.cpp:3866 rc.cpp:3875 rc.cpp:4388 rc.cpp:4770 rc.cpp:4779 rc.cpp:5295 #, kde-format msgid "X" msgstr "X" #: rc.cpp:187 rc.cpp:1097 rc.cpp:1968 rc.cpp:2851 rc.cpp:3869 rc.cpp:4773 #, kde-format msgid "Filling the database with initial values:" msgstr "Bezig met het vullen van de database met beginwaarden:" #: rc.cpp:196 rc.cpp:850 rc.cpp:1106 rc.cpp:1712 rc.cpp:1977 rc.cpp:2604 #: rc.cpp:2860 rc.cpp:3508 rc.cpp:3878 rc.cpp:4391 rc.cpp:4782 rc.cpp:5298 #, kde-format msgid "Status: " msgstr "Status: " #: rc.cpp:199 rc.cpp:1109 rc.cpp:1980 rc.cpp:2863 rc.cpp:3881 rc.cpp:4785 #, kde-format msgid "Database setup status..." msgstr "Status van het instellen van de database..." #: rc.cpp:202 rc.cpp:1112 rc.cpp:1926 rc.cpp:2809 rc.cpp:3884 rc.cpp:4788 #, kde-format msgid "Bruns Data File:" msgstr "Bruns gegevensbestand:" #: rc.cpp:205 rc.cpp:1115 rc.cpp:1929 rc.cpp:2812 rc.cpp:3887 rc.cpp:4791 #, kde-format msgid "Bruns Key File:" msgstr "Bruns indexbestand:" #: rc.cpp:208 rc.cpp:1118 rc.cpp:1932 rc.cpp:2815 rc.cpp:3890 rc.cpp:4794 #, kde-format msgid "Qt Database Driver:" msgstr "Qt Database Driver:" #: rc.cpp:211 rc.cpp:1121 rc.cpp:1935 rc.cpp:2818 rc.cpp:3893 rc.cpp:4797 #, kde-format msgid "Database Server:" msgstr "Database Server:" #: rc.cpp:214 rc.cpp:1124 rc.cpp:1938 rc.cpp:2821 rc.cpp:3896 rc.cpp:4800 #, kde-format msgid "Server Port:" msgstr "Server Port:" #: rc.cpp:217 rc.cpp:1127 rc.cpp:1941 rc.cpp:2824 rc.cpp:3899 rc.cpp:4803 #, kde-format msgid "Database Name" msgstr "Database naam" #: rc.cpp:220 rc.cpp:700 rc.cpp:1130 rc.cpp:1555 rc.cpp:1944 rc.cpp:2399 #: rc.cpp:2827 rc.cpp:3315 rc.cpp:3902 rc.cpp:4238 rc.cpp:4806 rc.cpp:5145 #, kde-format msgid "Database User:" msgstr "Database gebruiker:" #: rc.cpp:223 rc.cpp:1133 rc.cpp:1947 rc.cpp:2830 rc.cpp:3905 rc.cpp:4809 #, kde-format msgid "Database Password:" msgstr "Database wachtwoord:" #: rc.cpp:226 rc.cpp:1136 rc.cpp:1950 rc.cpp:2833 rc.cpp:3908 rc.cpp:4812 #, kde-format msgid "The default database name when creating new databases" msgstr "De standaard database-naam bij de aanmaak van een nieuwe database" #: rc.cpp:229 rc.cpp:1139 rc.cpp:1953 rc.cpp:2836 rc.cpp:3911 rc.cpp:4815 #, kde-format msgid "File Name" msgstr "Bestandsnaam" #: rc.cpp:232 rc.cpp:1142 rc.cpp:1956 rc.cpp:2839 rc.cpp:3914 rc.cpp:4818 #, kde-format msgid "The path where database file are stored. Leave empty!" msgstr "De locatie waar database-bestanden zijn opgeslagen. Laat dit leeg!" #: rc.cpp:235 rc.cpp:1145 rc.cpp:2016 rc.cpp:2899 rc.cpp:3640 rc.cpp:4544 #, kde-format msgid "Database Update:" msgstr "Bijwerken database:" #: rc.cpp:238 rc.cpp:1148 rc.cpp:2019 rc.cpp:2902 rc.cpp:3643 rc.cpp:4547 #, kde-format msgid "Overall Progress:" msgstr "Totale voortgang:" #: rc.cpp:241 rc.cpp:1151 rc.cpp:2022 rc.cpp:2905 rc.cpp:3646 rc.cpp:4550 #, kde-format msgid "Detail Progress:" msgstr "Detail voortgang:" #: rc.cpp:244 rc.cpp:1154 rc.cpp:2025 rc.cpp:2908 rc.cpp:3649 rc.cpp:4553 #, kde-format msgid "Status:" msgstr "Status: " #: rc.cpp:247 rc.cpp:1289 rc.cpp:1727 rc.cpp:2610 rc.cpp:3631 rc.cpp:4535 #, kde-format msgid "" "

            Kraft uses a database backend to store values. By " "default it uses a file based database with easy setup targeted to single " "user mode.


            " msgstr "" "

            Kraft gebruikt als backend een database om waarden in " "op te slaan. Standaard gebruikt het een makkelijk op te zetten database " "bedoeld voor gebruik door een enkele " "gebruiker.


            " #: rc.cpp:250 rc.cpp:1292 rc.cpp:1730 rc.cpp:2613 rc.cpp:3634 rc.cpp:4538 #, kde-format msgid "SQLite 3 - file based database (default)" msgstr "SQLite 3 - bestand gebaseerde database (standaard)" #: rc.cpp:253 rc.cpp:1295 rc.cpp:1733 rc.cpp:2616 rc.cpp:3637 rc.cpp:4541 #, kde-format msgid "MySQL Serverbased Database for advanced Setups" msgstr "MySQL Servergebaseerde Database voor een geavanceerde opzet" #: rc.cpp:256 rc.cpp:865 rc.cpp:1736 rc.cpp:2619 rc.cpp:3917 rc.cpp:4821 #, kde-format msgid "Footer Texts" msgstr "Voettekst" #: rc.cpp:259 rc.cpp:868 rc.cpp:1739 rc.cpp:2622 rc.cpp:3920 rc.cpp:4824 #, kde-format msgid "&Summary Text on Last Page:" msgstr "Samenvatting op laatste pagina:" #: rc.cpp:262 rc.cpp:871 rc.cpp:1742 rc.cpp:2625 rc.cpp:3923 rc.cpp:4827 #, kde-format msgid "&Greeting:" msgstr "Aanhef" #: rc.cpp:268 rc.cpp:877 rc.cpp:1748 rc.cpp:2631 rc.cpp:3929 rc.cpp:4833 #, kde-format msgid "Document &Tax:" msgstr "Belas&ting per document:" #: rc.cpp:271 rc.cpp:880 rc.cpp:2028 rc.cpp:2911 rc.cpp:3932 rc.cpp:4836 #, kde-format msgid "TextLabel" msgstr "Tekstlabel" #: rc.cpp:274 rc.cpp:883 rc.cpp:2031 rc.cpp:2914 rc.cpp:3935 rc.cpp:4839 #, kde-format msgid "&Project:" msgstr "&Project:" #: rc.cpp:277 rc.cpp:886 rc.cpp:2034 rc.cpp:2917 rc.cpp:3938 rc.cpp:4842 #, kde-format msgid "&Whiteboard:" msgstr "&Whiteboard:" #: rc.cpp:280 rc.cpp:889 rc.cpp:2037 rc.cpp:2920 rc.cpp:3941 rc.cpp:4845 #, kde-format msgid "" "Enter a label that describes the project. This may appear on the customer " "document." msgstr "" "Geef een label op dat het project beschrijft. Dit kan ook op het document " "voor de klant verschijnen." #: rc.cpp:283 rc.cpp:892 rc.cpp:2040 rc.cpp:2923 rc.cpp:3944 rc.cpp:4848 #, kde-format msgid "Postal &Address:" msgstr "Post &Adres:" #: rc.cpp:286 rc.cpp:895 rc.cpp:2043 rc.cpp:2926 rc.cpp:3947 rc.cpp:4851 #, kde-format msgid "not selected" msgstr "niet ingesteld" #: rc.cpp:289 rc.cpp:898 rc.cpp:2046 rc.cpp:2929 rc.cpp:3950 rc.cpp:4854 #, kde-format msgid "Select an addressee from the address books." msgstr "Selecteer een adres in het adresboek." #: rc.cpp:292 rc.cpp:901 rc.cpp:2049 rc.cpp:2932 rc.cpp:3953 rc.cpp:4857 #, kde-format msgid "select..." msgstr "Selecteren..." #: rc.cpp:295 rc.cpp:904 rc.cpp:2052 rc.cpp:2935 rc.cpp:3956 rc.cpp:4860 #, kde-format msgid "&Salutatory Address:" msgstr "Aanhef:" #: rc.cpp:298 rc.cpp:907 rc.cpp:2055 rc.cpp:2938 rc.cpp:3959 rc.cpp:4863 #, kde-format msgid "Customer:" msgstr "Klant:" #: rc.cpp:301 rc.cpp:910 rc.cpp:2058 rc.cpp:2941 rc.cpp:3962 rc.cpp:4866 #, kde-format msgid "&Entry Text on First Page:" msgstr "Geeft tekst op voor eerste pagina:" #: rc.cpp:304 rc.cpp:733 rc.cpp:1157 rc.cpp:1588 rc.cpp:2061 rc.cpp:2432 #: rc.cpp:2944 rc.cpp:3348 rc.cpp:3514 rc.cpp:4271 rc.cpp:4418 rc.cpp:5178 #, kde-format msgid "Click to add a new document type to the list." msgstr "Klik om een nieuw documenttype aan de lijst toe te voegen." #: rc.cpp:310 rc.cpp:1163 rc.cpp:2067 rc.cpp:2950 rc.cpp:3520 rc.cpp:4424 #, kde-format msgid "click to edit the selected document type name" msgstr "Klik om de naam van het geselecteerde documenttype te bewerken." #: rc.cpp:316 rc.cpp:739 rc.cpp:1169 rc.cpp:1594 rc.cpp:2073 rc.cpp:2438 #: rc.cpp:2956 rc.cpp:3354 rc.cpp:3526 rc.cpp:4277 rc.cpp:4430 rc.cpp:5184 #, kde-format msgid "click to remove the current document type" msgstr "Klik om het geselecteerde documenttype te verwijderen." #: rc.cpp:322 rc.cpp:1175 rc.cpp:2079 rc.cpp:2962 rc.cpp:3532 rc.cpp:4436 #, kde-format msgid "Unique Document Number" msgstr "Uniek documentnummer" #: rc.cpp:325 rc.cpp:1178 rc.cpp:2082 rc.cpp:2965 rc.cpp:3535 rc.cpp:4439 #, kde-format msgid "Number &Cycle:" msgstr "Volg&nummer:" #: rc.cpp:328 rc.cpp:337 rc.cpp:340 rc.cpp:724 rc.cpp:1181 rc.cpp:1190 #: rc.cpp:1193 rc.cpp:1579 rc.cpp:2085 rc.cpp:2094 rc.cpp:2097 rc.cpp:2423 #: rc.cpp:2968 rc.cpp:2977 rc.cpp:2980 rc.cpp:3339 rc.cpp:3538 rc.cpp:3547 #: rc.cpp:3550 rc.cpp:4262 rc.cpp:4442 rc.cpp:4451 rc.cpp:4454 rc.cpp:5169 #, kde-format msgid "example" msgstr "voorbeeld" #: rc.cpp:331 rc.cpp:1184 rc.cpp:2088 rc.cpp:2971 rc.cpp:3541 rc.cpp:4445 #, kde-format msgid "ident Template:" msgstr "ident Template:" #: rc.cpp:334 rc.cpp:718 rc.cpp:1187 rc.cpp:1573 rc.cpp:2091 rc.cpp:2417 #: rc.cpp:2974 rc.cpp:3333 rc.cpp:3544 rc.cpp:4256 rc.cpp:4448 rc.cpp:5163 #, kde-format msgid "Example Id:" msgstr "Voorbeeld volgnummer:" #: rc.cpp:343 rc.cpp:1196 rc.cpp:2100 rc.cpp:2983 rc.cpp:3553 rc.cpp:4457 #, kde-format msgid "Counter:" msgstr "Teller:" #: rc.cpp:346 rc.cpp:1199 rc.cpp:2103 rc.cpp:2986 rc.cpp:3556 rc.cpp:4460 #, kde-format msgid "&Edit Number Cycles..." msgstr "Volgnummersysteem inst&ellen..." #: rc.cpp:349 rc.cpp:1202 rc.cpp:2106 #, kde-format msgid "Template for PDF Creation" msgstr "Sjabloon voor aanmaak PDF" #: rc.cpp:352 rc.cpp:1205 #, kde-format msgid "&Template File" msgstr "Sjabloon-bes&tand" #: rc.cpp:355 rc.cpp:1208 rc.cpp:2115 rc.cpp:2998 rc.cpp:3568 rc.cpp:4472 #, kde-format msgid "W&atermark:" msgstr "W&atermerk:" #: rc.cpp:358 rc.cpp:1211 rc.cpp:2121 rc.cpp:3001 rc.cpp:3571 rc.cpp:4475 #, kde-format msgid "no watermark" msgstr "geen watermerk" #: rc.cpp:361 rc.cpp:1214 rc.cpp:2124 rc.cpp:3004 rc.cpp:3574 rc.cpp:4478 #, kde-format msgid "on first page" msgstr "op eerste pagina" #: rc.cpp:364 rc.cpp:1217 rc.cpp:2127 rc.cpp:3007 rc.cpp:3577 rc.cpp:4481 #, kde-format msgid "on all pages" msgstr "op alle pagina´s" #: rc.cpp:367 rc.cpp:1220 #, kde-format msgid "&Watermark File" msgstr "&Watermerk bestand" #: rc.cpp:370 rc.cpp:1223 rc.cpp:1983 rc.cpp:2866 rc.cpp:3598 rc.cpp:4502 #, kde-format msgid "Calculation Parts Fix" msgstr "Post vaste kosten" #: rc.cpp:373 rc.cpp:1226 rc.cpp:1986 rc.cpp:2869 rc.cpp:3601 rc.cpp:4505 #, kde-format msgid "

            Fix Cost Parts

            " msgstr "

            Post vaste kosten

            " #: rc.cpp:376 rc.cpp:1229 rc.cpp:1989 rc.cpp:2872 rc.cpp:3604 rc.cpp:4508 #, kde-format msgid "Add a fix cost for one unit of the template:" msgstr "Voert een post vaste kosten toe aan dit sjabloon:" #: rc.cpp:379 rc.cpp:808 rc.cpp:1232 rc.cpp:1529 rc.cpp:1992 rc.cpp:2528 #: rc.cpp:2875 rc.cpp:3432 rc.cpp:3607 rc.cpp:4346 rc.cpp:4511 rc.cpp:5253 #, kde-format msgid "&Label:" msgstr "&Label:" #: rc.cpp:382 rc.cpp:1235 rc.cpp:1995 rc.cpp:2878 rc.cpp:3610 rc.cpp:4514 #, kde-format msgid "describing text" msgstr "Omschrijving" #: rc.cpp:385 rc.cpp:1238 rc.cpp:1998 rc.cpp:2881 rc.cpp:3613 rc.cpp:4517 #, kde-format msgid "amortisation" msgstr "korting" #: rc.cpp:388 rc.cpp:680 rc.cpp:1241 rc.cpp:1511 rc.cpp:2001 rc.cpp:2211 #: rc.cpp:2884 rc.cpp:3106 rc.cpp:3616 rc.cpp:4218 rc.cpp:4520 rc.cpp:5125 #, kde-format msgid "&Amount:" msgstr "&Aantal:" #: rc.cpp:391 rc.cpp:1244 rc.cpp:2004 rc.cpp:2887 rc.cpp:3619 rc.cpp:4523 #, kde-format msgid "amount multiplier" msgstr "amount multiplier" #: rc.cpp:394 rc.cpp:1247 rc.cpp:2007 rc.cpp:2890 rc.cpp:3622 rc.cpp:4526 #, kde-format msgid "at &Price:" msgstr "voor de prijs van:" #: rc.cpp:397 rc.cpp:683 rc.cpp:1250 rc.cpp:1514 rc.cpp:2010 rc.cpp:2214 #: rc.cpp:2893 rc.cpp:3109 rc.cpp:3625 rc.cpp:4221 rc.cpp:4529 rc.cpp:5128 #, kde-format msgid "Price for one piece" msgstr "Prijs per stuk" #: rc.cpp:400 rc.cpp:1253 rc.cpp:2013 rc.cpp:2896 rc.cpp:3628 rc.cpp:4532 #, kde-format msgid "€" msgstr "€" #: rc.cpp:403 rc.cpp:1256 rc.cpp:2133 rc.cpp:3028 rc.cpp:3652 rc.cpp:4556 #, kde-format msgid "Form" msgstr "Formulier" #: rc.cpp:406 rc.cpp:1259 rc.cpp:2136 rc.cpp:3031 rc.cpp:3655 rc.cpp:4559 #: tagtemplatesdialog.cpp:58 #, kde-format msgid "Name:" msgstr "Naam:" #: rc.cpp:409 rc.cpp:1262 rc.cpp:2139 rc.cpp:3034 rc.cpp:3658 rc.cpp:4562 #, kde-format msgid "Organization:" msgstr "Organisatie:" #: rc.cpp:412 rc.cpp:1265 rc.cpp:2142 rc.cpp:3037 rc.cpp:3661 rc.cpp:4565 #, kde-format msgid "Street:" msgstr "Straat:" #: rc.cpp:415 rc.cpp:1268 rc.cpp:2145 rc.cpp:3040 rc.cpp:3664 rc.cpp:4568 #, kde-format msgid "Post Code:" msgstr "Postcode:" #: rc.cpp:418 rc.cpp:1271 rc.cpp:2148 rc.cpp:3043 rc.cpp:3667 rc.cpp:4571 #, kde-format msgid "City:" msgstr "Stad:" #: rc.cpp:421 rc.cpp:1274 rc.cpp:2151 rc.cpp:3046 rc.cpp:3670 rc.cpp:4574 #, kde-format msgid "Phone:" msgstr "Telefoon:" #: rc.cpp:424 rc.cpp:1277 rc.cpp:2154 rc.cpp:3049 rc.cpp:3673 rc.cpp:4577 #, kde-format msgid "Fax:" msgstr "Fax:" #: rc.cpp:427 rc.cpp:1280 rc.cpp:2157 rc.cpp:3052 rc.cpp:3676 rc.cpp:4580 #, kde-format msgid "Mobile Phone:" msgstr "Mobiele telefoon:" #: rc.cpp:430 rc.cpp:1283 rc.cpp:2160 rc.cpp:3055 rc.cpp:3679 rc.cpp:4583 #, kde-format msgid "EMail:" msgstr "EMail:" #: rc.cpp:433 rc.cpp:1286 rc.cpp:2163 rc.cpp:3058 rc.cpp:3682 rc.cpp:4586 #, kde-format msgid "Website:" msgstr "Website:" #: rc.cpp:436 rc.cpp:1298 rc.cpp:2166 rc.cpp:3061 rc.cpp:3965 rc.cpp:4869 #, kde-format msgid "Import Document Items" msgstr "Document-items importeren" #: rc.cpp:439 rc.cpp:1301 rc.cpp:2169 rc.cpp:3064 rc.cpp:3968 rc.cpp:4872 #, kde-format msgid "Import information" msgstr "Informatie importeren" #: rc.cpp:442 rc.cpp:1304 rc.cpp:2172 rc.cpp:3067 rc.cpp:3971 rc.cpp:4875 #, kde-format msgid "Select a &File to import from:" msgstr "Selecteer het bestand wat u wilt importeren:" #: rc.cpp:445 rc.cpp:1307 rc.cpp:2175 rc.cpp:3070 rc.cpp:3974 rc.cpp:4878 #, kde-format msgid "FixMe!" msgstr "FixMe!" #: rc.cpp:448 rc.cpp:1310 rc.cpp:2178 rc.cpp:3073 rc.cpp:3977 rc.cpp:4881 #, kde-format msgid "Import &Schema:" msgstr "&Schema importeren" #: rc.cpp:451 rc.cpp:1313 rc.cpp:2181 rc.cpp:3076 rc.cpp:3980 rc.cpp:4884 #, kde-format msgid "this is interesting information about the selected schema" msgstr "Dit is interessante informatie over het gekozen schema" #: rc.cpp:454 rc.cpp:1316 rc.cpp:2184 rc.cpp:3079 rc.cpp:3983 rc.cpp:4887 #, kde-format msgid "Insert all Items &after" msgstr "Alle items invoegen n&a" #: rc.cpp:457 rc.cpp:481 rc.cpp:1319 rc.cpp:1352 rc.cpp:2187 rc.cpp:2241 #: rc.cpp:3082 rc.cpp:3136 rc.cpp:3986 rc.cpp:4010 rc.cpp:4890 rc.cpp:4914 #, kde-format msgid "Tags" msgstr "Tags" #: rc.cpp:463 rc.cpp:1334 rc.cpp:2223 rc.cpp:3118 rc.cpp:3992 rc.cpp:4896 #, kde-format msgid "New Item Text" msgstr "Nieuw item-tekst" #: rc.cpp:466 rc.cpp:1337 rc.cpp:2226 rc.cpp:3121 rc.cpp:3995 rc.cpp:4899 #, kde-format msgid "&insert" msgstr "&Invoegen" #: rc.cpp:469 rc.cpp:1340 rc.cpp:2229 rc.cpp:3124 rc.cpp:3998 rc.cpp:4902 #, kde-format msgid "à" msgstr "a" #: rc.cpp:472 rc.cpp:1343 rc.cpp:2232 rc.cpp:3127 rc.cpp:4001 rc.cpp:4905 #, kde-format msgid "&after item" msgstr "N&a item" #: rc.cpp:475 rc.cpp:1346 rc.cpp:2235 rc.cpp:3130 rc.cpp:4004 rc.cpp:4908 #, kde-format msgid "Keep this item as template for future documents" msgstr "Dit item als sjabloon bewaren voor latere documenten" #: rc.cpp:478 rc.cpp:1349 rc.cpp:2238 rc.cpp:3133 rc.cpp:4007 rc.cpp:4911 #, kde-format msgid "save in &chapter" msgstr "Ops&laan in map" #: rc.cpp:490 rc.cpp:1361 rc.cpp:2250 rc.cpp:3157 rc.cpp:4019 rc.cpp:4923 #, kde-format msgid "Do Database Initialisation" msgstr "Database opnieuw opstarten" #: rc.cpp:493 rc.cpp:1364 rc.cpp:2253 rc.cpp:3160 rc.cpp:4022 rc.cpp:4926 #, kde-format msgid "Do XML archiving of documents they're printed?" msgstr "Documenten bij het afdrukken als XML archiveren?" #: rc.cpp:496 rc.cpp:1367 rc.cpp:2256 rc.cpp:3163 rc.cpp:4025 rc.cpp:4929 #, kde-format msgid "" "Where Kraft stores the XML archive documents. If empty, KDEHOME/share/apps " "is used." msgstr "" "Waar Kraft de XML archieven opslaat. Als dit leeg is, dan wordt \n" "KDEHOME/share/apps gebruikt." #: rc.cpp:499 rc.cpp:1370 rc.cpp:2259 rc.cpp:3166 rc.cpp:4028 rc.cpp:4932 #, kde-format msgid "The local xml document storage path" msgstr "De locatie voor de lokaal opgeslagen XML documenten" #: rc.cpp:502 rc.cpp:1373 rc.cpp:2262 rc.cpp:3169 rc.cpp:4031 rc.cpp:4935 #, kde-format msgid "Default mail user agent. Set xdg for xdg-email" msgstr "" "Standaard email programma. Stel in op xdg voor het programma xdg-email." #: rc.cpp:505 rc.cpp:508 rc.cpp:1376 rc.cpp:1379 rc.cpp:2265 rc.cpp:2268 #: rc.cpp:3172 rc.cpp:3175 rc.cpp:4034 rc.cpp:4037 rc.cpp:4938 rc.cpp:4941 #, kde-format msgid "The default geometry of the document view dialog" msgstr "" "De standaard grootte van het dialoogvenster voor het weergeven van het " "document." #: rc.cpp:511 rc.cpp:1382 rc.cpp:2271 rc.cpp:3178 rc.cpp:4040 rc.cpp:4944 #, kde-format msgid "The current state of the portal" msgstr "De huidige status van de portal" #: rc.cpp:514 rc.cpp:1385 rc.cpp:2274 rc.cpp:3181 rc.cpp:4043 rc.cpp:4947 #, kde-format msgid "The current geometry of the portal" msgstr "De huidige grootte van de portal" #: rc.cpp:517 rc.cpp:1388 rc.cpp:2277 rc.cpp:3184 rc.cpp:4046 rc.cpp:4950 #, kde-format msgid "The current geometry of the new doc assistant" msgstr "De huidige grootte van de nieuwe document assistent" #: rc.cpp:520 rc.cpp:1391 rc.cpp:2280 rc.cpp:3187 rc.cpp:4049 rc.cpp:4953 #, kde-format msgid "The splitter position of the document view dialog" msgstr "De schuifpijl-positie van de document weergave" #: rc.cpp:523 rc.cpp:1394 rc.cpp:2283 rc.cpp:3190 rc.cpp:4052 rc.cpp:4956 #, kde-format msgid "The default size of the material catalog view" msgstr "" "De standaard grootte van het dialoogvenster voor de weergave van de \n" "materiaalcatalogus." #: rc.cpp:526 rc.cpp:1397 rc.cpp:2286 rc.cpp:3193 rc.cpp:4055 rc.cpp:4959 #, kde-format msgid "The splitter setting for the doc assistant" msgstr "De schuifpijl-instelling voor de document assistent" #: rc.cpp:529 rc.cpp:1400 rc.cpp:2289 rc.cpp:3196 rc.cpp:4058 rc.cpp:4962 #, kde-format msgid "The window size of the template to document dialog for plants" msgstr "" "De venstergrootte van het sjabloon voor het documentendialoog van de planten" #: rc.cpp:532 rc.cpp:1403 rc.cpp:2292 rc.cpp:3199 rc.cpp:4061 rc.cpp:4965 #, kde-format msgid "The window size of the template to document dialog" msgstr "De venstergrootte van het sjabloon voor het documentendialoog" #: rc.cpp:535 rc.cpp:1406 rc.cpp:2295 rc.cpp:3202 rc.cpp:4064 rc.cpp:4968 #, kde-format msgid "The digest list column arrangement for the Latest-list" msgstr "The digest list column arrangement for the Latest-list" #: rc.cpp:538 rc.cpp:1409 rc.cpp:2298 rc.cpp:3205 rc.cpp:4067 rc.cpp:4971 #, kde-format msgid "The digest list column arrangement for the all-list" msgstr "The digest list column arrangement for the all-list" #: rc.cpp:541 rc.cpp:1412 rc.cpp:2301 rc.cpp:3208 rc.cpp:4070 rc.cpp:4974 #, kde-format msgid "The digest list column arrangement for timeline" msgstr "The digest list column arrangement for timeline" #: rc.cpp:544 rc.cpp:1415 rc.cpp:2304 rc.cpp:3211 rc.cpp:4073 rc.cpp:4977 #, kde-format msgid "The sizes of the slider in the address picker Widget" msgstr "The sizes of the slider in the address picker Widget" #: rc.cpp:547 rc.cpp:1418 rc.cpp:2307 rc.cpp:3214 rc.cpp:4076 rc.cpp:4980 #, kde-format msgid "The state of the treeview inside the address selector widget" msgstr "The state of the treeview inside the address selector widget" #: rc.cpp:550 rc.cpp:1421 rc.cpp:2310 rc.cpp:3217 rc.cpp:4079 rc.cpp:4983 #, kde-format msgid "Size of the address select dialog" msgstr "Grootte van adres zoekvenster" #: rc.cpp:553 rc.cpp:1424 rc.cpp:2313 rc.cpp:3220 rc.cpp:4082 rc.cpp:4986 #, kde-format msgid "State of the window of the material catalog" msgstr "State of the window of the material catalog" #: rc.cpp:556 rc.cpp:1427 rc.cpp:2316 rc.cpp:3223 rc.cpp:4085 rc.cpp:4989 #, kde-format msgid "Geometry of the material catalog" msgstr "Opbouw van de materiaal catalogus" #: rc.cpp:559 rc.cpp:1430 rc.cpp:2319 rc.cpp:3226 rc.cpp:4088 rc.cpp:4992 #, kde-format msgid "State of the header of the material catalog" msgstr "State of the header of the material catalog" #: rc.cpp:562 rc.cpp:1433 rc.cpp:2322 rc.cpp:3229 rc.cpp:4091 rc.cpp:4995 #, kde-format msgid "State of the window of the template catalog" msgstr "State of the window of the template catalog" #: rc.cpp:565 rc.cpp:1436 rc.cpp:2325 rc.cpp:3232 rc.cpp:4094 rc.cpp:4998 #, kde-format msgid "Geometry the template catalog" msgstr "Geometry the template catalog" #: rc.cpp:568 rc.cpp:1439 rc.cpp:2328 rc.cpp:3235 rc.cpp:4097 rc.cpp:5001 #, kde-format msgid "State of the header of the template catalog" msgstr "State of the header of the template catalog" #: rc.cpp:571 rc.cpp:1442 rc.cpp:2331 rc.cpp:3238 rc.cpp:4100 rc.cpp:5004 #, kde-format msgid "" "Default percentage the sale price for a material should be higher than its " "purchase price" msgstr "" "Standaard zou voor materiaal de verkoopprijs hoger moeten zijn dan de " "inkoopprijs" #: rc.cpp:574 rc.cpp:1445 rc.cpp:2334 rc.cpp:3241 rc.cpp:4103 rc.cpp:5007 #, kde-format msgid "The name of the last selected chapter in the catalog" msgstr "The name of the last selected chapter in the catalog" #: rc.cpp:577 rc.cpp:1448 rc.cpp:2337 rc.cpp:3244 rc.cpp:4106 rc.cpp:5010 #, kde-format msgid "The complete filename of the trml2pdf binary" msgstr "Het complete bestandsnaam van het trml2pdf-programma" #: rc.cpp:580 rc.cpp:1451 rc.cpp:2340 rc.cpp:3247 rc.cpp:4109 rc.cpp:5013 #, kde-format msgid "The path to the output directory for document pdfs" msgstr "De locatie voor de document-pdfs" #: rc.cpp:583 rc.cpp:1454 rc.cpp:2343 rc.cpp:3250 rc.cpp:4112 rc.cpp:5016 #, kde-format msgid "The last created doc type." msgstr "Laatst aangemaakte documenttype." #: rc.cpp:586 rc.cpp:1457 rc.cpp:2346 rc.cpp:3253 rc.cpp:4115 rc.cpp:5019 #, kde-format msgid "The date format for print." msgstr "De datum-instelling voor uitgeprinte documenten." #: rc.cpp:589 rc.cpp:1460 rc.cpp:2349 rc.cpp:3256 rc.cpp:4118 rc.cpp:5022 #, kde-format msgid "The greeting below on the document footer." msgstr "The greeting below on the document footer." #: rc.cpp:592 rc.cpp:1463 rc.cpp:2352 rc.cpp:3259 rc.cpp:4121 rc.cpp:5025 #, kde-format msgid "The salut message on the document header." msgstr "De aanhef in het briefhoofd." #: rc.cpp:595 rc.cpp:1466 rc.cpp:2355 rc.cpp:3262 rc.cpp:4124 rc.cpp:5028 #, kde-format msgid "" "The name of the catalog chapter where to store new templates in by default" msgstr "" "De naam van de catalogusmap waar standaard nieuwe sjablonen worden " "opgeslagen" #: rc.cpp:598 rc.cpp:1469 rc.cpp:2358 rc.cpp:3265 rc.cpp:4127 rc.cpp:5031 #, kde-format msgid "The name of the last used import schema for items." msgstr "De naam van de laatst gebruikte schema voor het importeren van items." #: rc.cpp:601 rc.cpp:1472 rc.cpp:2361 rc.cpp:3268 rc.cpp:4130 rc.cpp:5034 #, kde-format msgid "The name of the last used input file for items." msgstr "The name of the last used input file for items." #: rc.cpp:604 rc.cpp:1475 rc.cpp:2364 rc.cpp:3271 rc.cpp:4133 rc.cpp:5037 #, kde-format msgid "" "User name as reference to the KAddressbook to identify 'my' address " "(DEPRECATED)." msgstr "" "Gebruikersnaam als referentie naar het KAddressbook om \"mijn\" adres te \n" "identificeren (Verouderd)." #: rc.cpp:607 rc.cpp:1478 rc.cpp:2367 rc.cpp:3274 rc.cpp:4136 rc.cpp:5040 #, kde-format msgid "" "UID of the user as reference to the KAddressbook to identify 'my' address." msgstr "" "UID of the user as reference to the KAddressbook to identify 'my' address." #: rc.cpp:610 rc.cpp:1481 rc.cpp:2370 rc.cpp:3286 rc.cpp:4148 rc.cpp:5052 #, kde-format msgid "The doc id template" msgstr "The doc id template" #: rc.cpp:613 rc.cpp:1484 rc.cpp:2373 rc.cpp:3289 rc.cpp:4151 rc.cpp:5055 #, kde-format msgid "Localization on document level" msgstr "Per document taal instellen" #: rc.cpp:616 rc.cpp:1487 rc.cpp:2376 rc.cpp:3292 rc.cpp:4154 rc.cpp:5058 #, kde-format msgid "The tax default for new documents." msgstr "De standaard belastingtarief voor nieuwe documenten." #: rc.cpp:619 rc.cpp:1490 rc.cpp:2379 rc.cpp:3295 rc.cpp:4157 rc.cpp:5061 #, kde-format msgid "The label for alternative positions" msgstr "Het label voor alternatieve voorstellen" #: rc.cpp:622 rc.cpp:625 rc.cpp:1493 rc.cpp:1496 rc.cpp:2382 rc.cpp:2385 #: rc.cpp:3298 rc.cpp:3301 rc.cpp:4160 rc.cpp:4163 rc.cpp:5064 rc.cpp:5067 #, kde-format msgid "The label for demand positions" msgstr "Het label voor meerwerk-posten" #: rc.cpp:631 rc.cpp:1325 rc.cpp:2193 rc.cpp:3088 rc.cpp:4169 rc.cpp:5076 #, kde-format msgid "Settings" msgstr "Instellingen" #: rc.cpp:637 rc.cpp:1669 rc.cpp:2561 rc.cpp:3465 rc.cpp:4175 rc.cpp:5082 #, kde-format msgid "Edit Material" msgstr "Materiaal bewerken" #: rc.cpp:640 rc.cpp:1672 rc.cpp:2564 rc.cpp:3468 rc.cpp:4178 rc.cpp:5085 #, kde-format msgid "Store in C&hapter" msgstr "Op&slaan in map" #: rc.cpp:646 rc.cpp:1678 rc.cpp:2570 rc.cpp:3474 rc.cpp:4184 rc.cpp:5091 #, kde-format msgid "Pac&kaged:" msgstr "Verpa&kt:" #: rc.cpp:649 rc.cpp:1681 rc.cpp:2573 rc.cpp:3477 rc.cpp:4187 rc.cpp:5094 #, kde-format msgid "per P&ackage" msgstr "per pak" #: rc.cpp:652 rc.cpp:1684 rc.cpp:2576 rc.cpp:3480 rc.cpp:4190 rc.cpp:5097 #, kde-format msgid "Prices" msgstr "Prijzen" #: rc.cpp:655 rc.cpp:1687 rc.cpp:2579 rc.cpp:3483 rc.cpp:4193 rc.cpp:5100 #, kde-format msgid "= Price of &Sale:" msgstr "=Verkoopprij&s:" #: rc.cpp:658 rc.cpp:1690 rc.cpp:2582 rc.cpp:3486 rc.cpp:4196 rc.cpp:5103 #, kde-format msgid "pl&us" msgstr "pl&us" #: rc.cpp:662 rc.cpp:755 rc.cpp:1610 rc.cpp:1694 rc.cpp:2454 rc.cpp:2586 #: rc.cpp:3370 rc.cpp:3490 rc.cpp:4200 rc.cpp:4293 rc.cpp:5107 rc.cpp:5200 #, no-c-format, kde-format msgid "%" msgstr "%" #: rc.cpp:665 rc.cpp:1697 rc.cpp:2589 rc.cpp:3493 rc.cpp:4203 rc.cpp:5110 #, kde-format msgid "&Purchase Price:" msgstr "Inkoop&prijs:" #: rc.cpp:668 rc.cpp:1499 rc.cpp:2199 rc.cpp:3094 rc.cpp:4206 rc.cpp:5113 #, kde-format msgid "Calculation Item Material" msgstr "Materiaal toevoegen aan de berekening" #: rc.cpp:671 rc.cpp:1502 rc.cpp:2202 rc.cpp:3097 rc.cpp:4209 rc.cpp:5116 #, kde-format msgid "

            Calculation Part 'Material'

            " msgstr "

            Post materiaal

            " #: rc.cpp:674 rc.cpp:1505 rc.cpp:2205 rc.cpp:3100 rc.cpp:4212 rc.cpp:5119 #, kde-format msgid "Add Material to the template calculation." msgstr "Materiaal toevoegen aan de berekening in het sjabloon." #: rc.cpp:677 rc.cpp:1508 rc.cpp:2208 rc.cpp:3103 rc.cpp:4215 rc.cpp:5122 #, kde-format msgid "material" msgstr "materiaal" #: rc.cpp:686 rc.cpp:1517 rc.cpp:2217 rc.cpp:3112 rc.cpp:4224 rc.cpp:5131 #, kde-format msgid "unit" msgstr "Eenheid" #: rc.cpp:689 rc.cpp:1544 rc.cpp:2388 rc.cpp:3304 rc.cpp:4227 rc.cpp:5134 #, kde-format msgid "" "Please enter the MySQL Database server settings. \n" "\n" "For detailed setup instructions for the MySQL to use with Kraft please check the Kraft website." msgstr "" "Geef de instellingen op voor de MySQL Database server\n" "\n" "Ga voor gedetailleerde instructies voor hoe MySQL samen met Kraft te \n" "gebruiken naar de website van Kraft." #: rc.cpp:694 rc.cpp:1549 rc.cpp:2393 rc.cpp:3309 rc.cpp:4232 rc.cpp:5139 #, kde-format msgid "Database Host:" msgstr "Database Host:" #: rc.cpp:697 rc.cpp:1552 rc.cpp:2396 rc.cpp:3312 rc.cpp:4235 rc.cpp:5142 #, kde-format msgid "Database Name:" msgstr "Databasenaam:" #: rc.cpp:703 rc.cpp:1558 rc.cpp:2402 rc.cpp:3318 rc.cpp:4241 rc.cpp:5148 #, kde-format msgid "Password:" msgstr "Wachtwoord" #: rc.cpp:706 rc.cpp:1561 rc.cpp:2405 rc.cpp:3321 rc.cpp:4244 rc.cpp:5151 #, kde-format msgid "

            Edit Number Cycles

            " msgstr "

            Volgnummersysteem bewerken

            " #: rc.cpp:709 rc.cpp:1564 rc.cpp:2408 rc.cpp:3324 rc.cpp:4247 rc.cpp:5154 #, kde-format msgid "Number Cycle Details" msgstr "Details volgnummers" #: rc.cpp:712 rc.cpp:1567 rc.cpp:2411 rc.cpp:3327 rc.cpp:4250 rc.cpp:5157 #, kde-format msgid "&Number Cycle:" msgstr "Volg&nummers:" #: rc.cpp:715 rc.cpp:1570 rc.cpp:2414 rc.cpp:3330 rc.cpp:4253 rc.cpp:5160 #, kde-format msgid "&Counter:" msgstr "Teller:" #: rc.cpp:721 rc.cpp:1576 rc.cpp:2420 rc.cpp:3336 rc.cpp:4259 rc.cpp:5166 #, kde-format msgid "ident &Template:" msgstr "Volgnummer-sjabloon:" #: rc.cpp:727 rc.cpp:1582 rc.cpp:2426 rc.cpp:3342 rc.cpp:4265 rc.cpp:5172 #, kde-format msgid "&Select a number cycle and edit the details on the right:" msgstr "Kies een volgnummersysteem en stel de details rechts in:" #: rc.cpp:730 rc.cpp:1585 rc.cpp:2429 rc.cpp:3345 rc.cpp:4268 rc.cpp:5175 #, kde-format msgid "New Item" msgstr "Nieuw item" #: rc.cpp:736 rc.cpp:1591 rc.cpp:2435 rc.cpp:3351 rc.cpp:4274 rc.cpp:5181 #, kde-format msgid "add" msgstr "Toevoegen" #: rc.cpp:742 rc.cpp:1597 rc.cpp:2441 rc.cpp:3357 rc.cpp:4280 rc.cpp:5187 #, kde-format msgid "remove" msgstr "Verwijderen" #: rc.cpp:745 rc.cpp:1600 rc.cpp:2444 rc.cpp:3360 rc.cpp:4283 rc.cpp:5190 #, kde-format msgid "1." msgstr "1." #: rc.cpp:748 rc.cpp:751 rc.cpp:1603 rc.cpp:1606 rc.cpp:2447 rc.cpp:2450 #: rc.cpp:3363 rc.cpp:3366 rc.cpp:4286 rc.cpp:4289 rc.cpp:5193 rc.cpp:5196 #, kde-format msgid "D" msgstr "D" #: rc.cpp:758 rc.cpp:1613 rc.cpp:2457 rc.cpp:3373 rc.cpp:4296 rc.cpp:5203 #, kde-format msgid "of the sum of" msgstr "voor de som van" #: rc.cpp:761 rc.cpp:1616 rc.cpp:2460 rc.cpp:3376 rc.cpp:4299 rc.cpp:5206 #, kde-format msgid "" "Please enter the SQLite Database Settings.\n" "\n" "Pick a filename to name the SQLite database file or leave the default setting." msgstr "" "Voer de instellingen in voor de SQLite Database.\\n\n" "\\n\n" "Geef een bestandsnaam op voor het SQLite databasebestand of gebruik de \n" "standaardwaarde." #: rc.cpp:766 rc.cpp:1621 rc.cpp:2465 rc.cpp:3381 rc.cpp:4304 rc.cpp:5211 #, kde-format msgid "store the database file at default place." msgstr "Sla het databasebestand op de standaard locatie op." #: rc.cpp:769 rc.cpp:1624 rc.cpp:2468 rc.cpp:3384 rc.cpp:4307 rc.cpp:5214 #, kde-format msgid "select a file name:" msgstr "Bestandsnaam selecteren:" #: rc.cpp:772 rc.cpp:1627 rc.cpp:2480 rc.cpp:3396 rc.cpp:4310 rc.cpp:5217 #, kde-format msgid "

            Add a Tax Rate

            " msgstr "

            BTW-tarief toevoegen" #: rc.cpp:775 rc.cpp:1630 rc.cpp:2483 rc.cpp:3399 rc.cpp:4313 rc.cpp:5220 #, kde-format msgid "Start-Date:" msgstr "Startdatum:" #: rc.cpp:778 rc.cpp:1633 rc.cpp:2486 rc.cpp:3402 rc.cpp:4316 rc.cpp:5223 #, kde-format msgid "&Reduced Tax Rate:" msgstr "Laag BTW-tarief:" #: rc.cpp:781 rc.cpp:1636 rc.cpp:2489 rc.cpp:3405 rc.cpp:4319 rc.cpp:5226 #, kde-format msgid "&Full Tax Rate:" msgstr "Hoog BTW-tarief:" #: rc.cpp:784 rc.cpp:1639 rc.cpp:2492 rc.cpp:3408 rc.cpp:4322 rc.cpp:5229 #, kde-format msgid "Edit Document Text Template" msgstr "Edit Document Text Template" #: rc.cpp:787 rc.cpp:1642 rc.cpp:2495 rc.cpp:3411 rc.cpp:4325 rc.cpp:5232 #, kde-format msgid "&Name:" msgstr "&Naam:" #: rc.cpp:790 rc.cpp:1645 rc.cpp:2498 rc.cpp:3414 rc.cpp:4328 rc.cpp:5235 #, kde-format msgid "displayed as" msgstr "getoond als" #: rc.cpp:793 rc.cpp:1648 rc.cpp:2501 rc.cpp:3417 rc.cpp:4331 rc.cpp:5238 #, kde-format msgid "in doc type" msgstr "In documenttype" #: rc.cpp:796 rc.cpp:1651 rc.cpp:2504 rc.cpp:3420 rc.cpp:4334 rc.cpp:5241 #, kde-format msgid "&Text:" msgstr "&Tekst:" #: rc.cpp:799 rc.cpp:1520 rc.cpp:2519 rc.cpp:3423 rc.cpp:4337 rc.cpp:5244 #, kde-format msgid "Calculation Item Time" msgstr "Arbeid berekenen" #: rc.cpp:802 rc.cpp:1523 rc.cpp:2522 rc.cpp:3426 rc.cpp:4340 rc.cpp:5247 #, kde-format msgid "

            Calculation Part 'Time'

            " msgstr "

            Post arbeid

            " #: rc.cpp:805 rc.cpp:1526 rc.cpp:2525 rc.cpp:3429 rc.cpp:4343 rc.cpp:5250 #, kde-format msgid "" "Calculate time efforts here for one unit of the template.
            Note that the" " costs may depend on a global hourly rate." msgstr "" "Voer hier de benodigde tijd in voor een exemplaar van het sjabloon. " "
            Vergeet niet dat het project-tarief invloed kan hebben op de kosten." #: rc.cpp:811 rc.cpp:1532 rc.cpp:2531 rc.cpp:3435 rc.cpp:4349 rc.cpp:5256 #, kde-format msgid "Work" msgstr "Werk" #: rc.cpp:814 rc.cpp:1535 rc.cpp:2534 rc.cpp:3438 rc.cpp:4352 rc.cpp:5259 #, kde-format msgid "&Time Effort:" msgstr "Nodigde &tijd:" #: rc.cpp:817 rc.cpp:1538 rc.cpp:2537 rc.cpp:3441 rc.cpp:4355 rc.cpp:5262 #, kde-format msgid "&Hourly Rate:" msgstr "Uurtarief:" #: rc.cpp:820 rc.cpp:1541 rc.cpp:2540 rc.cpp:3444 rc.cpp:4358 rc.cpp:5265 #, kde-format msgid "Apply the &global hourly rate" msgstr "Project-tarief toepassen" #: rc.cpp:823 rc.cpp:1654 rc.cpp:2543 rc.cpp:3447 rc.cpp:4361 rc.cpp:5268 #, kde-format msgid "

            Add a unit

            " msgstr "

            Eenheid toevoegen

            " #: rc.cpp:826 rc.cpp:1657 rc.cpp:2546 rc.cpp:3450 rc.cpp:4364 rc.cpp:5271 #, kde-format msgid "Unit short" msgstr "Eenheid afgekort" #: rc.cpp:829 rc.cpp:1660 rc.cpp:2549 rc.cpp:3453 rc.cpp:4367 rc.cpp:5274 #, kde-format msgid "Unit long" msgstr "Eenheid voluit" #: rc.cpp:832 rc.cpp:1663 rc.cpp:2552 rc.cpp:3456 rc.cpp:4370 rc.cpp:5277 #, kde-format msgid "Unit plural short" msgstr "Eenheid meervoud afgekort" #: rc.cpp:835 rc.cpp:1666 rc.cpp:2555 rc.cpp:3459 rc.cpp:4373 rc.cpp:5280 #, kde-format msgid "Unit plural long" msgstr "Eenheid meervoud voluit" #: rc.cpp:838 rc.cpp:1700 rc.cpp:2592 rc.cpp:3496 rc.cpp:4379 rc.cpp:5286 #, kde-format msgid "" "This step checks if the database schema version is sufficient for this version of Kraft. \n" "\n" "In case it is not, the schema is updated automatically.\n" msgstr "" "Deze stap controleert of de versie van het databaseschema modern genoeg is voor deze versie van Kraft. \n" "\n" "Zo niet, dan wordt het schema automatisch bijgewerkt.\n" #: rc.cpp:853 rc.cpp:1715 rc.cpp:2607 rc.cpp:3511 rc.cpp:4394 rc.cpp:5301 #, kde-format msgid "Upgrade not yet started" msgstr "Opwaarderen nog niet gestart" #: rc.cpp:856 rc.cpp:1718 rc.cpp:2471 rc.cpp:3387 rc.cpp:4397 rc.cpp:5304 #, kde-format msgid "

            Add a Wage group

            " msgstr "

            Functiegroep toevoegen

            " #: rc.cpp:859 rc.cpp:1721 rc.cpp:2474 rc.cpp:3390 rc.cpp:4400 rc.cpp:5307 #, kde-format msgid "Group name" msgstr "Functienaam" #: rc.cpp:862 rc.cpp:1724 rc.cpp:2477 rc.cpp:3393 rc.cpp:4403 rc.cpp:5310 #, kde-format msgid "Wage" msgstr "Salaris" #: rc.cpp:2109 rc.cpp:2118 rc.cpp:2995 rc.cpp:3019 rc.cpp:3025 rc.cpp:3565 #: rc.cpp:3589 rc.cpp:3595 rc.cpp:4469 rc.cpp:4493 rc.cpp:4499 #, kde-format msgid "select" msgstr "Selecteren" #: rc.cpp:2112 rc.cpp:3016 rc.cpp:3586 rc.cpp:4490 #, kde-format msgid "&Watermark File:" msgstr "&Watermerk bestand:" #: rc.cpp:2130 rc.cpp:2992 rc.cpp:3562 rc.cpp:4466 #, kde-format msgid "&Template File:" msgstr "&Sjabloon bestand:" #: rc.cpp:2507 rc.cpp:3145 rc.cpp:4406 rc.cpp:5313 #, kde-format msgid "Dialog" msgstr "Dialoogvenster" #: rc.cpp:2510 rc.cpp:3148 rc.cpp:4409 rc.cpp:5316 #, kde-format msgid "" "

            XRechnung Additional Data

            " msgstr "" "

            Extra informatie voor XRechnung

            " #: rc.cpp:2513 rc.cpp:3151 rc.cpp:4412 rc.cpp:5319 #, kde-format msgid "Due Date:" msgstr "Verval datum:" #: rc.cpp:2516 rc.cpp:3154 rc.cpp:4415 rc.cpp:5322 #, kde-format msgid "Buyer Reference:" msgstr "Inkoop referentie" #: rc.cpp:2558 rc.cpp:3462 rc.cpp:4376 rc.cpp:5283 #, kde-format msgid "Unit ECE20" msgstr "Eenheid ECE20" #: rc.cpp:2989 rc.cpp:3559 rc.cpp:4463 #, kde-format msgid "PDF Creation and Postprocessing" msgstr "Creatie en nabewerking van PDF" #: rc.cpp:3010 rc.cpp:3580 rc.cpp:4484 #, kde-format msgid "alternating (3 pages)" msgstr "Afwisselend (3 pagina's)" #: rc.cpp:3013 rc.cpp:3583 rc.cpp:4487 #, kde-format msgid "different first and last page (3 pages)" msgstr "Afwijkende eerste en laatste pagina (3 pagina's)" #: rc.cpp:3022 rc.cpp:3592 rc.cpp:4496 #, kde-format msgid "Append PDF:" msgstr "Voeg PDF toe" #: rc.cpp:3277 rc.cpp:4139 rc.cpp:5043 #, kde-format msgid "Bank account name." msgstr "Naam voor bankrekening." #: rc.cpp:3280 rc.cpp:4142 rc.cpp:5046 #, kde-format msgid "Business Identifier Code\" (BIC) of the bank." msgstr "Business Identifier Code\" (BIC) van de bank." #: rc.cpp:3283 rc.cpp:4145 rc.cpp:5049 #, kde-format msgid "IBAN of the bank account." msgstr "IBAN van de bankrekening" #: rc.cpp:5070 #, kde-format msgid "Display the EPC Code as long as the doc sum is below this value." msgstr "Toon de EPC-code zolang de totale waarde onder dit getal is." #: setupassistant.cpp:36 #, kde-format msgid "Welcome to the Kraft Setup Assistant" msgstr "Welkom bij de Kraft setup assistent" #: setupassistant.cpp:55 #, kde-format msgid "Select the Database Backend" msgstr "Selecteer de Database Backend" #: setupassistant.cpp:92 #, kde-format msgid "Sqlite File Name" msgstr "SQLite bestandsnaam" #: setupassistant.cpp:146 #, kde-format msgid "MySql Detail Information" msgstr "Gedetailleerde MySql-informatie" #: setupassistant.cpp:188 #, kde-format msgid "Create Database" msgstr "Database creëren" #: setupassistant.cpp:210 setupassistant.cpp:223 #, kde-format msgid "0/%1" msgstr "0/%1" #: setupassistant.cpp:242 setupassistant.cpp:252 setupassistant.cpp:290 #, kde-format msgid "%1/%2" msgstr "%1/%2" #: setupassistant.cpp:265 #, kde-format msgid "Upgrade the Database" msgstr "Database opwaarderen" #: setupassistant.cpp:314 #, kde-format msgid "Your Company Address" msgstr "Uw bedrijfsadres" #: setupassistant.cpp:319 #, kde-format msgid "" "Select your companies address either from the address book or enter it " "manually. It is set as a consigner on the documents." msgstr "" "Selecteer in het adresboek uw eigen adres of voer het handmatig in. Deze " "wordt gebruikt als afzender in de documenten." #: setupassistant.cpp:328 #, kde-format msgid "Select from Addressbook" msgstr "Selecteer in adresboek" #: setupassistant.cpp:418 #, kde-format msgid "Final Status" msgstr "Final Status" #: setupassistant.cpp:512 #, kde-format msgid "" "

            Can't connect to your database. Are you sure your credentials are correct" " and the database exists?

            " msgstr "" "

            Kan geen verbinding maken met de database. Weet u zeker dat uw \n" "instellingen correct zijn en dat de database bestaat?

            " #: setupassistant.cpp:523 #, kde-format msgid "

            Can't open your database file, check the permissions and such." msgstr "" "Kan het databasebestand niet openen, controleer de permissies en " "dergelijke.

            " #: setupassistant.cpp:532 #, kde-format msgid "" "

            The database is already existing, no action needs to be taken " "here.

            Please hit next to proceed.

            " msgstr "" "

            De database bestaat al, verdere acties zijn niet nodig.

            Druk op " "volgende om verder te gaan.

            " #: setupassistant.cpp:581 #, kde-format msgid "

            The database setup was successfully completed.

            " msgstr "

            De database is succesvol gecreëerd.

            " #: setupassistant.cpp:582 #, kde-format msgid "

            You can start to work with Kraft now. Please do not forget to

            " msgstr "

            U kunt nu met Kraft gaan werken. Vergeet niet om

            " #: setupassistant.cpp:584 #, kde-format msgid "
          • adjust various settings in the Kraft Preferences dialog.
          • " msgstr "" "
          • in het dialoogvenster van Kraft voor de voorkeursinstellingen diverse \n" "instellingen aan te passen.
          • " #: setupassistant.cpp:585 #, kde-format msgid "
          • Check the Catalog chapter list.
          • " msgstr "
          • Bekijk de lijst met catalogus-mappen.
          • " #: setupassistant.cpp:586 #, kde-format msgid "
          • Make your business and have fun.
          • " msgstr "
          • Zet uw eigen bedrijf op en heb veel plezier ermee.
          • " #: setupassistant.cpp:588 #, kde-format msgid "" "

            If you press Finish now, the new database configuration is stored " "in Krafts configuration.

            " msgstr "" "

            Als u nu op Voltooien drukt, dan wordt de nieuwe database \n" "configuratie in de configuratie van Kraft opgeslagen.

            " #: setupassistant.cpp:604 #, kde-format msgid "" "The Database can not be connected. Please check the database credentials." msgstr "" "Verbinding met de database is niet mogelijk. Controleer de gegevens van \n" "database." #: setupassistant.cpp:610 #, kde-format msgid "The database core tables do not exist. Please check initial setup." msgstr "" "De basistabellen in de database zijn onvindbaar. Voer de initiële aanmaak \n" "opnieuw uit." #: setupassistant.cpp:617 #, kde-format msgid "Database is up to date. No upgrade is required." msgstr "De database is up-to-date. bijwerken is niet nodig." #: setupassistant.cpp:622 #, kde-format msgid "Parse Update Commands..." msgstr "Bezig met het bijwerken..." #: setupassistant.cpp:665 #, kde-format msgid "The Upgrade failed!" msgstr "Het bijwerken is mislukt!" #: setupassistant.cpp:667 #, kde-format msgid "The Upgrade succeeded, the current schema version is %1!" msgstr "Het bijwerken is gelukt, de versie van het huidige schema is %1!" #: setupassistant.cpp:680 #, kde-format msgid "" "The Database can not be connected. Please check the database credentials!" msgstr "" "Verbinding met de database is niet mogelijk. Controleer de gegevens van \n" "database." #: setupassistant.cpp:686 #, kde-format msgid "Parse Create Commands..." msgstr "Bezig met het aanmaken..." #: setupassistant.cpp:694 #, kde-format msgid "Parse database fillup commands..." msgstr "Bezig met het vullen van de database..." #: setupassistant.cpp:707 #, kde-format msgid "Processing database creation commands..." msgstr "Bezig met het aanmaken van de database..." #: setupassistant.cpp:724 #, kde-format msgid "Process database fillup commands..." msgstr "Bezig met het vullen van de database..." #: setupassistant.cpp:734 #, kde-format msgid "Successfully finished commands." msgstr "De commando's zijn succesvol voltooid." #: setupassistant.cpp:736 #, kde-format msgid "Failed to perform all commands." msgstr "Het uitvoeren van alle commando's is mislukt." #: setupassistant.cpp:780 #, kde-format msgid "" "This assistant guides you through the basic settings of your Kraft " "installation." msgstr "" "Deze assistent leidt u door de basisinstellingen van uw Kraft installatie." #: setupassistant.cpp:790 #, kde-format msgid "There was no database configuration found." msgstr "Er is geen database configuratie gevonden." #: setupassistant.cpp:792 #, kde-format msgid "A valid current database configuration file was found." msgstr "Er is een geldige database configuratie gevonden." #: setupassistant.cpp:814 #, kde-format msgid "The database schema version is too low. It will be updated." msgstr "De database-indeling is te oud, Het zal worden bijgewerkt." #: setupassistant.cpp:817 #, kde-format msgid "The current database schema version is too high. Leaving untouched! " msgstr "Het huidige database-schemaversie is te hoog. Laat het ongewijzigd!" #: setupassistant.cpp:824 #, kde-format msgid "" "

            The database can be opened, but does not contain valid content.

            A " "new database can be created automatically from scratch.

            " msgstr "" "

            De database kan worden geopend, maar heeft geen geldige inhoud.

            >

            U " "kunt een nieuwe database vanaf nul aanmaken.

            " #: setupassistant.cpp:831 #, kde-format msgid "

            Kraft failed to connect to the configured database.

            " msgstr "

            Kraft kon geen verbinding maken met de ingestelde database.

            " #: setupassistant.cpp:833 #, kde-format msgid "" "

            Please check the database server setup and restart Kraft to connect." msgstr "" "

            Controleer de instellingen van de database server en herstart Kraft om " "verbinding te maken." #: setupassistant.cpp:835 #, kde-format msgid "

            Please check the database file." msgstr "

            Controleer het databasebestand." #: setupassistant.cpp:837 #, kde-format msgid "or create a new database by hitting next.

            " msgstr "" "of maak een nieuwe database aan door te klikken op volgende.

            " #: setupassistant.cpp:845 #, kde-format msgid "

            Please hit next and follow the instructions.

            " msgstr "

            Klik op volgende en volg de instructies.

            " #: tagtemplatesdialog.cpp:47 #, kde-format msgid "Edit Tag Template" msgstr "Bewerk tag sjabloon" #: tagtemplatesdialog.cpp:54 #, kde-format msgid "Edit a Tag Template" msgstr "Tag sjabloon bewerken" #: tagtemplatesdialog.cpp:55 #, kde-format msgid "Adjust settings for name, color and description." msgstr "Instellingen wijzigen voor naam, kleur en beschrijving." #: tagtemplatesdialog.cpp:63 #, kde-format msgid "Description:" msgstr "Beschrijving:" #: tagtemplatesdialog.cpp:69 #, kde-format msgid "Associated Color:" msgstr "Gekozen kleur" #: tagtemplatesdialog.cpp:141 #, kde-format msgid "Add, edit and remove tag templates for use in the documents." msgstr "" "Het toevoegen, bewerken en verwijderen van tag sjablonen te gebruiken in " "documenten." #: tagtemplatesdialog.cpp:165 #, kde-format msgid "Add..." msgstr "Toevoegen..." #: tagtemplatesdialog.cpp:167 #, kde-format msgid "Edit..." msgstr "Bewerken..." #: tagtemplatesdialog.cpp:170 #, kde-format msgid "Delete..." msgstr "Verwijderen..." #: tagtemplatesdialog.cpp:223 #, kde-format msgid "Do you really want to delete the template?" msgstr "Wilt u het sjabloon verwijderen? " #: taxeditdialog.cpp:36 #, kde-format msgid "Edit Tax Rates" msgstr "Belastingtarieven bewerken" #: templkatalogview.cpp:101 #, kde-format msgid "" msgstr "" #: templkataloglistview.cpp:47 #, kde-format msgid "Calc. Type" msgstr "Berekeningsmethode" #: templkataloglistview.cpp:54 #, kde-format msgid "Template Catalog" msgstr "Sjabloon catalogus" #: textselection.cpp:42 #, kde-format msgid "Template Collection" msgstr "Verzameling sjablonen" #: textselection.cpp:100 #, kde-format msgid "Template Actions" msgstr "Sjabloon acties" #: textselection.cpp:129 #, kde-format msgid "This is the standard text used in new documents." msgstr "Dit is de standaard tekst voor nieuwe documenten." #: textselection.cpp:138 #, kde-format msgid "%1 Templates for %2" msgstr "%1 sjablonen voor %2" #: textselection.cpp:146 #, kde-format msgid "" "There is no %1 template text available for document type %2.
            Click the " "add-button below to create one." msgstr "" "Er is geen %1 tekstsjabloon beschikbaar voor document type %2.
            Klik op " "de knop voor toevoegen hieronder om een te creëren." #: textselection.cpp:201 #, kde-format msgid "&Use in Document" msgstr "Gebr&uikt in document" #: texteditdialog.cpp:42 #, kde-format msgid "Edit Text Templates" msgstr "Tekst sjablonen bewerken" #: texteditdialog.cpp:62 #, kde-format msgid "Edit %1 Template" msgstr "Bewerk %1 Sjabloon" #: texttemplate.cpp:103 #, kde-format msgid "Failed to open template source" msgstr "Openen van sjablonen is mislukt" #: texttemplateinterface.cpp:53 #, kde-format msgid "No file name given for template" msgstr "Geen naam opgegeven voor sjabloon" #: texttemplateinterface.cpp:61 #, kde-format msgid "Could not find template file %1" msgstr "Kan sjabloonbestand %1 niet vinden" #: timecalcpart.cpp:82 #, kde-format msgid "Minutes" msgstr "Minuten" #: timecalcpart.cpp:84 #, kde-format msgid "Hours" msgstr "Uren" #: timecalcpart.cpp:86 #, kde-format msgid "Seconds" msgstr "Seconden" kraft-1.1/reports/000077500000000000000000000000001450127457600141735ustar00rootroot00000000000000kraft-1.1/reports/CMakeLists.txt000066400000000000000000000003411450127457600167310ustar00rootroot00000000000000add_subdirectory(pics) ########### install files ############### install(FILES delivery_receipt.trml invoice.trml kraft.css invoice.gtmpl xrechnung.xrtmpl DESTINATION ${DATA_INSTALL_DIR}/kraft/reports) kraft-1.1/reports/README.md000066400000000000000000000060711450127457600154560ustar00rootroot00000000000000# Report Templates From the templates in this directory, Kraft is generating the final documents in PDF format. ## Customizing ReportLab Templates Please refer to http://volle-kraft-voraus.de/Main/Documenttemplate about customizing the output document with the old ReportLab based system. ## Weasyprint WeasyPrint is a modern, HTML and CSS based way of creating PDF documents. The project homepage is [Weasyprint Project](https://weasyprint.org/). WeasyPrint will replace the so far used ReportLab based system after a deprecation period. ### Try it! WeasyPrint can be tested from Kraft Version 0.95 on. Just create a template and give it the file extension .gtmpl and Kraft will automatically use the Grantlee templating and WeasyPrint. The appearance of the printed page is mostly influenced by the CSS (Cascading Style Sheet) in file `invoice.css`. ## Internationalization All "human readable" strings in the doc templates are translated to the target language in the code, similar to the normal user interface. Instead of changing the template to the word in a non English language, one of the following template variables could be used: | Template Var. | Meaning | English Default| |---------------|----------------------------------------|----------------| |LAB_NO_SHORT |Sequence number printed on the document |No. | |LAB_ITEM |Document item printed on the document |Item| |LAB_QUANTITY_SHORT|Abbrev. of Quantity printed on the document|Qty.| |LAB_UNIT |Unit printed on the document|Unit| |LAB_PRICE |Price of an item printed on the document|Price| |LAB_SUM |Printed on the document |Sum | |LAB_NET |printed on the document |Net | |LAB_VAT |Printed on the document |VAT | |LAB_PHONE |Printed on the document |Phone| |LAB_FAX |Printed on the document |FAX | |LAB_MOBILE |Printed on the document |Mobile| |LAB_EMAIL |Printed on the document |Email| |LAB_WEBSITE |Printed on the document |Website| |LAB_SPECIAL_ITEMS|Text underneath the list of items to sign out special items like Demand or Alternative items|Please note: This offer contains %1 alternative or demand positions, printed in italic font..| |LAB_TAX_FREE_ITEMS|Label for the amount of tax free items|tax free items (%1 pcs.)| |LAB_TAX_REDUCED_ITEMS|Label for the amount of tax reduced items|items with reduced tax of %1% (%2 pcs.)| |LAB_TAX_FULL_ITEMS|Label for the amount of full tax items|No label: items with full tax of %1% (%2 pcs.)| |LAB_PAGE |Printed on the document |Page| |LAB_PAGE_OF |Printed on the document |of| |LAB_DOC_NO |Printed on the document |Document No.| |LAB_DATE |Printed on the document |Date| |LAB_PROJECT |Printed on the document |Project| |LAB_CUST_ID |Printed on the document |Customer Id| |LAB_CURRENCY_SIGN |Printed on the document |the currency symbol| kraft-1.1/reports/contrib/000077500000000000000000000000001450127457600156335ustar00rootroot00000000000000kraft-1.1/reports/contrib/README.md000066400000000000000000000003661450127457600171170ustar00rootroot00000000000000# Examples This directories contains examples of templates for document generation in Kraft. The purpose is to understand how to create templates for own usage in the perfect way. Feel free to contribute your own template to be included here. kraft-1.1/reports/contrib/bnc-ng/000077500000000000000000000000001450127457600167775ustar00rootroot00000000000000kraft-1.1/reports/contrib/bnc-ng/bnc-document-ng.gtmpl000066400000000000000000000232741450127457600230340ustar00rootroot00000000000000{% comment %} To test this file, get an intermediate HTML output of Kraft, copy the referenced CSS into the block and paste it into https://printcss.live/ to be able modify it with an immediate preview {% endcomment %} {% if kraft.VERSION %} {% endif %} {% if doc.buyerReference %} {% endif %} {% if doc.predecessor %} {% endif %} {% if doc.projectLabel %} {% endif %} {% comment %} If there is a need for style definitions containing variables or other template language elements they have to be put here. If they are necassary for multiple template definitions consider moving them to an include file. {% endcomment %} {{ doc.docType }} {{ doc.ident }} {% autoescape off %}
            {{ doc.address }}
            Rechnungsanschrift

            Lerchenweg 7
            53359 Rheinbach

            Ihr Ansprechpartner
            Telefon
            E-Mail
            Lieferanschrift

            Lerchenweg 7
            53359 Rheinbach

            {{ me.NAME }}
            {{ me.PHONE }}
            {{ me.EMAIL }}
            {{ doc.dateStr }}
            {{ doc.docType }}
            {{ doc.ident }} {% if doc.predecessor %}     ({{ label.PREDECESSOR }}: {{ doc.predecessor }}) {% endif %}
            {% if doc.doc.buyerReference %}
            {{ label.BUYERREFERENCE }}
            {{ doc.buyerReference }}
            {% endif %} {% if doc.projectLabel %}
            {{ label.PROJECT }}: {{ doc.projectLabel }}
            {% endif %}
            {% if doc.salut %}

            {{ doc.salut }}

            {% endif %} {% if doc.preText %}

            {{ doc.preText }}

            {% endif %} {% if doc.items|length > 0 %} {% for item in doc.items %}
            {% comment %} This empty row is needed to define the width of the columns. In tables with fixed width defined in CSS the first row is the defining one. As it is also generating an empty line as separator it has been kept inside the for-loop instead of putting it in front of the loop. {% endcomment %}
            {% endfor %}
            {{ label.NO_SHORT }} {{ label.QUANTITY_SHORT }} {{ label.UNIT }} {{ label.PRICE }} {{ label.SUM }}
            {{ item.itemNumber }} {% if item.kind == 'Alternative' %} {% elif item.kind == 'Comment' %} {% elif item.kind == 'Demand' %} {% else %} {% endif %} {{ item.htmlText }}
            {{ item.amount }}  {{ item.unit }} {{ item.unitPrice }} {{ item.nettoPrice }} {% if doc.hasIndividualTaxation %} {{ item.taxMarker }}   {% endif %}
            {% if doc.hasIndividualTaxation %} {% else %} {% endif %}
            {{ label.NET }} {{ doc.nettoSumStr }}
            {{ doc.taxMarkerReduced }}  +{{ doc.reducedTaxPercentStr }}% {{ label.VAT }} {{ doc.reducedTaxSumStr }}
            {{ doc.taxMarkerFull }}  +{{ doc.fullTaxPercentStr }}% {{ label.VAT }} {{ doc.fullTaxSumStr }}
            +{{ doc.taxPercentStr }}% {{ label.VAT }} {{ doc.taxSumStr }}
            {{ label.SUM }} {{ doc.bruttoSumStr }}
            {% endif %} {% if doc.postText %}

            {{ doc.postText }}

            {% endif %}

            {{ doc.goodbye }}

            {% endautoescape %} kraft-1.1/reports/contrib/bnc-ng/bnc-global.css000066400000000000000000000272451450127457600215230ustar00rootroot00000000000000/* Zeichensatz: */ @charset "UTF-8"; /* Fonts: */ /* as this document will always be rendered on the same small set of * machines using web fonts off the web may be overkill and create * unnecessary traffic and extended rendering times. It is far better to * download the woff-files from their source and store them besides this * file (or use a specified path for them). You can yúse OTF and TTF * files just as well. */ /* @import url("https://fonts.googleapis.com/css?family=Calibri|Oxygen|Pacifico|Open+Sans+Pro:400,700,400italic,700italic,400bold"); @import url("https://fonts.googleapis.com/css?family=Consolas|Inconsolata:400,700,400italic,700italic"); @import url("https://fonts.googleapis.com/css?family=Roboto"); @import url("https://fonts.googleapis.com/css?family=Raleway"); @import url("https://fonts.googleapis.com/css?family=Calibri:400"); @import url("https://fonts.googleapis.com/css?family=Calibri:700"); @import url("https://fonts.googleapis.com/css?family=Calibri:400italic"); @import url("https://fonts.googleapis.com/css?family=Calibri:700italic"); @import url("https://fonts.googleapis.com/css?family=Calibri:400bold"); */ /* @import url("https://fonts.googleapis.com/css?family=Consolas:400"); @import url("https://fonts.googleapis.com/css?family=Consolas:700"); @import url("https://fonts.googleapis.com/css?family=Consolas:400italic"); @import url("https://fonts.googleapis.com/css?family=Consolas:700italic"); */ @font-face { font-family: "Arial Narrow"; src: url("../Fonts/Arial Narrow.ttf") format(truetype); font-style: normal; font-weight: 400; } @font-face { font-family: "Barmeno"; src: url("../Fonts/Barmeno-Regular.otf") format(opentype); font-style: normal; font-weight: normal; } @font-face { font-family: "Calibri"; src: url("../Fonts/Calibri.ttf") format(truetype), url("../Fonts/Calibri.woff2") format(woff2); font-style: normal; font-weight: normal; } @font-face { font-family: "Calibri"; src: url("../Fonts/Calibri-Bold.ttf") format(truetype), url("../Fonts/Calibri-Bold.woff2") format(woff2); font-style: normal; font-weight: bold; } @font-face { font-family: "Calibri"; src: url("../Fonts/Calibri-Italic.ttf") format(truetype), url("../Fonts/Calibri-Italic.woff2") format(woff2); font-style: italic; font-weight: normal; } @font-face { font-family: "Calibri"; src: url("../Fonts/Calibri-BoldItalic.ttf") format(truetype), url("../Fonts/Calibri-BoldItalic.woff2") format(woff2); font-style: italic; font-weight: bold; } @font-face { font-family: "Consolas"; src: url("../Fonts/consola.ttf") format(truetype); font-style: normal; font-weight: normal; } /* General page settings for printouts */ @page { size: A4 portrait; margin-left: 0; margin-top: 0; margin-right: 0; margin-bottom: 0; } /* if you set page margins the position: absolute; items will not be absolute anymore... */ @page :first { margin-left: 25mm; margin-top: 0; margin-right: 20mm; margin-bottom: 40mm; } @page :left { margin-left: 20mm; margin-top: 20mm; margin-right: 25mm; margin-bottom: 15mm; } @page :right { margin-left: 25mm; margin-top: 20mm; margin-right: 20mm; margin-bottom: 15mm; } @page :blank { } /* Everything in here should only be relevant for printing BUT if you want * to test your design in a browser it might be a good idea to remove the * @media print {} block */ /* @media print { */ /* Watermark: Nike. DON'T DO IT. */ /* takes long, opacity is not working as expected in 2022 body :before { content: ''; position: absolute; top: 0; bottom: 0; left: 0; right: 0; background: url(BNC-watermark.png); background-position: center; background-size: 100%; background-repeat: no-repeat; background-attachment: fixed; z-index: -1; opacity: 0.05; } */ /* Page Breaks */ /* The following settings are possible: page-break-after : auto | always | avoid | left | right page-break-before : auto | always | avoid | left | right page-break-inside : auto | avoid */ h1 { page-break-before: always; } h1, h2, h3, h4, h5, h6, h7 { page-break-after: avoid; } table, tr, figure { page-break-inside: avoid; page-break-after: auto; } /* page break class; use as
            to insert */ .pagebreak { page-break-before: always; } /* DIN 5008 address field */ /* height 45mm. Address starts 17.7mm from top, 6 linex max. Additional * remarks go upwards into the upper 17.7mm, 5 lines max. * see https://www.workingoffice.de/din-5008/adresse-nach-din-5008/ */ .ISO-address-window { font-family: Calibri; font-size: 8pt; font-style: normal; line-height: 1.1; position: absolute; display: block; white-space: pre-line; top: 45mm; /* top: 62.7mm; */ left: 20mm; width: 90mm; height: 45mm; } .address-field { position: absolute; display: block; white-space: pre-line; font-size: 10pt; font-style: normal; line-height: 1.2; top: 55mm; left: 0mm; width: 80mm; height: 36.3mm; } .buyer-reference { position: absolute; font-family: Calibri; font-size: 10pt; line-height: 1.25; top: 93mm; left: 98mm; width: 400mm; height: 20pt; } .date { position: absolute; font-family: Calibri; font-size: 12pt; font-weight: bold; line-height: 1; top: 93mm; left: 144mm; width: 30mm; height: 12pt; } .document-type-and-number { position: absolute; font-family: Barmeno; font-size: 12pt; font-weight: bold; line-height: 1.2; top: 110mm; left: 0mm; width: 165mm; height: 36pt; } .header-block-1 { position: absolute; font-family: Barmeno; font-size: 10pt; line-height: 1.25; top: 45mm; left: 98mm; width: 40mm; height: 40mm; } .header-block-2 { position: absolute; font-family: Barmeno; font-size: 10pt; line-height: 1.25; top: 45mm; left: 144mm; width: 40mm; height: 40mm; } .project { position: absolute; font-family: Calibri; font-size: 10pt; font-weight: bold; line-height: 1; top: 125mm; left: 0mm; width: 165mm; } /* report area; item styling */ .doc-items { border-collapse: collapse; width: 165mm; table-layout: fixed; page-break-inside:avoid; margin-right: 0px; margin-left: 0px; } .doc-items-header { /* meaning all th (table header) cells in a table of class doc-item */ vertical-align: top; line-height: 1.1; box-sizing: border-box; border-collapse: padding-top: 2mm; padding-left: 2mm; padding-right: 2mm; border: solid; border-spacing: 1px; border-top: 1px solid black; border-bottom: 1px solid black; border-left: 0; border-right: 0; } table.doc-items td { /* meaning all td cells in a table of class doc-item -- remember, every item might be in its own table */ vertical-align: top; line-height: 1.1; box-sizing: border-box; padding-top: 2mm; padding-left: 2mm; padding-right: 2mm; } .doc-item-style-individualTaxation { vertical-align: super; font-size: 60%; } .col-item-no { vertical-align: top; width: 6%; } .col-item-text { width: 75%; } .col-item-alternative { width: 75%; } .col-item-comment { width: 75%; } .col-item-ondemand { width: 75%; } .col-item-standard { width: 75%; } .col-item-amount { width: 52%; } .col-item-unit { width: 12%; } .col-item-unitprice { width: 15%; } .col-item-total { width: 15%; color: #000000; font-weight: bold; } /* totals, taxes and bottom text */ .totals { width: 165mm; /* table-layout: fixed; /* this somehow adds 2mm horizontal spacing and messes everyting up */ vertical-align: top; line-height: 1.25; box-sizing: border-box; text-align: right; bottom: 0; /* The following margins pull the whole box to the right */ margin-right: 0; margin-left: 0; margin-top: 8mm; /*separation between items and sums */ margin-bottom: 12mm; /* separation between sums and footer text */ } table.totals td { box-sizing: border-box; padding-top: 2mm; padding-left: 2mm; padding-right: 2mm; } .totals-col-spacer { padding-top: 1mm; width: 60%; } .totals-col-label { padding-top: 1mm; width: 20%; } .totals-col-value { padding-top: 1mm; width: 20%; } .totals-first-line { border-top: solid black 1px; } .totals-final-line { border-top: solid black 1px; border-bottom: solid black 2px; } .entrytext { } .entrytext-unprocessed { white-space: pre-line; } .bottomtext { } .bottomtext-unprocessed { white-space: pre-line; } .goodbye { } /* This will be the style for the first element of the "report area" of the printout. * Due to absolute positioning of blocks above it it is impossible to adjust the * start of that zone using a top margin. It will be used on an otherwise * empty div. */ .generate-first-page-margin { font-family: Calibri; font-size: 10pt; line-height: 1.2; left: 0mm; width: 165mm; padding-top: 135mm; } /* Tables with units konsiting of multiple rows might be getting a page break * inserted where it hurts. This will avoid them. */ .no-page-break-inside { page-break-inside: auto; } /* these classes can be used for debugging whenever you don't understand * what is happening to your positioning just add one of these classes * to your HTML
            s */ .DEBUG-box-black { border: 0.1mm solid black; } .DEBUG-box-red { border: 0.1mm solid red; } .DEBUG-box-green { border: 0.1mm solid green; } .DEBUG-box-blue { border: 0.1mm solid blue; } /* bad style to do things not based on semantic grouping, but... */ /* text alignment within an element */ .align-center { text-align: center; } .align-left { text-align: left; } .align-right { text-align: right; } .align-justify { text-align: right; } .superscript { vertical-align: super; font-size: 60%; } .subscript { vertical-align: sub; font-size: 60%; } .weight-bold { font-weight: bold; } .weight-normal { font-weight: normal; } /* explicit font settings */ .main-font-regular-6 { font-family: 'Calibri'; font-size: 6pt; } .main-font-regular-8 { font-family: 'Calibri'; font-size: 8pt; } .main-font-regular-10 { font-family: 'Calibri'; font-size: 10pt; } .main-font-regular-12 { font-family: 'Calibri'; font-size: 12pt; } /* classless settings for the entire document */ html { font-family: 'Calibri'; font-size: 10pt; line-height: 1.2; margin: 0px; } /* A perverse invention by Google: There is a browser built-in CSS style * sheet defining certain settings "to make the web look like it should". * The worst part are implicit margin settigs that affect any element * without "position: absolute;". While this might be a good idea for a web * browser it makes print layout an educated guess. */ body{ margin: 0px; } table { border-collapse: collapse; vertical-align: top; box-sizing: border-box; } th { border-bottom: .2mm solid #555; color: #555; font-size: 10pt; font-weight: 400; /* padding-bottom: .25cm; */ } td { vertical-align: top; } /* } /* @media print} */ /* The following style definitions are intended to be used in multi-line * text entries as poor man's easy-to-use HTML building blocks. Use them * inside s for text effects. */ .font-barmeno { font-family: Bameno; } .font-consolas { font-family: Consolas; } kraft-1.1/reports/contrib/bnc/000077500000000000000000000000001450127457600163755ustar00rootroot00000000000000kraft-1.1/reports/contrib/bnc/README.md000066400000000000000000000005731450127457600176610ustar00rootroot00000000000000 These templates were contributed by Achim Patzner The difference between the unsafe-variant the the "safe" variant is that the unsafe variant does render html tags in post-, pre- and item texts. HTML Tags in texts are not enabled in Kraft by default. bnc-letter.gtmpl is a template to write a letter with Kraft. It skips the items and uses pre- and post-text. kraft-1.1/reports/contrib/bnc/bnc-document-with-prices-unsafe.gtmpl000066400000000000000000000210171450127457600255340ustar00rootroot00000000000000{% comment %} To test this file, get an intermediate HTML output of Kraft, copy the referenced CSS into the block and paste it into https://printcss.live/ to be able modify it with an immediate preview {% endcomment %} {% if doc.projectLabel %} {% endif %} {% if doc.predecessor %} {% endif %} {% if doc.projectLabel %} {% endif %} {% comment %} If there is a need for style definitions containing variables or other template language elements they have to be put here. If they are necassary for multiple template definitions consider moving them to an include file. {% endcomment %} {{ doc.docType }} {{ doc.ident }} {% autoescape off %}
            {{ doc.address }}
            Rechnungsanschrift

            Lerchenweg 7
            53359 Rheinbach

            Ihr Ansprechpartner
            Telefon
            E-Mail
            Lieferanschrift

            Lerchenweg 7
            53359 Rheinbach

            {{ me.NAME }}
            {{ me.PHONE }}
            {{ me.EMAIL }}
            {{ doc.dateStr }}
            {{ doc.docType }}
            {{ doc.ident }} {% if doc.predecessor %}     ({{ label.PREDECESSOR }}: {{ doc.predecessor }}) {% endif %}
            {% if doc.doc.buyerReference %}
            {{ label.BUYERREFERENCE }}
            {{ doc.buyerReference }}
            {% endif %} {% if doc.projectLabel %}
            {{ label.PROJECT }}: {{ doc.projectLabel }}
            {% endif %}
            {% if doc.salut %}

            {{ doc.salut }}

            {% endif %} {% if doc.preText %}

            {{ doc.preText }}

            {% endif %} {% for item in doc.items %}
            {{ item.itemNumber }} {% if item.kind == 'Alternative' %} {% elif item.kind == 'Comment' %} {% elif item.kind == 'Demand' %} {% else %} {% endif %} {{ item.htmlText }}
            {{ item.amount }}  {{ item.unit }} {{ item.unitPrice }} {{ item.nettoPrice }} {% if doc.hasIndividualTaxation %} {{ item.taxMarker }}   {% endif %}
            {% endfor %} {% if doc.hasIndividualTaxation %} {% else %} {% endif %}
            {{ label.NET }} {{ doc.nettoSumStr }}
            {{ doc.taxMarkerReduced }}  +{{ doc.reducedTaxPercentStr }}% {{ label.VAT }} {{ doc.reducedTaxSumStr }}
            {{ doc.taxMarkerFull }}  +{{ doc.fullTaxPercentStr }}% {{ label.VAT }} {{ doc.fullTaxSumStr }}
            +{{ doc.taxPercentStr }}% {{ label.VAT }} {{ doc.taxSumStr }}
            {{ label.SUM }} {{ doc.bruttoSumStr }}
            {% if doc.postText %}

            {{ doc.postText }}

            {% endif %}

            {{ doc.goodbye }}

            {% endautoescape %} kraft-1.1/reports/contrib/bnc/bnc-document-with-prices.gtmpl000066400000000000000000000210501450127457600242520ustar00rootroot00000000000000{% comment %} To test this file, get an intermediate HTML output of Kraft, copy the referenced CSS into the block and paste it into https://printcss.live/ to be able modify it with an immediate preview {% endcomment %} {% if doc.projectLabel %} {% endif %} {% if doc.predecessor %} {% endif %} {% if doc.projectLabel %} {% endif %} {% comment %} If there is a need for style definitions containing variables or other template language elements they have to be put here. If they are necassary for multiple template definitions consider moving them to an include file. {% endcomment %} {{ doc.docType }} {{ doc.ident }} {% autoescape off %}
            {{ doc.address }}
            Rechnungsanschrift

            Lerchenweg 7
            53359 Rheinbach

            Ihr Ansprechpartner
            Telefon
            E-Mail
            Lieferanschrift

            Lerchenweg 7
            53359 Rheinbach

            {{ me.NAME }}
            {{ me.PHONE }}
            {{ me.EMAIL }}
            {{ doc.dateStr }}
            {{ doc.docType }}
            {{ doc.ident }} {% if doc.predecessor %}     ({{ label.PREDECESSOR }}: {{ doc.predecessor }}) {% endif %}
            {% if doc.doc.buyerReference %}
            {{ label.BUYERREFERENCE }}
            {{ doc.buyerReference }}
            {% endif %} {% if doc.projectLabel %}
            {{ label.PROJECT }}: {{ doc.projectLabel }}
            {% endif %}
            {% if doc.salut %}

            {{ doc.salut }}

            {% endif %} {% if doc.preTextHtml %}

            {{ doc.preTextHtml|safe }}

            {% endif %} {% for item in doc.items %}
            {{ item.itemNumber }} {% if item.kind == 'Alternative' %} {% elif item.kind == 'Comment' %} {% elif item.kind == 'Demand' %} {% else %} {% endif %} {{ item.htmlText }}
            {{ item.amount }}  {{ item.unit }} {{ item.unitPrice }} {{ item.nettoPrice }} {% if doc.hasIndividualTaxation %} {{ item.taxMarker }}   {% endif %}
            {% endfor %} {% if doc.hasIndividualTaxation %} {% else %} {% endif %}
            {{ label.NET }} {{ doc.nettoSumStr }}
            {{ doc.taxMarkerReduced }}  +{{ doc.reducedTaxPercentStr }}% {{ label.VAT }} {{ doc.reducedTaxSumStr }}
            {{ doc.taxMarkerFull }}  +{{ doc.fullTaxPercentStr }}% {{ label.VAT }} {{ doc.fullTaxSumStr }}
            +{{ doc.taxPercentStr }}% {{ label.VAT }} {{ doc.taxSumStr }}
            {{ label.SUM }} {{ doc.bruttoSumStr }}
            {% if doc.postTextHtml %}

            {{ doc.postTextHtml|safe }}

            {% endif %}

            {{ doc.goodbye }}

            {% endautoescape %} kraft-1.1/reports/contrib/bnc/bnc-document-without-prices-unsafe.gtmpl000066400000000000000000000151601450127457600262660ustar00rootroot00000000000000{% comment %} To test this file, get an intermediate HTML output of Kraft, copy the referenced CSS into the block and paste it into https://printcss.live/ to be able modify it with an immediate preview {% endcomment %} {% if doc.projectLabel %} {% endif %} {% if doc.predecessor %} {% endif %} {% if doc.projectLabel %} {% endif %} {% comment %} If there is a need for style definitions containing variables or other template language elements they have to be put here. If they are necassary for multiple template definitions consider moving them to an include file. {% endcomment %} {{ doc.docType }} {{ doc.ident }} {% autoescape off %}
            {{ doc.address }}
            Rechnungsanschrift

            Lerchenweg 7
            53359 Rheinbach

            Ihr Ansprechpartner
            Telefon
            E-Mail
            Lieferanschrift

            Lerchenweg 7
            53359 Rheinbach

            {{ me.NAME }}
            {{ me.PHONE }}
            {{ me.EMAIL }}
            {{ doc.dateStr }}
            {{ doc.docType }}
            {{ doc.ident }} {% if doc.predecessor %}     ({{ label.PREDECESSOR }}: {{ doc.predecessor }}) {% endif %}
            {% if doc.doc.buyerReference %}
            {{ label.BUYERREFERENCE }}
            {{ doc.buyerReference }}
            {% endif %} {% if doc.projectLabel %}
            {{ label.PROJECT }}: {{ doc.projectLabel }}
            {% endif %}
            {% if doc.salut %}

            {{ doc.salut }}

            {% endif %} {% if doc.preText %}

            {{ doc.preText }}

            {% endif %} {% for item in doc.items %}
            {{ item.itemNumber }} {% if item.kind == 'Alternative' %} {% elif item.kind == 'Comment' %} {% elif item.kind == 'Demand' %} {% else %} {% endif %} {{ item.htmlText }}
            {{ item.amount }}  {{ item.unit }}
            {% endfor %} {% if doc.postText %}

            {{ doc.postText }}

            {% endif %}

            {{ doc.goodbye }}

            {% endautoescape %} kraft-1.1/reports/contrib/bnc/bnc-document-without-prices.gtmpl000066400000000000000000000152061450127457600250100ustar00rootroot00000000000000{% comment %} To test this file, get an intermediate HTML output of Kraft, copy the referenced CSS into the block and paste it into https://printcss.live/ to be able modify it with an immediate preview {% endcomment %} {% if doc.projectLabel %} {% endif %} {% if doc.predecessor %} {% endif %} {% if doc.projectLabel %} {% endif %} {% comment %} If there is a need for style definitions containing variables or other template language elements they have to be put here. If they are necassary for multiple template definitions consider moving them to an include file. {% endcomment %} {{ doc.docType }} {{ doc.ident }} {% autoescape off %}
            {{ doc.address }}
            Rechnungsanschrift

            Lerchenweg 7
            53359 Rheinbach

            Ihr Ansprechpartner
            Telefon
            E-Mail
            Lieferanschrift

            Lerchenweg 7
            53359 Rheinbach

            {{ me.NAME }}
            {{ me.PHONE }}
            {{ me.EMAIL }}
            {{ doc.dateStr }}
            {{ doc.docType }}
            {{ doc.ident }} {% if doc.predecessor %}     ({{ label.PREDECESSOR }}: {{ doc.predecessor }}) {% endif %}
            {% if doc.doc.buyerReference %}
            {{ label.BUYERREFERENCE }}
            {{ doc.buyerReference }}
            {% endif %} {% if doc.projectLabel %}
            {{ label.PROJECT }}: {{ doc.projectLabel }}
            {% endif %}
            {% if doc.salut %}

            {{ doc.salut }}

            {% endif %} {% if doc.preTextHtml %}

            {{ doc.preTextHtml|safe }}

            {% endif %} {% for item in doc.items %}
            {{ item.itemNumber }} {% if item.kind == 'Alternative' %} {% elif item.kind == 'Comment' %} {% elif item.kind == 'Demand' %} {% else %} {% endif %} {{ item.htmlText }}
            {{ item.amount }}  {{ item.unit }}
            {% endfor %} {% if doc.postTextHtml %}

            {{ doc.postTextHtml }}

            {% endif %}

            {{ doc.goodbye }}

            {% endautoescape %} kraft-1.1/reports/contrib/bnc/bnc-global.css000066400000000000000000000251751450127457600211210ustar00rootroot00000000000000/* Zeichensatz: */ @charset "UTF-8"; /* Fonts: */ /* as this document will always be rendered on the same small set of * machines using web fonts off the web may be overkill and create * unnecessary traffic and extended rendering times. It is far better to * download the woff-files from their source and store them besides this * file (or use a specified path for them). You can yúse OTF and TTF * files just as well. */ /* @import url("https://fonts.googleapis.com/css?family=Calibri|Oxygen|Pacifico|Open+Sans+Pro:400,700,400italic,700italic,400bold"); @import url("https://fonts.googleapis.com/css?family=Consolas|Inconsolata:400,700,400italic,700italic"); @import url("https://fonts.googleapis.com/css?family=Roboto"); @import url("https://fonts.googleapis.com/css?family=Raleway"); @import url("https://fonts.googleapis.com/css?family=Calibri:400"); @import url("https://fonts.googleapis.com/css?family=Calibri:700"); @import url("https://fonts.googleapis.com/css?family=Calibri:400italic"); @import url("https://fonts.googleapis.com/css?family=Calibri:700italic"); @import url("https://fonts.googleapis.com/css?family=Calibri:400bold"); @import url("https://fonts.googleapis.com/css?family=Consolas:400"); @import url("https://fonts.googleapis.com/css?family=Consolas:700"); @import url("https://fonts.googleapis.com/css?family=Consolas:400italic"); @import url("https://fonts.googleapis.com/css?family=Consolas:700italic"); */ @font-face { font-family: "Arial Narrow"; src: url("../Fonts/Arial Narrow.ttf") format(truetype); font-style: normal; font-weight: 400; } @font-face { font-family: "Barmeno"; src: url("../Fonts/Barmeno-Regular.otf") format(opentype); font-style: normal; font-weight: normal; } @font-face { font-family: "Calibri"; src: url("../Fonts/Calibri.ttf") format(truetype), url("../Fonts/Calibri.woff2") format(woff2); font-style: normal; font-weight: normal; } @font-face { font-family: "Calibri"; src: url("../Fonts/Calibri-Bold.ttf") format(truetype), url("../Fonts/Calibri-Bold.woff2") format(woff2); font-style: normal; font-weight: bold; } @font-face { font-family: "Calibri"; src: url("../Fonts/Calibri-Italic.ttf") format(truetype), url("../Fonts/Calibri-Italic.woff2") format(woff2); font-style: italic, oblique; font-weight: normal; } @font-face { font-family: "Calibri"; src: url("../Fonts/Calibri-BoldItalic.ttf") format(truetype), url("../Fonts/Calibri-BoldItalic.woff2") format(woff2); font-style: italic, oblique; font-weight: bold; } @font-face { font-family: "Consolas"; src: url("../Fonts/consola.ttf") format(opentype); font-style: normal; font-weight: normal; } /* General page settings for printouts */ @page { size: A4 portrait; margin-left: 0; margin-top: 0; margin-right: 0; margin-bottom: 0; } /* if you set page margins the position: absolute; items will not be absolute anymore... */ @page :first { margin-left: 25mm; margin-top: 0; margin-right: 20mm; margin-bottom: 40mm; } @page :left { margin-left: 20mm; margin-top: 20mm; margin-right: 25mm; margin-bottom: 15mm; } @page :right { margin-left: 25mm; margin-top: 20mm; margin-right: 20mm; margin-bottom: 15mm; } @page :blank { } /* Everything in here should only be relevant for printing BUT if you want * to test your design in a browser it might be a good idea to remove the * @media print {} block */ /* @media print { */ /* Watermark: Nike. DON'T DO IT. */ /* takes long, opacity is not working as expected in 2022 body :before { content: ''; position: absolute; top: 0; bottom: 0; left: 0; right: 0; background: url(BNC-watermark.png); background-position: center; background-size: 100%; background-repeat: no-repeat; background-attachment: fixed; z-index: -1; opacity: 0.05; } */ /* Page Breaks */ /* The following settings are possible: page-break-after : auto | always | avoid | left | right page-break-before : auto | always | avoid | left | right page-break-inside : auto | avoid */ h1 { page-break-before: always; } h1, h2, h3, h4, h5, h6, h7 { page-break-after: avoid; } table, tr, figure { page-break-inside: avoid; page-break-after: auto; } /* page break class; use as
            to insert */ .pagebreak { page-break-before: always; } /* DIN 5008 address field */ /* height 45mm. Address starts 17.7mm from top, 6 linex max. Additional * remarks go upwards into the upper 17.7mm, 5 lines max. * see https://www.workingoffice.de/din-5008/adresse-nach-din-5008/ */ .ISO-address-window { font-family: Calibri; font-size: 8pt; font-style: normal; line-height: 1.1; position: absolute; display: block; white-space: pre-line; top: 45mm; /* top: 62.7mm; */ left: 20mm; width: 90mm; height: 45mm; } .address-field { position: absolute; display: block; white-space: pre-line; font-size: 10pt; font-style: normal; line-height: 1.2; top: 55mm; left: 0mm; width: 80mm; height: 36.3mm; } .buyer-reference { position: absolute; font-family: Calibri; font-size: 10pt; line-height: 1.25; top: 93mm; left: 98mm; width: 400mm; height: 20pt; } .date { position: absolute; font-family: Calibri; font-size: 12pt; font-weight: bold; line-height: 1; top: 93mm; left: 144mm; width: 30mm; height: 12pt; } .document-type-and-number { position: absolute; font-family: Barmeno; font-size: 12pt; font-weight: bold; line-height: 1.2; top: 110mm; left: 0mm; width: 165mm; height: 36pt; } .header-block-1 { position: absolute; font-family: Barmeno; font-size: 10pt; line-height: 1.25; top: 45mm; left: 98mm; width: 40mm; height: 40mm; } .header-block-2 { position: absolute; font-family: Barmeno; font-size: 10pt; line-height: 1.25; top: 45mm; left: 144mm; width: 40mm; height: 40mm; } .project { position: absolute; font-family: Calibri; font-size: 10pt; font-weight: bold; line-height: 1; top: 125mm; left: 0mm; width: 165mm; } /* report area; item styling */ .doc-items { border-collapse: collapse; width: 165mm; table-layout: fixed; page-break-inside:avoid; margin-right: 0px; margin-left: 0px; } table.doc-items td { /* meaning all td cells in a table of class doc-item -- remember, every item is in its own table */ vertical-align: top; line-height: 1.1; box-sizing: border-box; padding-top: 2mm; padding-left: 2mm; padding-right: 2mm; } .doc-item-style-individualTaxation { vertical-align: super; font-size: 60%; } .col-item-no { vertical-align: top; width: 6%; } .col-item-text { width: 75%; } .col-item-alternative { width: 75%; } .col-item-comment { width: 75%; } .col-item-ondemand { width: 75%; } .col-item-standard { width: 75%; } .col-item-amount { width: 52%; } .col-item-unit { width: 12%; } .col-item-unitprice { width: 15%; } .col-item-total { width: 15%; color: #000000; font-weight: bold; } /* totals, taxes and bottom text */ .totals { width: 165mm; /* table-layout: fixed; /* this somehow adds 2mm horizontal spacing and messes everyting up */ vertical-align: top; line-height: 1.25; box-sizing: border-box; text-align: right; bottom: 0; /* The following margins pull the whole box to the right */ margin-right: 0; margin-left: 0; margin-top: 8mm; /*separation between items and sums */ margin-bottom: 12mm; /* separation between sums and footer text */ } table.totals td { box-sizing: border-box; padding-top: 2mm; padding-left: 2mm; padding-right: 2mm; } .totals-col-spacer { padding-top: 1mm; width: 60%; } .totals-col-label { padding-top: 1mm; width: 20%; } .totals-col-value { padding-top: 1mm; width: 20%; } .totals-first-line { border-top: solid black 1px; } .totals-final-line { border-top: solid black 1px; border-bottom: solid black 2px; } .bottomtext { } .goodbye { } /* This will be the style for the first element of the "report area" of the printout. * Due to absolute positioning of blocks above it it is impossible to adjust the * start of that zone using a top margin. It will be used on an otherwise * empty div. */ .generate-first-page-margin { font-family: Calibri; font-size: 10pt; line-height: 1.2; left: 0mm; width: 165mm; padding-top: 135mm; } /* these classes can be used for debugging whenever you don't understand * what is happening to your positioning just add one of these classes * to your HTML
            s */ .DEBUG-box-black { border: 0.1mm solid black; } .DEBUG-box-red { border: 0.1mm solid red; } .DEBUG-box-green { border: 0.1mm solid green; } .DEBUG-box-blue { border: 0.1mm solid blue; } /* bad style to do things not based on semantic grouping, but... */ /* text alignment within an element */ .align-center { text-align: center; } .align-left { text-align: left; } .align-right { text-align: right; } .superscript { vertical-align: super; font-size: 60%; } .subscript { vertical-align: sub; font-size: 60%; } .weight-bold { font-weight: bold; } .weight-normal { font-weight: normal; } /* explicit font settings */ .main-font-regular-6 { font-family: 'Calibri'; font-size: 6pt; } .main-font-regular-8 { font-family: 'Calibri'; font-size: 8pt; } .main-font-regular-10 { font-family: 'Calibri'; font-size: 10pt; } .main-font-regular-12 { font-family: 'Calibri'; font-size: 12pt; } /* classless settings for the entire document */ html { font-family: 'Calibri'; font-size: 10pt; line-height: 1.2; margin: 0px; } /* A perverse invention by Google: There is a browser built-in CSS style * sheet defining certain settings "to make the web look like it should". * The worst part are implicit margin settigs that affect any element * without "position: absolute;". While this might be a good idea for a web * browser it makes print layout an educated guess. */ body{ margin: 0px; } table { border-collapse: collapse; vertical-align: top; box-sizing: border-box; } th { border-bottom: .2mm solid #555; color: #555; font-size: 10pt; font-weight: 400; /* padding-bottom: .25cm; */ } td { vertical-align: top; } /* } /* @media print} */ kraft-1.1/reports/contrib/bnc/bnc-letter.gtmpl000066400000000000000000000115001450127457600214760ustar00rootroot00000000000000{% comment %} To test this file, get an intermediate HTML output of Kraft, copy the referenced CSS into the block and paste it into https://printcss.live/ to be able modify it with an immediate preview {% endcomment %} {% if doc.projectLabel %} {% endif %} {% if doc.predecessor %} {% endif %} {% if doc.projectLabel %} {% endif %} {% comment %} If there is a need for style definitions containing variables or other template language elements they have to be put here. If they are necassary for multiple template definitions consider moving them to an include file. {% endcomment %} {{ doc.docType }} {{ doc.ident }} {% autoescape off %}
            {{ doc.address }}
            Rechnungsanschrift

            Lerchenweg 7
            53359 Rheinbach

            Ihr Ansprechpartner
            Telefon
            E-Mail
            Lieferanschrift

            Lerchenweg 7
            53359 Rheinbach

            {{ me.NAME }}
            {{ me.PHONE }}
            {{ me.EMAIL }}
            {{ doc.dateStr }}
            {{ doc.docType }}
            {{ doc.ident }} {% if doc.predecessor %}     ({{ label.PREDECESSOR }}: {{ doc.predecessor }}) {% endif %}
            {% if doc.doc.buyerReference %}
            {{ label.BUYERREFERENCE }}
            {{ doc.buyerReference }}
            {% endif %} {% if doc.projectLabel %}
            {{ label.PROJECT }}: {{ doc.projectLabel }}
            {% endif %}
            {% if doc.salut %}

            {{ doc.salut }}

            {% endif %} {% if doc.preText %}

            {{ doc.preText }}

            {% endif %} {% if doc.postText %}

            {{ doc.postText }}

            {% endif %}

            {{ doc.goodbye }}

            {% endautoescape %} kraft-1.1/reports/contrib/debug/000077500000000000000000000000001450127457600167215ustar00rootroot00000000000000kraft-1.1/reports/contrib/debug/README.md000066400000000000000000000003221450127457600201750ustar00rootroot00000000000000This debug template displays all available template variables including their value of the current docuemnt. Very useful to understand which variables are available. Contributed by Achim Patzner kraft-1.1/reports/contrib/debug/debug.css000066400000000000000000000221631450127457600205250ustar00rootroot00000000000000/* Zeichensatz: */ @charset "UTF-8"; /* Fonts: */ /* as this document will always be rendered on the same small set of * machines using web fonts off the web may be overkill and create * unnecessary traffic and extended rendering times. It is far better to * download the woff-files from their source and store them besides this * file (or use a specified path for them). You can yúse OTF and TTF * files just as well. */ @import url("https://fonts.googleapis.com/css?family=Calibri|Oxygen|Pacifico|Open+Sans+Pro:400,700,400italic,700italic,400bold"); @import url("https://fonts.googleapis.com/css?family=Consolas|Inconsolata:400,700,400italic,700italic"); @import url("https://fonts.googleapis.com/css?family=Roboto"); @import url("https://fonts.googleapis.com/css?family=Raleway"); @import url("https://fonts.googleapis.com/css?family=Calibri:400"); @import url("https://fonts.googleapis.com/css?family=Calibri:700"); @import url("https://fonts.googleapis.com/css?family=Calibri:400italic"); @import url("https://fonts.googleapis.com/css?family=Calibri:700italic"); @import url("https://fonts.googleapis.com/css?family=Calibri:400bold"); @import url("https://fonts.googleapis.com/css?family=Consolas:400"); @import url("https://fonts.googleapis.com/css?family=Consolas:700"); @import url("https://fonts.googleapis.com/css?family=Consolas:400italic"); @import url("https://fonts.googleapis.com/css?family=Consolas:700italic"); /* General page settings for printouts */ @page { size: A4 portrait; margin-left: 10mm; margin-top: 10mm; margin-right: 10mm; margin-bottom: 10mm; } h1 { page-break-before: always; } h1, h2, h3, h4, h5, h6, h7 { /* page-break-after: avoid; */ } table, tr, figure { page-break-inside: avoid; page-break-after: auto; } /* page break class; use as
            to insert */ .pagebreak { page-break-before: always; } /* DIN 5008 address field */ /* height 45mm. Address starts 17.7mm from top, 6 linex max. Additional * remarks go upwards into the upper 17.7mm, 5 lines max. * see https://www.workingoffice.de/din-5008/adresse-nach-din-5008/ */ .ISO-address-window { font-family: Calibri; font-size: 8pt; font-style: normal; line-height: 1.1; position: absolute; display: block; white-space: pre-line; top: 45mm; /* top: 62.7mm; */ left: 20mm; width: 90mm; height: 45mm; } .address-field { display: block; white-space: pre-line; line-height: 1.2; } .buyer-reference { position: absolute; font-family: Calibri; font-size: 10pt; line-height: 1.25; top: 93mm; left: 98mm; width: 400mm; height: 20pt; } .date { position: absolute; font-family: Calibri; font-size: 12pt; font-weight: bold; line-height: 1; top: 93mm; left: 144mm; width: 30mm; height: 12pt; } .document-type-and-number { position: absolute; font-family: Barmeno; font-size: 12pt; font-weight: bold; line-height: 1.2; top: 110mm; left: 0mm; width: 165mm; height: 36pt; } .header-block-1 { position: absolute; font-family: Barmeno; font-size: 10pt; line-height: 1.25; top: 45mm; left: 98mm; width: 40mm; height: 40mm; } .header-block-2 { position: absolute; font-family: Barmeno; font-size: 10pt; line-height: 1.25; top: 45mm; left: 144mm; width: 40mm; height: 40mm; } .project { position: absolute; font-family: Calibri; font-size: 10pt; font-weight: bold; line-height: 1; top: 125mm; left: 0mm; width: 165mm; } /* report area; item styling */ .doc-items { border-collapse: collapse; width: 165mm; table-layout: fixed; page-break-inside:avoid; margin-right: 0px; margin-left: 0px; } .doc-items-header { /* meaning all th (table header) cells in a table of class doc-item */ vertical-align: top; line-height: 1.1; box-sizing: border-box; border-collapse: padding-top: 2mm; padding-left: 2mm; padding-right: 2mm; border: solid; border-spacing: 1px; border-top: 1px solid black; border-bottom: 1px solid black; border-left: 0; border-right: 0; } table.doc-items td { /* meaning all td cells in a table of class doc-item -- remember, every item might be in its own table */ vertical-align: top; line-height: 1.1; box-sizing: border-box; padding-top: 2mm; padding-left: 2mm; padding-right: 2mm; } .doc-item-style-individualTaxation { vertical-align: super; font-size: 60%; } .col-item-no { vertical-align: top; width: 6%; } .col-item-text { width: 75%; } .col-item-alternative { width: 75%; } .col-item-comment { width: 75%; } .col-item-ondemand { width: 75%; } .col-item-standard { width: 75%; } .col-item-amount { width: 52%; } .col-item-unit { width: 12%; } .col-item-unitprice { width: 15%; } .col-item-total { width: 15%; color: #000000; font-weight: bold; } /* totals, taxes and bottom text */ .totals { width: 165mm; /* table-layout: fixed; /* this somehow adds 2mm horizontal spacing and messes everyting up */ vertical-align: top; line-height: 1.25; box-sizing: border-box; text-align: right; bottom: 0; /* The following margins pull the whole box to the right */ margin-right: 0; margin-left: 0; margin-top: 8mm; /*separation between items and sums */ margin-bottom: 12mm; /* separation between sums and footer text */ } table.totals td { box-sizing: border-box; padding-top: 2mm; padding-left: 2mm; padding-right: 2mm; } .totals-col-spacer { padding-top: 1mm; width: 60%; } .totals-col-label { padding-top: 1mm; width: 20%; } .totals-col-value { padding-top: 1mm; width: 20%; } .totals-first-line { border-top: solid black 1px; } .totals-final-line { border-top: solid black 1px; border-bottom: solid black 2px; } .entrytext { } .entrytext-unprocessed { white-space: pre-line; } .bottomtext { } .bottomtext-unprocessed { white-space: pre-line; } .goodbye { } /* This will be the style for the first element of the "report area" of the printout. * Due to absolute positioning of blocks above it it is impossible to adjust the * start of that zone using a top margin. It will be used on an otherwise * empty div. */ .generate-first-page-margin { font-family: Calibri; font-size: 10pt; line-height: 1.2; left: 0mm; width: 165mm; padding-top: 135mm; } /* Tables with units konsiting of multiple rows might be getting a page break * inserted where it hurts. This will avoid them. */ .no-page-break-inside { page-break-inside: avoid; } /* these classes can be used for debugging whenever you don't understand * what is happening to your positioning just add one of these classes * to your HTML
            s */ .DEBUG-box-black { border: 0.1mm solid black; } .DEBUG-box-red { border: 0.1mm solid red; } .DEBUG-box-green { border: 0.1mm solid green; } .DEBUG-box-blue { border: 0.1mm solid blue; } /* bad style to do things not based on semantic grouping, but... */ /* text alignment within an element */ .align-center { text-align: center; } .align-left { text-align: left; } .align-right { text-align: right; } .align-justify { text-align: right; } .superscript { vertical-align: super; font-size: 60%; } .subscript { vertical-align: sub; font-size: 60%; } .weight-bold { font-weight: bold; } .weight-normal { font-weight: normal; } /* explicit font settings */ .main-font-regular-6 { font-family: 'Calibri'; font-size: 6pt; } .main-font-regular-8 { font-family: 'Calibri'; font-size: 8pt; } .main-font-regular-10 { font-family: 'Calibri'; font-size: 10pt; } .main-font-regular-12 { font-family: 'Calibri'; font-size: 12pt; } /* classless settings for the entire document */ html { font-family: 'Calibri'; font-size: 10pt; line-height: 1.2; margin: 0px; } /* A perverse invention by Google: There is a browser built-in CSS style * sheet defining certain settings "to make the web look like it should". * The worst part are implicit margin settigs that affect any element * without "position: absolute;". While this might be a good idea for a web * browser it makes print layout an educated guess. */ body{ margin: 0px; } table { border-collapse: collapse; vertical-align: top; box-sizing: border-box; } th { border-bottom: .2mm solid #555; color: #555; font-size: 10pt; font-weight: 400; /* padding-bottom: .25cm; */ } td { vertical-align: top; } /* } /* @media print} */ /* The following style definitions are intended to be used in multi-line * text entries as poor man's easy-to-use HTML building blocks. Use them * inside s for text effects. */ .font-barmeno { font-family: Bameno; } .font-consolas { font-family: Consolas; } kraft-1.1/reports/contrib/debug/debug.gtmpl000066400000000000000000000270221450127457600210570ustar00rootroot00000000000000 Document Information Sheet {% autoescape off %}

            Document Information Sheet

            About Kraft ("kraft.*")

            kraft. Content
            VERSION {{ kraft.VERSION }}
            DB_SCHEME {{ kraft.DBSCHEME }}
            SYS_USER {{ kraft.SYS_USER }}
            HOSTNAME {{ kraft.HOSTNAME }}

            Django % debug %

            {% debug %}

            Recipient's address

            {{ doc.address }}

            About "me."

            Field "label." "me."
            ORGANIZATION {{ label.ORGANISATION }} {{ me.ORGANISATION }}
            STREET{{ me.STREET }}
            POSTCODE{{ me.POSTCODE }}
            POSTBOX{{ me.POSTBOX }}
            EXTENDED{{ me.EXTENDED }}
            LOCALITY{{ me.LOCALITY }}
            REGION{{ me.REGION }}
            COUNTRY{{ me.COUNTRY }}
            LABEL{{ me.LABEL }}
            URL{{ label.WEBSITE }}{{ me.URL }}
            EMAIL{{ me.URL }}
            PHONE{{ me.PHONE }}
            FAX{{ me.FAX }}
            CELL{{ me.CELL }}

            "customer.*"

            customer.* "label." Content
            ORGANIZATION {{ label.ORGANISATION }} {{ customer.ORGANISATION }}
            STREET{{ customer.STREET }}
            POSTCODE{{ customer.POSTCODE }}
            POSTBOX{{ customer.POSTBOX }}
            EXTENDED{{ customer.EXTENDED }}
            LOCALITY{{ customer.LOCALITY }}
            REGION{{ customer.REGION }}
            COUNTRY{{ customer.COUNTRY }}
            LABEL{{ customer.LABEL }}
            URL{{ label.WEBSITE }}{{ customer.URL }}
            EMAIL{{ customer.URL }}
            PHONE{{ customer.PHONE }}
            FAX{{ customer.FAX }}
            CELL{{ customer.CELL }}

            Labels ("label.*")

            "label." Content
            NO_SHORT{{ label.NO_SHORT }}
            ITEM{{ label.ITEM }}
            QUANTITY_SHORT{{ label.QUANTITY_SHORT }}
            UNIT{{ label.UNIT }}
            PRICE{{ label.PRICE }}
            SUM{{ label.SUM }}
            NET{{ label.NET }}
            VAT{{ label.VAT }}
            TYPE{{ label.TYPE }}
            PHONE{{ label.PHONE }}
            FAX{{ label.FAX }}
            MOBILE{{ label.MOBILE }}
            EMAIL{{ label.EMAIL }}
            WEBSITE{{ label.WEBSITE }}
            PREDECESSOR{{ label.PREDECESSOR }}
            PAGE{{ label.PAGE }}
            PAGE_OF{{ label.PAGE_OF }}
            DOC_NO{{ label.DOC_NO }}
            DATE{{ label.DATE }}
            PROJECT{{ label.PROJECT }}
            CUST_ID{{ label.CUST_ID }}
            CURRENCY_SIGN{{ label.CURRENCY_SIGN }}
            NO_SHORT{{ label.NO_SHORT }}
            ITEM{{ label.ITEM }}
            QUANTITY_SHORT{{ label.QUANTITY_SHORT }}
            UNIT{{ label.UNIT }}
            PRICE{{ label.PRICE }}
            SUM{{ label.SUM }}

            Document ("doc.")

            Field "label." "doc."
            dateStr{{ doc.dateStr }}
            dateStrISO{{ doc.dateStrISO }}
            docType (TYPE){{ label.TYPE }}{{ doc.docType }}
            clientUid{{ doc.clientUid }}
            goodbye{{ doc.goodbye }}
            docIDStr{{ doc.docIDStr }}
            docIdentifier{{ doc.docIdentifier }}
            ident (DOC_NO){{ label.DOC_NO }}{{ doc.ident|safe }}
            buyerReference{{ doc.buyerReference }}
            dateStr (DATE){{ label.DATE }}{{ doc.dateStr }}
            dueDateStrISO{{ doc.dueDateStrISO }}
            projectLabel (PROJECT){{ label.PROJECT }}{{ doc.projectLabel }}
            predecessor (PREDECESSOR){{ label.PREDECESSOR }}{{ doc.predecessor }}
            salut{{ doc.salut }}
            preText{{ doc.preText }}
            preTextHtml{{ doc.preTextHtml|safe }}
            postText{{ doc.postText }}
            postTextHtml{{ doc.postTextHtml|safe }}

            Items ("doc.items.*")

            {% for item in doc.items %} {% if doc.hasIndividualTaxation %} {% endif %} {% endfor %}
            {{ label.NO_SHORT }} {{ label.ITEM }} {{ label.QUANTITY_SHORT }} {{ label.UNIT }} {{ label.PRICE }} {{ label.SUM }}
            {{ item.itemNumber }}. {% if item.kind == 'Alternative' %} item.kind == 'Alternative' {% elif item.kind == 'Comment' %} item.kind == 'Comment' {% elif item.kind == 'Demand' %} item.kind == 'Demand' {% else %} item.kind == 'Standard' {% endif %} taxMarker: {{ item.taxMarker }}
            {{ item.text }}
            {{ label.QUANTITY_SHORT }} {{ label.UNIT }} {{ label.PRICE }} {{ label.SUM }}
            {{ item.amount }} {{ item.unit }} {{ item.unitPrice }} {{ item.nettoPrice }}



            Footer data ("doc.*")

            "doc.*" Content
            nettoSumStr{{ doc.nettoSumStr }}
            nettoSumNum{{ doc.nettoSumNum }}
            bruttoSumStr{{ doc.bruttoSumStr }}
            bruttoSumNum{{ doc.bruttoSumNum }}
            taxSumStr{{ doc.taxSumStr }}
            taxSumNum{{ doc.taxSumNum }}
            fullTaxSumStr{{ doc.fullTaxSumStr }}
            fullTaxSumNum{{ doc.fullTaxSumNum }}
            reducedTaxSumStr{{ doc.reducedTaxSumStr }}
            reducedTaxSumNum{{ doc.reducedTaxSumNum }}
            dueDate{{ doc.dueDate }}
            dueDateStrISO{{ doc.dueDateStrISO }}
            buyerReference{{ doc.buyerReference }}
            fullTaxPercentNum{{ doc.fullTaxPercentNum }}
            fullTaxPercentStr{{ doc.fullTaxPercentStr }}
            reducedTaxPercentNum{{ doc.reducedTaxPercentNum }}
            reducedTaxPercentStr{{ doc.reducedTaxPercentStr }}
            taxPercentStr{{ doc.taxPercentStr }}
            taxPercentNum{{ doc.taxPercentNum }}
            taxMarkerFull{{ doc.taxMarkerFull }}
            taxMarkerReduced{{ doc.taxMarkerReduced }}
            {% endautoescape %} kraft-1.1/reports/contrib/kfg/000077500000000000000000000000001450127457600164025ustar00rootroot00000000000000kraft-1.1/reports/contrib/kfg/README000066400000000000000000000001671450127457600172660ustar00rootroot00000000000000A very plain output document with position texts over the whole line and prices below. To be printed on company paper. kraft-1.1/reports/contrib/kfg/invoice.trml000066400000000000000000000133771450127457600207510ustar00rootroot00000000000000 blockAlignment start="0,0" stop="3,0" value="RIGHT" />

            {{ADDRESS}}
            {{DOCTYPE}} Nr. {{DOCID}} {{SALUT}} {{PRETEXT}} {{#POSITIONS}} {{POS_NUMBER}}. {{POS_TEXT}} {{POS_AMOUNT}} {{POS_UNIT}} je {{POS_UNITPRICE}} {{POS_TOTAL}} {{/POSITIONS}} Netto {{NETTOSUM}} {{#SECTION_REDUCED_TAX}} +{{REDUCED_TAX}}% MwSt. {{REDUCED_TAX_SUM}} {{/SECTION_REDUCED_TAX}} {{#SECTION_FULL_TAX}} +{{FULL_TAX}}% MwSt. {{FULL_TAX_SUM}} {{/SECTION_FULL_TAX}} Gesamt {{BRUTTOSUM}} {{#SPECIAL_POS}} Bitte beachten Sie: Dieses Angebot enthält {{COUNT}} in Schrägschrift gedruckte Alternativ- oder Bedarfsposten. Diese sind in der Endsumme nicht enthalten. {{/SPECIAL_POS}} {{POSTTEXT}} {{GOODBYE}}
            kraft-1.1/reports/delivery_receipt.trml000066400000000000000000000142451450127457600204370ustar00rootroot00000000000000

            {{ADDRESS}}
            {{DATE}}

            {{DOCTYPE}} {{LAB_NO_SHORT}} {{DOCID}}

            {{SALUT}} {{PRETEXT}} {{LAB_NO_SHORT}} {{LAB_ITEM}} {{LAB_QUANTITY_SHORT}} {{LAB_UNIT}} {{#POSITIONS}} {{POS_NUMBER}}. {{POS_TEXT}} {{POS_AMOUNT}} {{POS_UNIT}} {{/POSITIONS}} {{POSTTEXT}} {{GOODBYE}}
            kraft-1.1/reports/invoice.gtmpl000066400000000000000000000152621450127457600167020ustar00rootroot00000000000000 {% if doc.projectLabel %} {% endif %} {% if doc.predecessor %} {% endif %} {% if doc.projectLabel %} {% endif %} {# Include the stylesheet file. It will have to reside in the same dir as the template file #} {# "Set to 1 to enable html in the texts - experimental! #} {% with 0 as enableHtmlInTexts %} {{ doc.docType }} {{ doc.ident }} {% autoescape off %}

            {{ me.ORGANISATION }} - {{ me.STREET }} - {{ me.POSTCODE }} {{ me.LOCALITY }}

            {{ doc.address }}
            {{ label.TYPE }}
            {{ doc.docType }}
            {{ label.DOC_NO }}
            {{ doc.ident }}
            {{ label.DATE }}
            {{ doc.dateStr }}
            {% if doc.projectLabel %}
            {{ label.PROJECT }}
            {{ doc.projectLabel }}
            {% endif %} {% if doc.predecessor > 0 %}
            {{ label.PREDECESSOR }}
            {{ doc.predecessor }}
            {% endif %}

            {{ doc.docType }} {{ doc.ident }}

            {{ doc.salut }}

            {% if enableHtmlInTexts %} {{ doc.preText|safe|linebreaks }} {% else %} {{ doc.preTextHtml|safe }} {% endif %}

            {% for item in doc.items %} {% endfor %}
            {{ label.NO_SHORT }} {{ label.ITEM }} {{ label.QUANTITY_SHORT }} {{ label.UNIT }} {{ label.PRICE }} {{ label.SUM }}
            {{ item.itemNumber }}. {% if item.kind == 'Alternative' or item.kind == 'Demand' %} {% endif %} {% if enableHtmlInTexts %} {{ item.text|linebreaks }} {% else %} {{ item.htmlText|safe }} {% endif %} {% if item.kind == 'Alternative' or item.kind == 'Demand' %} {% endif %} {{ item.amount }} {{ item.unit }} {{ item.unitPrice }} {{ item.nettoPrice }} {{ item.taxMarker }}
            {% if doc.hasIndividualTaxation %} {# This section is shown for documents with individual tax rates #} {% else %} {# This section is shown for documents with one consistent tax rate #} {# Note: taxPercentStr can either be reduced or full, depending on #} {# the tax settings of the document #} {% endif %}
            {{ label.NET }} {{ doc.nettoSumStr }}
            {{ doc.taxMarkerReduced }}  +{{ doc.reducedTaxPercentStr }}% {{ label.VAT }} {{ doc.reducedTaxSumStr }}
            {{ doc.taxMarkerFull }}  +{{ doc.fullTaxPercentStr }}% {{ label.VAT }} {{ doc.fullTaxSumStr }}
            +{{ doc.taxPercentStr }}% {{ label.VAT }} {{ doc.taxSumStr }}
            {{ label.SUM }} {{ doc.bruttoSumStr }}

            {% if enableHtmlInTexts %} {{ doc.postText|linebreaks }} {% else %} {{ doc.postTextHtml|safe }} {% endif %}

            {{ doc.goodbye }}

            {%if doc.isInvoice and epcqrcode.valid and epcqrcode.show %}

            EPC QR Code Dieser QR Code ermöglicht einfaches, sicheres und schnelles Begleichen dieser Rechnung via GiroPay: Diesen Code mit dem Smartphone scannen und Überweisung per Banking App aufgeben.

            {% endif %} {% endautoescape %} {% endwith %} kraft-1.1/reports/invoice.trml000066400000000000000000000200601450127457600165250ustar00rootroot00000000000000

            {{ADDRESS}}
            {{DATE}}

            {{DOCTYPE}} {{LAB_NR_SHORT}} {{DOCID}}

            {{SALUT}} {{PRETEXT}} {{LAB_NO_SHORT}} {{LAB_ITEM}} {{LAB_QUANTITY_SHORT}} {{LAB_UNIT}} {{LAB_PRICE}} {{LAB_SUM}} {{#POSITIONS}} {{POS_NUMBER}}. {{POS_TEXT}} {{POS_AMOUNT}} {{POS_UNIT}} {{POS_UNITPRICE}} {{POS_TOTAL}} {{#TAX_FREE}} a) {{/TAX_FREE}} {{#REDUCED_TAX}} b) {{/REDUCED_TAX}} {{#FULL_TAX}} {{/FULL_TAX}} {{/POSITIONS}} {{LAB_NET}} {{NETTOSUM}} {{#SECTION_REDUCED_TAX}} +{{REDUCED_TAX}}% {{LAB_VAT}} {{REDUCED_TAX_SUM}} {{/SECTION_REDUCED_TAX}} {{#SECTION_FULL_TAX}} +{{FULL_TAX}}% {{LAB_VAT}} {{FULL_TAX_SUM}} {{/SECTION_FULL_TAX}} {{LAB_SUM}} {{BRUTTOSUM}} {{#TAX_FREE_ITEMS}} a)  {{LAB_TAX_FREE_ITEMS}} {{/TAX_FREE_ITEMS}} {{#REDUCED_TAX_ITEMS}} b)  {{LAB_TAX_REDUCED_ITEMS}} {{/REDUCED_TAX_ITEMS}} {{#FULL_TAX_ITEMS}} {{LAB_TAX_FULL_ITEMS}} {{/FULL_TAX_ITEMS}} {{#SPECIAL_POS}} {{LAB_SPECIAL_ITEMS}} {{/SPECIAL_POS}} {{POSTTEXT}} {{GOODBYE}}
            kraft-1.1/reports/invoice_kfg.gtmpl000066400000000000000000000143211450127457600175240ustar00rootroot00000000000000 Kraft Document {% autoescape off %}

            {{ me.ORGANISATION }} - {{ me.STREET }} - {{ me.POSTCODE }} {{ me.LOCALITY }}

            {{ doc.address }}
            {{ label.DOC_NO }}
            {{ doc.ident }}
            {{ label.DATE }}
            {{ doc.dateStr }}
            {% if doc.projectLabel %}
            {{ label.PROJECT }}
            {{ doc.projectLabel }}
            {% endif %}

            {{ doc.docType }} {{ doc.ident }}

            {{ doc.salut }}

            {{ doc.preTextHtml|safe }}

            {% for item in doc.items %}
            {{ item.itemNumber }}. {% if item.kind == 'Alternative' or item.kind == 'Demand' %} {% endif %} {{ item.htmlText }} {% if item.kind == 'Alternative' or item.kind == 'Demand' %} {% endif %}
            {{ item.amount }}  {{ item.unit }} {{ item.unitPrice }} {{ item.nettoPrice }} {% if doc.hasIndividualTaxation %} {{ item.taxMarker }}  {% endif %}
            {% endfor %} {% if doc.hasIndividualTaxation %} {% else %} {% endif %}
            {{ label.NET }} {{ doc.nettoSumStr }}
            {{ doc.taxMarkerReduced }}  +{{ doc.reducedTaxPercentStr }}% {{ label.VAT }} {{ doc.reducedTaxSumStr }}
            {{ doc.taxMarkerFull }}  +{{ doc.fullTaxPercentStr }}% {{ label.VAT }} {{ doc.fullTaxSumStr }}
            +{{ doc.taxPercentStr }}% {{ label.VAT }} {{ doc.taxSumStr }}
            {{ label.SUM }} {{ doc.bruttoSumStr }}

            {{ doc.postTextHtml|safe }}

            {{ doc.goodbye }}

            {% endautoescape %} kraft-1.1/reports/kraft.css000066400000000000000000000063051450127457600160200ustar00rootroot00000000000000 html { color: #14213d; font-family: Oxygen; font-size: 10pt; line-height: 1.6; } html body { margin: 0; padding-top: 2mm; } html h1 { color: #2f590a; font-family: Roboto; font-size: 14pt; margin: 0; } html address { font-style: normal; white-space: pre-line; margin-bottom: 9mm; height: 40mm; border: solid 0px; } html aside { display: flex; margin: 2em 0 4em; } html aside address { font-style: normal; white-space: pre-line; } html aside address#to { color: #a9a; flex: 1; } html aside address#from { text-align: right; } /* * A absolute positioned block to display document extra info * on the right top of the document. */ html dl { text-align: right; position: absolute; right: 0; top: 8mm; } html dl dt, html dl dd { display: inline; margin: 0; } html dl dt { color: #a9a; } html dl dt::before { content: ''; display: block; } html dl dt::after { content: ':'; } sup { position: relative; vertical-align: baseline; top: -0.4em; } /* */ html p#letterheader { font-size: 8pt; text-decoration: underline; } html p.entrytext { } html p.bottomtext { } html p.goodbye { } html p.epcqrcode { margin-top: 2cm; border-top: 0.5px solid #888; padding-top: 1em; vertical-align: top; font-size: 8pt; } html img.epc { border: 1px solid #ddd; border-radius: 4px; padding: 5px; width: 120px; float: right; } /* * Item-Table * formats the item list. Each item is a line. */ html table#items { border-collapse: collapse; width: 100%; table-layout: fixed; /* The following margins pull the whole box to the right */ margin-right: 0px; margin-left: auto; } /* * Table header. It is repeated on every page. */ html table th { border-bottom: .2mm solid #555; color: #555; font-size: 10pt; font-weight: 400; padding-bottom: .25cm; text-transform: uppercase; } html table td { vertical-align: top; padding-top: 6mm; } .col-center { text-align: center; } .col-right { text-align: right; } .col-left { text-align: left; } .col-No { width: 5%; } .col-Text { width: 45%; } .col-Amount { width: 8%; padding-right:0.8em; } .col-Unit { width: 10%; } .col-SPrice { width: 11%; } .col-Sum { width: 14%; color: #2f590a; font-weight: bold; } .col-Taxmarker { width: 1%; } /* * The table to display the document sum */ html table#total { border-collapse: collapse; width: 40%; table-layout: fixed; text-align: right; bottom: 0; font-size: 10pt; /* The following margins pull the whole box to the right */ margin-right: 22px; margin-left: auto; margin-bottom: 12mm; } html table#total td { padding-top: 1mm; text-align: right; } .col-TotalSum { color: #2f590a; font-weight: bold; } /* the lines above the sums */ html table#total tr:nth-of-type(1) { border-top: solid 1px; } html table#total tr:last-of-type { border-top: solid 2px; } kraft-1.1/reports/kraft_kfg.css000066400000000000000000000073161450127457600166520ustar00rootroot00000000000000 @charset "UTF-8"; /* Use google web fonts */ @import url("https://fonts.googleapis.com/css?family=Pacifico|Open+Sans+Pro:400,700"); @import url("https://fonts.googleapis.com/css?family=Roboto"); @import url("https://fonts.googleapis.com/css?family=Oxygen"); @import url("https://fonts.googleapis.com/css2?family=Raleway"); @import url("https://fonts.googleapis.com/css2?family=Inconsolata:wght@700"); /* General page settings for print */ @page { size: A4; margin-left: 2.4cm; margin-top:27mm; margin-right: 1.6cm; margin-bottom: 2cm; color: #2f590a; } html { font-family: 'Oxygen'; font-size: 10pt; line-height: 1.6; } html body { margin: 0; padding-top: 2mm; } html h1 { color: #2f590a; font-family: Roboto; font-size: 14pt; margin: 0; } html address { font-style: normal; white-space: pre-line; margin-bottom: 9mm; height: 40mm; border: solid 0px; } html aside { display: flex; margin: 2em 0 4em; } html aside address { font-style: normal; white-space: pre-line; } html aside address#to { color: #a9a; flex: 1; } html aside address#from { text-align: right; } /* * A absolute positioned block to display document extra info * on the right top of the document. */ html dl { text-align: right; position: absolute; right: 0; top: 8mm; } html dl dt, html dl dd { display: inline; margin: 0; } html dl dt { color: #a9a; } html dl dt::before { content: ''; display: block; } html dl dt::after { content: ':'; } sup { position: relative; vertical-align: baseline; top: -0.4em; } img#logo { position: absolute; right: 0px; top: -150px; width: 178px; height: 191px; z-index: -1; } html p.letterheader { font-size: 8pt; text-decoration: underline; } html p.entrytext { } html p.bottomtext { } html p.goodbye { } /* * Item-Table * formats the item list. Each item is a line. */ html table.items { border-collapse: collapse; width: 16.8cm; table-layout: fixed; page-break-inside:avoid; margin-right: 0px; margin-left: 0px; } html table tr { page-break-inside:avoid; page-break-after:auto; } /* * Table header. It is repeated on every page. */ html table th { border-bottom: .2mm solid #555; color: #555; font-size: 10pt; font-weight: 400; padding-bottom: .25cm; text-transform: uppercase; } html table td { vertical-align: top; padding: 0px; padding-top: 3mm; } html table tr.secondline td { padding-top: 1mm; } .col-center { text-align: center; } .col-right { text-align: right; } .col-left { text-align: left; } /* The columns of the items table */ .col-No { width: 6%; } .col-Text { width: 75%; } .col-Amount { width: 52%; } .col-Unit { width: 12%; } .col-SPrice { width: 15%; } .col-Sum { width: 15%; color: #2f590a; font-weight: bold; } .col-total-first { width: 60%; } .col-total-mid { width: 20%; } .col-total-last { width: 20%; } /* * The table to display the document sum */ html table#total { border-collapse: collapse; width: 16.8cm; table-layout: fixed; text-align: right; bottom: 0; font-size: 10pt; /* The following margins pull the whole box to the right */ margin-right: 0px; margin-left: 0px; margin-bottom: 12mm; margin-top: 8mm; } html table#total td { padding-top: 1mm; text-align: right; } .col-total-line1 { border-top: solid black 1px; } .col-total-line2 { border-top: solid black 2px; } kraft-1.1/reports/offer_no_prices.trml000066400000000000000000000155451450127457600202470ustar00rootroot00000000000000 {{ADDRESS}} {{DATE}}

            {{DOCTYPE}} {{LAB_NO_SHORT}} {{DOCID}}

            {{SALUT}} {{PRETEXT}} {{LAB_NO_SHORT}} {{LAB_ITEM}} {{LAB_QUANTITY_SHORT}} {{#POSITIONS}} {{POS_NUMBER}}. {{POS_TEXT}} {{POS_AMOUNT}} {{POS_UNIT}} {{/POSITIONS}} {{#SPECIAL_POS}} {{LAB_SPECIAL_ITEMS}} {{/SPECIAL_POS}} {{POSTTEXT}} {{GOODBYE}}
            kraft-1.1/reports/pdfwatermark_3pages.odt000066400000000000000000000236031450127457600206400ustar00rootroot00000000000000PKdU^2 ''mimetypeapplication/vnd.oasis.opendocument.textPKdUConfigurations2/accelerator/PKdUConfigurations2/images/Bitmaps/PKdUConfigurations2/toolpanel/PKdUConfigurations2/progressbar/PKdUConfigurations2/statusbar/PKdUConfigurations2/toolbar/PKdUConfigurations2/floater/PKdUConfigurations2/popupmenu/PKdUConfigurations2/menubar/PKdU manifest.rdf͓n0=wE8FP=|d-D/G;PKq't PKdU settings.xml[[W"9~_AuV:PfAg-t5I"~Ҡ/4O@_JU}_UD=uᧃRKߥHFPM%kWI|!jE꣪IA/^|W祉i\N?;.ţƘIv>pਜ~z:z aϥӿ8%ؗ2);/ᐫOV+{w~5 b`⎟xG=.]We_nF~brd'kW*b¿Ov3ANcpK(tmh5S&MGBwOD/u kw}&oKCuJ269se{b7J`kN>V݇v# ɮM!l޿I(j&B -f& D/\z˥׍YTڥ)"o솱oi냂Cܴxa?Ҟ0.cuc5! )9k,\|7ݞ x?/dVCt15.EWa0sbX4;*aAB`a A@`0Fq'Et?&׸K+yNvbƇ\$P0 c]LaLv3 1I4%LA>am"=$a! +vRQ$"%YZX ; ^-li$$QG Ĉ &q-$RDCS$NT戇ո Wuj_=+hȆ^[!B2|W3\Hd#LAir`J!H8fkL^}{N.#A/eR "ʪkƹp|@i.P抣]Srщޤn [5aHw\Uȑj)3r~4$[,?_ۋ(^n4_MZp~"FU ̡:WAյ!eEBH%x=6Xsw-ݖo_N0m{;|ɠ5X,qݖ̛]:O4ԋos`-Mz-A9?aEܥ1G`.BgBqq7hsۚL~[:P`\(;d)CPo<%BE⪰F=,V!!Rڳ +xVX/#WV?DP-DIyNALGDnâfEdH1%֑䚬TZj y}dP0uv`Wn(8ZIі9GfL` c:9aaJI!9s@hy)M۹PKln3PKdUyp/Thumbnails/thumbnail.pngPNG  IHDRjpPLTE,0.-LKeϽ;6V1Xzˑ孕a}zp@ͺ=A-xt8|kÇ,<|"Sg> [6/_s]{ęaS)NQKvx$B.'N&x'C2kܷn>qFjԨ~+/B(9ՏIENDB`PKdU styles.xmln8}`e'd;b}ms#Iv~EdVl1-sbϳ3!fфHyygrwb ["rVh!cjąZ&J-Cպ\Njr3aDF{#4ÞffRM3g<~^~j5x =cD4dTq,hR'KQ[ Gve-d>qCڜMwӏ4}mJs !jqH`1wwcXI{ K* ݝ\3Y:pZZIqM$4Kj jY ɔe W* 䦮 e+?/![8~35:/9֍>guGXO12)tO R:Rh*xERf*Y)@%$[*G soG3M#nHXeQ+&GXs׫$WЙD -;Glk&,;Gd ljRn`)ef!SKkG3 [yb0Nwd-i[(҃MYK/[qjxO P' 5B 5_&ZeLs':Y!! m3=ܲd4M!4FQg2ڶTVE+>_iBHʡ(7qڵX6sIoa1-9)YNyApye] :%bdp';!hnÂ-URhd,Lt;@)H- >!3pX'Jņ-N<& R>2[&+c~`4  ;XI*63,1OsM9"ijܜuu|p MK{E)9$D=srי1ŷM_N#84#xxPkS&yͨp46ih\Sg"`#/3zjf_S/.B[he|*{m^b~!5H[3Ι?Q3a:$:kжׅfTm78n'Spj1'gCgʛq xôɴ{i/}{R):*7ƍIּqO1ǓK=5X4:U$n<ai'9i}u9vt]* Me_,|o '?K8NX&*moRO :{fCвߪc Sxpr] g3h`0l?8fq ر ׫@!m,.i;␶Cn.i;䇋C8퐻C8s0y T``,|S+@ܤy,v}L,`="͹|3 iUא鐂_A=h'fpZדfcx!ck`Hy!;} pk-COKF7$z_1maO4_~7۠R*nu{Ff2)>4WY.W _ncD@Ji"$.{;xRaKCΣ![$U~Cv<7>摜#UOSY|׈(Ȋ_ >ijMBJӯ"%2^_)V%.ԯ)Mxkʟ.D\Ճ+[N>ZxE3Z([+R5]帍8@NU͢[DN'?~)6븥MϓSHGmu,c6ZAmsʎꟁ}:/PKazX 4PKdU content.xmlWMo6W*C;nd/A Pl@DRJR;$%v,[Df烤nklLt~3K*rY0Q=ߟ]{Y,Y! \ ` Z/C60[HUoڐ[]зW ݯc6I|\bg PF\?/o1 9ݳˬ.{.d=n sdD&f::3y&*g1:sEoll51W0ח[bjxR`vf8*᲋yvXWyfU|yǓx^ҋV5~PK_2PKdUMETA-INF/manifest.xmln }˄0iO=KLD S5o?5MR#ߖ.-qXWe`mž_;7NIN"x +JUQR-l\:@tm\&nh.a(W_!!tZ0*7܂6\ـN֖^ѩb⮯yURb{kѐ8ce뜲 &xtMˆoA혐y2^։Ow<4\EWj01(m|:xJ*c=wDLZC~}-<|1N_PKK -%PKdU^2 ''mimetypePKdUMConfigurations2/accelerator/PKdUConfigurations2/images/Bitmaps/PKdUConfigurations2/toolpanel/PKdUConfigurations2/progressbar/PKdU6Configurations2/statusbar/PKdUnConfigurations2/toolbar/PKdUConfigurations2/floater/PKdUConfigurations2/popupmenu/PKdUConfigurations2/menubar/PKdUh Hmanifest.rdfPKdUq't meta.xmlPKdUln3 settings.xmlPKdUyp/( Thumbnails/thumbnail.pngPKdUazX 4 styles.xmlPKdU_2 content.xmlPKdUK -%!META-INF/manifest.xmlPKe#kraft-1.1/reports/pdfwatermark_3pages.pdf000066400000000000000000000232251450127457600206230ustar00rootroot00000000000000%PDF-1.6 %äüöß 2 0 obj <> stream xm A }­Inw/!S,X`!xg%f z{zdG] %̓;$w7de>CRdmS&$kbg(V7T^÷_v g7hoc0 endstream endobj 3 0 obj 157 endobj 5 0 obj <> stream xm1 @ IzwM!p nZA${COv/@@,蹋 $Nxr qq($=+lĐ"YClQ2uѤdMRŊΚ3`+د`|tcvό6f(ke0 endstream endobj 6 0 obj 156 endobj 8 0 obj <> stream xm1 @ IzwM!p nZA${COv/@@,蹋 $Nxr qq($=+lGbY!EV:hRH&)vƊbqgM0|PK>Cvό6f(ke0 endstream endobj 9 0 obj 156 endobj 11 0 obj <> stream xzmtSו˶l}`ɖֵo ,۲Be  $X%[JlIdSᦐPSd|MBHJ3@3$+8Ӥ}]6/yg& k92vͬsM&5!Z2Cx %7qt:#l3ݎ!ƒO՝W Q#D}n|X֟eF IH(,GHP#CdW{Ga"1z3WOlUx9/".C=0W)J'LY$dmH?Di?"8+*H[\#]cD$?C,IB?gwQhrr#dHL!ey=E29fϐq:ϼ|, ^|d܏|G* 1hȗ[hc,S\ >8>y;Js $pNNO$>y[[>Li٥ߓY=@V2Lux/ 0o03TwwspܵG:;8ws2!R | ),.LtsMWH!Z-,Ê͊1+&Q,KlXSV4!{];z{ovv{۶lt ׵468uk׬MZT:A`oHCݎ:<AI bw7#!I jBAɍc7Is%I &Btyسˏ1 H )F 5XT4ZSNGg;#BG+,B!i[΍sS8PXwvXmRXT풚b4trTy= ڵa1/!ԝ;gg vVjgĎNN/$e^fKp:odF[BAk_E/s=;lp6t~qfDV;tM_|U~- QV뗸 !UU% i8zMFfvs@F/ 9!ʙsԃ"ֶg?+)jNѐ43u7-J>VF 0Y r5& +`PY=CJ> `(h;h90\# %w\ι'jXX+RY. 36g*T.ਬ%9;ٺ:g-qUZ\kg]:lu?<&ق01op@G0C V+g9StdF[sf%MFsV>z$^D&|J zL8l`%yi C:#o0ޝ(iVrC ;F Mjw24؟݌DsYN^1 Fӹ,`9k5x,Y&RHzgí3'‘]sn82 _kzs!rJ(B-#aW݄0>zi4 Ms9r9ǝV M0MPָ Z%=Y-u<9p"<2tY-VDGzaGxt a(_ Dg؈K@q I܂RHE(-GWQ[̀3X{pI ?/JpSEjH9wPgUX T@AAFpuÁb 8X pV~Y*9F髀6F_dqm]`9͗Acc;u/^2x6v;qV46@j;\M딆2SUzÚ*P=O27;~ϝÇW];լbU<[ђҜ,~œ2v*KIqiq4(Set8Wz#@,pI Ј1tNrb|zR%̮&#ĀHȂTʾ';HXdϜ9Ý T~ Toe=/(reEWFc@*-- a*(ceÁT p@aoNùZ_.w]wlf^hVj !8koml\d+l[Cn_B[Е*Kf),R]R|IQ߹DVD"lf0Ae_}3 /q31 ̰ >12ߚU3[(k{C^ b%5df(֢SzWd0t _@m"&_gppok4:e=F[l]F%V`-ͫj-@]Rp;O}}*]ͶO- _yhxhyac_ ݿW<91[PKrK?/3r),)QrH[+%İ+@ϕTm,U\Z*.}zuAlie 7 @8c>xV~k~.˿ELd%9cܢ5&iU`-6 &bfZ宀<_ R%0S JVH%l] T09wM_JiɈի \*SUjPl>8w^X_nnH]W_&V[]іOX&3xr,VpܮBQM5x{N;VxʁNVtv DzCCƆY[^{6 ?b<:Xu͒o\a3(-MZ#z TWX֠;ibY VfUrzk֋+VA0i=y$5]l1讶7v[p}ƴb)Q+& X֚%fxR/S if #; GނGY~]Ɂ?81͒+,ğ)fg݋uNgYb˪ dmq1Y-**J z_n/TZW / 74_j6X-ڰno-7qC ˆrꩫ%!ZU+irv:RU1H7JJqq/Z+~=diϒx%!gOGTS'[qe@I>Qn%ėbڽn戚02@#2$ Vy^>6k;^ H xd"_-빿bkdTi ז32 DP2̑(h*D(V&L&ܿ}H.(V-;/s 둢V&'zqZ)V_:mB_YNwfc}KfD}"5#xgDHx!4J$I"U kZci x ȟ@}#B- 1 ''5!/GʹچhFܮ@%,'SG)[I"(fql)n8MW#-В2a$%PC@^9Uj{%iLd8 }q GY%6툜Q9wcS,0-ognO3<\Y \H(C,aM{,.k` ԏ ęi9JS'{=o},\o-_ay4$8H' #rN}3-27iM&Xe,s٦R܌'~tR}X2f15" OJGn=9sKB, Y/v$[QցI_,g}|Ռk^֣q%YR,cKnjWb^_$ʙn@W{f#3oEcgX襏@hee哗UAK ͗a/%٥KK3KK7||r~fyN|o;mms}g僧Awv=|; 螱=|zۓ]o<ƶ9 Nj סzfγ&؁ӆ>xyP܆z?G(+zu}>g~qBkۓgۼ 6]v/>R wsw{k^ʻ:dv һtC`]dȩ[q:ݰp3fPy8178`W/H^ H5޵GRО9? >vxVHM~)*#pS`93錝]`#> endobj 14 0 obj <> stream x]j0y,o .Cm@j 1.|&P9gHNk:)LWփ\öaD1備[ Z$x胞.|/ru+ HCCRUd< yX @׹v,q?XG(l尩 Êm[,ʼe砭40rϹ9FM9z}?s7kϸANpgz.(۵#aV.%!ժ o F endstream endobj 15 0 obj <> endobj 16 0 obj <> endobj 17 0 obj <> endobj 1 0 obj <> endobj 4 0 obj <> endobj 7 0 obj <> endobj 10 0 obj <> endobj 18 0 obj <> endobj 19 0 obj < /Producer /CreationDate(D:20221203133755+01'00')>> endobj xref 0 20 0000000000 65535 f 0000008488 00000 n 0000000019 00000 n 0000000247 00000 n 0000008613 00000 n 0000000267 00000 n 0000000494 00000 n 0000008738 00000 n 0000000514 00000 n 0000000741 00000 n 0000008863 00000 n 0000000761 00000 n 0000007606 00000 n 0000007628 00000 n 0000007820 00000 n 0000008179 00000 n 0000008400 00000 n 0000008433 00000 n 0000009001 00000 n 0000009099 00000 n trailer < <600627D27A4A6E02BF6BC0FE03F7CBA9> ] /DocChecksum /5A4F44497702D75A7B96DF30B92BC8A1 >> startxref 9274 %%EOF kraft-1.1/reports/pics/000077500000000000000000000000001450127457600151315ustar00rootroot00000000000000kraft-1.1/reports/pics/CMakeLists.txt000066400000000000000000000005021450127457600176660ustar00rootroot00000000000000########### install files ############### install(FILES lurchie.png DESTINATION ${DATA_INSTALL_DIR}/kraft/reports/images) install(FILES postit.png kraft_customer.png DESTINATION ${DATA_INSTALL_DIR}/kraft/reports/images/docdigestdetailview) install(FILES identity.png DESTINATION ${DATA_INSTALL_DIR}/kraft/reports/images) kraft-1.1/reports/pics/identity.png000066400000000000000000000110411450127457600174650ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs^tIME"eIDATx[ p\y}hw%$Kö0D2҄Li!S:f̄$t<BhIII@ cclecY-[kjuN9f%M̶>w 1~0_ ?{h|{ڎesQjO,OϑuF$lb!''z$Rbo w"[(~1JM0%ib$JB$g mƇW]|$=zE0Up )!['^Ň~z:[b&vaAM* bA4(eP ZqM-\#k8(դ0_vRJ:>>qz xV(h,"X|džnÇg[^0nMUq0 u-XrH'w 0H13~J_|JxX b)UQ,L<K Q_ROH!dMڏ 3sgy'=9)[~!2?&3ԈX}j̛T­{VOgQ$ !t=ӆ$RgE^F2Y榙 )#e㡄׭ Rhݺ Ľ\׹CJѱ #~-F[ rcYg3r$۶n~޿}-p~: 0g(5tD2:=Ncg5!}v^QeO^J$ (/WLOx' %b,^4Ԍy6ο:ԃ uIZŪqDטqUA):y$]t.|aX=+}{a7^~[i?ȻTpB0K#f^r^|;_r⭊bA,tw5 JGAE.ahvxqO[b̸*nѺS+S 0ˡw8Y _Iϼ HUUe --QE-g1w08E`qUEG>f4y4Gdr๶O ^(򺚫!@[ۜSNBJEc`zL_1];5`?$O Sng}ϬZ=?8m枿Κ=wAi"JES b3SهsPP?s|)jƯT+Fw 2BUH 4V9(a/0@ab C}֕B᪄D:]Ega}/\0a'=B44PJ3' D}KLUilH)!Q>If:M TwRHsdw-Xk;/1-$rl֭u9PJn`0J,53H/Fˎgx5 -mHgϚ=($(oU!{T+;<>utϥShmmCSKJ!vEUԀIdƽcc[(@gg'hpgh 뼦1Y@F6q R!<*T*dAa$T)t^3+HlLrX~ "jܵ~Ѯ7;R㑅DшSRU\O{('* U%?q9-[=ɲGFrouۡwv7}?`+~gtsc 甀sFS m^84>=60{#ǎV{3{kkҍ :g=!^ n) , -]sut #Z񈉈8ΌlTp+H._r pK/~L ;G. ^~f.oL.O^AQAze;qBd Ѱ" _nC\MP"BC= 5xE*4T{ws 5~$$ z05`U\^Bh.2R袤019*Be4˵@QEWf]p*\c2ܞ R攑kvA*&}BJBI-cZA@V0'y8 Q l0*&{bѹ“R? *-S⫰3 zy WLgn`۲tx;:C_ 7U24(S ۏ ޕma|oC vEquO摈GBHVNN!Y)(Q&{{Y[TT/Fy1jwWxkZΨK6V'"~gHc1Ţ"DX<}{ѓ1ʭ R&MX>wl(s(6Z43~[hUFXi'b"qV*$̩E#O¤S! J#,uLH +|+tKN'! [v'o{ R319Cx$s %UB /%%bBH FBA$vQ  PcSJr ,Y.i3{`شi-~lQn"qgpgq 5IENDB`kraft-1.1/reports/pics/kraft_customer.png000066400000000000000000000114401450127457600206670ustar00rootroot00000000000000PNG  IHDR00WtEXtSoftwareAdobe ImageReadyqe<IDATxZi]Y~wx;;N8iRph46 TЖPAS "AT@-E~T]( ޔiK8x6sG 1f sMpw<ව ꋏc~]` ю8QSuyh=R[=3`;6LY< W3 }<<_4d, ~?e^!]hi;2Fɑ4Lv729/֔,{a<'{;l+dz}:sdǂ0XVV+ô_mdO XӴˤ]-)3U`Q?+eOM^4%@7ip9<ݹGN{_ ĽKjٖ-"K;ô]:!ycFXyGEᑇnŁr o=VTݿ^z= ɛb$ftc?:d7l?sMC?KLDy׆\HBE(v:]ty;?{|6[q YSs]سK.Y• j6i92ꦇ=b lu+*dLF-TDwA:9TVѢ#ׁ{M bdD8_ysWuA\^lm9T6T6^=҉/:4OV{Ư i Aԏ&2@u XFͶD9 sþad6q~zuJIE# dFرs|R Kg:_AU& l07%Kz}|\]vhP0 oFʏ"td_;KK l7>V*-,5 窛ݡ8Jwt ˎ򐉁9Cm:)^zfBρ/kvM`6,ǁC5<ze(+ aY$2ܨ t]3:EL2K}epw+z>1NAo9t V]?ҷ/4;v abba26p@ NEq8y-7XD1Z (3AR ڍv>|^$F$6L]3{ʥ܁ geF th"y!f*X}w '=YXvqۑ]8zx'cn`!ɖn (-~$>U7K*hWMJmt5 e rb)9X 'jBR*#v,^qxiEJؐfK8VEx,J l.r Ik$mIB֙UmCϹkdߊ$8 y4  :B ZBu ( NT7XW]U 0`|8b0 U3f4 J[v|C{K)0(ӑ׽M1q1o,/1384sIKx)Y&>9<p| ftזt |Hō(1.,n/ [~tjT^^ax8԰uOWuF'عmxj~gq2;i:mvhA&>c<с\.3e0dK5 WdND,k}F?YF[N%CFet#)5|?jy5U 3K8 4:8h1CN_Bg=U<9d{x<5F,t{L6sbe"u`3ņsnFWc"vSp9#) n–ϠRbtg|Wkx1ߦ,a{"e%ք\L=V*f9Q9hӡ@#e gbqE|6-ߏ*f)|I+'!f$Rwގѹ#_{fm]3BkVkr54dRgFulx!x<[^_|_Bg #Mv-d9 RpJ4 =q\=C]{|-1G cR0Xkx2W~X Y\xMЉ<(a,[}oib03zTC”c2"wrɏ@E+D(g#2?s;8kP퀑v8#C>!Cٗ x A~/$9fh}YKae*2c *i! ~< \3~K}yTIĖ7?73ͫ/)l qLOa3į+QŽq%(Ρ,Xܨh$Xo'oY:y`M7+w,Nݍ0nB7Iﻟ`xI5'$^{9ŻIB/TqH&MsIL|s0 34ʵDqWQaYCXrz_1>gkfQL$0_G'7XFpMXWq.t}{OlYC1ìW;ǵlN89JaR* &GʸkrÅTrTƔSrHt,,.+Qcj$*a/=S.h=p>8)n,CF ohቸĕ_۞$ ö09>ZRer$\2+MsjVP6Ռ"QGQB |ȽX;x/^\_?}_C @/lp\/:fH9Rh4=>Dof⻭\QJ>5YYp]qF1iI Ѧ9 LyeҒ I$~Ze<<6!$NHH7T$F"L% <`&'$S7r-5ic;K"QP+xK[mjI$,xRݓj2x D}A&b]b qh<hG A3DyME?z],bHL !wv$-(Lx=Q-aj֦:{Gл6>RCD9q3fRž4yD Wg{&۝q$5~7WE^V7HG_Qճ-beOo,t,JZKk-it=xtSuA4g c {O_Z+FD;ݒ+YMo]][mf;.SE|@E[2HhEH"wVd$ GIK1իu]{ĺT&x#Qa-U/peYyB^ȴ;pzSW>0D`;@0cYdSR#&ힰMJ->SoE| 0ۉ%mϏ~/G|2S7L-+EO32ENm2$-HcV%V4A8J]Cz?s?|pZ3:arxI/$p#K P·3 F8`&-!eDUE%tk><}/3o` V7nIENDB`kraft-1.1/reports/pics/lurchie.png000066400000000000000000000533771450127457600173110ustar00rootroot00000000000000PNG  IHDRZbKGD pHYs  tIME  1$FtEXtCommentCreated with The GIMPd%n IDATxwT?Sԝ3ۗ, (bc%%`K$}_[$FE~ĈѨ(T:R3Svꙙ9K3}]s̩﹟!9I.$$$$䀜䀜䀜䀜ss菴RPPpԓ|ᇜ~߉꫑e ,ȡdje$ >3{9u۴i830L;3 XD"A}}=q'h'{۷x<`b;b#L&24 N3sNr@INr@INr@I)F`ɒ%\}՜r)X,t:L0'|H$u޽{̔)S9r$ݻwjy߿?iƋ/H:>}k?Պhd̝;Y;vp饗xjqeyf|#:{oL&$Iw̘1mv3uTFM=Z!7o#Fd2a63f ;o_nW\q%%%t:+زeK}7nM7Ĵi3f ={$//O=/z ƍ2Y*++ ,bK.v]?s-O?8WVV&M6~"u@TWWUZZ*ʲ_q"NwT*%zuSO=U\~bРA3f{>ݴi%%%?>|B O?0 BՊkV̟?_̛7OL2EfիW_oQL:5k\f͚bĉB@\~BNo~^z?OW_zjB׋_|1똹sf]x>px@O`ObΜ9B V{;yda0ľ}:$/)gϞ-joOź~m&Y`z^_B @s= v*^oֶ{NM+WT㢹YرCXVګVF`t',ѥKN7663fLה>ϔ)S (1mڴN1}b6Eiii?N3<ۧ^opbQ)I76nguVzؿ}gw:Õ @1r)>ߟvg@Lq%%%nO5sxg;ݧS^^-[@s="t{}f}_B=M:3qDu_[gB,]TTϘ":NN=co~ Q[[e͞=[444@^vX|y6|ņ :w2vUUUJ{ /Pݶw^;v&&MR[V1~xqw tzL :ՈDB|bժUYۿq>f? ΀I$ÇW}x/ϒ|@?~{Y/.1f~jcy iB<TE_QQqge_ :T,[,$ѳgϯqK$L&};^c{GO?| G.?]2i$6mԩSYh>X%LƯׯ۷oGe„ X,6lsᣏ>T*u\uV=ش'Cuڕ;vs-Æ 9oL#կB͛;,< .T{F4֭[;e 7ܐeu2%6QF߽9|Xg?Z'v2$IF~…\saF|8{ݺu; ˖-SP@BuL0TnA#SQYu]'h:PQ/tYNeĉ(?5О&6mz㳨*/f̘!裏~HVUYZ*ʢ_:lG?Qy=oȑHD̞=[<4ԤIc=&?ٳg{LL>] 0e?ϸqu]'LK.gyfVcر_uuubҥ*19s戚 B1gu$/_.0s=WgĈ+C)",GH̚5K,\P,\PL>] 1bƵ5Dyyݻ$IꫯV3nJ@΀o߾+FҸd~8t"~.L/,&)Ht^xq鵾V 755r_|5"??_Y~M7ݤTWWc N'<ˏx;C!wq֬Y =sbȑd2 ^/ $̙#tփ|?k4V#A zׯ5آE\ <h4jcNJ_~ôUǭfԾpB1x`bƍ .<3JĂ ɓT&Ə/^yh 8,~TUUg4Μ$}nO8/&.B P`f:엑t:M2Dբ)U}41J3%g#"%T*LJ*dHL a40GmF/ضmW]u Gys=CYYY-ٻw/wz{o`0,'$v.xӷݻUе;=O;ߝuxeڵvi;E)䣀7T*[vj֮[GϲH9%\0H6)jc6FSh)t~ǜ>wٌ1}*U` !HR4{Xr)䎒Uz VN 䃕+X8o;o󪠕LD+$|^!Ҝ>MK (RCLa1L9mX, ߏ5uX8X| hhDD aЂBIG"h)4rM:{xV:6KBvI:$R6=h4hi 1L˜1DUP_4mM 8X|EE_J9׬e |jvVA v )mۆΞ8{~[zx}^f?$s_z YN&4EʦGqaEӾGSOEqTA<gMk,~m|>/IhBIk}6v{'q,T˖Ss7r33 | 9[_UWܟ¶U{:pcXŵcm>9jC_Xb$:ݱjs!yߩX쉓#vOBWpۭF phĺ=YK.d^nbE``ϝwߍh"1vpbY=~y4D[+ eXXos^fse|!6P٧_8sw}}ƿoğའk.؏6ƕW_SV3Ͼ,g,$RiǟE+ټn=;gW/]Bc_#w-?R.(%QbF.2 %1p?'R|j06|SN}lƴ/LIDhA =4 oq߃R4^cI3q=|ޔ֮QMeORYײF5z`³$D E]eu v}a۷u"FBF س'ﯪ=>g!ڂB!5Qǀ6BN!rO*Lʥ%J\ҐُzDtZn& =I[ h+3[xO0 s@>exGN-#mQsu)NxPZ!?V=yOW$@ Zh#u!eй\EjN>/SFðÙuf3V}e|!V~*K`p߽%^jҮhc) ֐3qǝQE$ xIZa?`h(Jwx EjI3|r D`׊Fє2pfl4c T%N %ߎo]5)˫"3m,or JT3[7nwg %!K=~fN(ZAl )nycTAKަ %BÕH ^w9ԸPߜPs"vۃ:&" U^58M̌1rJh) uJ[Ң#mҶ FVv@RbZyʫQؙulz/JTJqۭټiSN#HR;dNjr/1cqE4s]s){jzpCѾtw@T&Y#U`J`C}LI\rpRNh]Ƈ6\ 6ģd'q.)p1M̛2iIExâ~rUƿֽ{~/6^\Vn>ݑ"5ujkf Zw(ZHT]$E޶I(J2myo]8eO+8 0փ`G^=/?Ӂ@J6+y~v;ڕx/(Ÿ?BZҲ+T[|ͧAC_JgAZx= Kəphº=)3S0=,s_x^MI5hcMyi>H Z͓VW֭~RN J%80rJXB$*Cj+c^Ciя>vm%ߣ!F`\vc=oBHS`֪ZVb%pҿf\y͏;h?~yr'= Ι^XyWE{8e5RÕKl5nbV0`݊`MZ4ohtim"yO+>v;ĺX*S"ǎ::tyZwdi$y2 L(BO`TݭI: M:dD!a ѵ:b?LjnFȤ:ϿI@bn.b-_[6p~.~o_oPY;Nծ=8t$)^ (#)6[8yS"0ʍcD9RbgىwJ  P58/rJ$~%>4U$rI=ߌn宻gu>۶kL79՜ڵzRe6r2wgmҮ$Ձi_]4MH_;ff~EB5U P)RUOM$]jp(T+.VZH ĺYI%,;Chci~Ӿ8Isep;?WW^~w~>[kja2(҅R6SMm>iKRZa]O2߈yoc$^fT&NH_;@F-)}(IxS.(SZ Z MhI u1Z)&<ȉ/'4iSIC`yh4=V|JxԧZi m7^տL4g!Y]N? $"\3'u܎5J8e|!7N^[nLBV DO&Z&22-Vm] AKh;uHM1~2#¼+vIED10m!VPEYX7V@ŕ}kź(ǴIuH;]&푇or9KZ +mGyG5N/f݃PQ)5x,o:sRs7nR6=ee;MݷnIDR6#qMU*I6UA5BgGI))4c=6SyR2dcܒ]!5h>p?yZp~H'*][ osU} eg…N+'0փ&k}mhX#Rii݊{֯GVc$ΆkM'^Q]!aΙ<3aX<3~ES&ynbBԦt8W4&|cZBI[[͇^(p?;vh<{eZO$4ds3 E"#ԗ@ѐtе&I;u7'p~Hт}mh;ڛztI \+L?x^xŌ9tlZq$-:?s@W祵tv{{;8(eἼ}1od^"R"kx cC} `؂S#|ߡjH-2JΩC"TFfS a5z IDAT1bJʬ^_ݝOShM-rbc\wXJd4܇$p-k$ejn.[ |# 瑴s`Vx-e;JPc2Dt qXEH# Z Bӟ~!."vA8kרBIZ:1CH,B4[L=T0U1*=)&1>vlZn "mlk%QKt(94ĥ`2/6Z"iN-Cj~C²+ȾC8}ɓy70D sagrA ȋ_bh,'H~zSm\s|$(;mg"f֭~(6pJҦw}M: C]cm c}KFߜjƇqoXu$J7!KUۆ ʺUqh*+^j"^f&Q`$QbVhU^[Ļ[I.:HhJAJbӊcerS3G"i%0.e+m"nKpޅgz̿Æ13y qbW2ᬉ'V>ix[6租"S N߈%8nNg5_[AGr *)zc$݊&)CC La o}kxF dX4S  *'B!V: 4$,XĻX0414Fy8iT0@ANRσDOtp2r0$ yb1nVZ1b+{ʂhP%E?Ya#FvnFCAaBh([pWsퟋ,' q)Z:ѣ;cE&e@l+Z>0ƣ +- qahT8]TԞu{@RB̌ugP1[{}=~xɔ#?hA4 RiC,}kuH$់/5(2a٩^ye}}%[T(6#5({sC$4 uxnsVi0c *y c<!Ri#Kڛza )6~W&KZ5#$xެXw^HO[QY/J%oSE1vN^y ?ޕX xiWqS@JcWbV +P4oi}KEO26`rJ9Awj|2ژֶ#\i7Π% #) TDe ok^ +X Q&~kа */AvnG+v]_7dgUM\cwwt:~>v.XubƻXWcOOt*)DhDwv_De2ӸgQj$ͪgӚrhci}80W rcݪ# I:5>BmEiBI?ka؂ZQ̤F~گC|Ht}/;XuaxFt$ +A6mnr9Jv:"yI:ڷw/>PpiN{MjVLecǼ38glYp~e}Kxw+MrfK4oNd1h4 -&x8HU݉jEM/6a"iK㴲IދwJ !574O/cƎ=2y6C]X7[zM 9 7QWsǃ^s_{9nlu80 *SvRN֡m!e{ZGUjKFCڨp)_FW7yGMXل==oAJkW5b66/3YTC oV^FeRvŔ LG_ֈmcX5/38x iG aF I1mKM], Ox 3>TF?h.wY1r] 06Ui>.Ac>Z:el[Їdm 4uZ&abR#uJCB$唈TڱSZU\`RmЈ|a5ýXYmcyR !H: /6cǺOD G{8@[8ŻXr3B\n@+h I n yU k^Č-1r% .y1k+H:$a݊6D*$4"RS aЪ= S^S5pF_&oIDz۰ ;Du@Y#oC JTAj t4I: xcbR5CEr"v&i>dR _Ϸ0㦟2l`>YV6.(fAlIwM:$gY짟"K^/@v:Ƣ6Fó2˻Cѥ{wv?ΣjnJu6 n%ցN{Zȇm6B.0aGF-Vz\g'4D-UyaMq/ýX XۺI[tSVE㶙0)gVf_&^bRAbU"ݭ9@ѼJ3y\?pu:ހd@ZRAk(D~~~# TuZ.R6m_W3y w0 *Uy*핧:tx >%p2I8C.4oI(v(2aݮDۿ%-:"m)|5M~Nn$eӣ % YTj:%lܲǨfEH:#ĻXõ`XC7`JiI 6hU ̦i}PeBRR,4^'Ϯj̊-2"부9wZ9N Mq#QعyZrnFV(i8?hT/S>[YOߜ@.2OI˺!$ڢDՀF0(]39eӀqoX˝y9{$Ǐ,<X85̱ZD[0mѫ:q~PrRPZź#>UPوw$ۀmh/6r$cW-BIjIk^mTCRCLu-p~BBf?8D[ ;&VUJiײ&%5' D+ ZV~18#&YuP3`kG>^rStdP_Ϧv]!Cj2˺a&N]^7A#f t:إ0mZUjQ6h7IAm|hPs3^֭~ui Oi"0ڍ\dR uöwROYT6u-ؗ_}\TPR_C# X$EG>nq#zP2܌1JWhjrN{GS7K]P&Jm$mrE>|vv\+1WFevrvW2Kԩ 5rZ5Kڤt^1U,yb#$x{J:}; (֭~L(6#)VC_vnE7 5'FSӕ 8"kUHژ޶[ض)M^..ǵ1Ιi&z#dP^Wqh$\iCIei~tfx`[߂u{f♿v6R.0푗(@T`.gg钷:r2Is!EIST>mR{:>j"P|]M~$C_E2A47PWsXJJK XViWRtlK-h4ȅ&l[-2^yJ -E&cIE*R4?GI^XJzgg믪q1 #5UdBI@D=ŴcOaEz==VϯGRTT@UH }@d9z\EmSuANSScS}qip{0HfzOY @De8^cПauĺZh>DKM*'I1W)]}q7wuzȝw͌ne!\+U@BI/:.rhT463#q$q}ՊXlR_.'"'{1W%-_b0EU$Bq9!۶mPW7+{"K0훊E|^Bj We^jz_8v.JeeiEkB2:M# >/s_xEG"Su+H`Xr@:G]$Κ՟b'gc_mBܹ|^u·$OhrEE9\ۃY&~z5EGϡKe1;[@0jp?]!1.2O lT@j5̸.?KIDATXSGRYE)I' !xϳG'͸'68ɤgϞ=c\㏜ F{!zmgPWr-op'.N: !8m^tmW.&^z6mpBoe)8.Zw_DmcmoNIiiߤd<~ n.d9o @ oɞ/ i2P)XcaO 2@*}$,1|V!6oчm!\<0|^IJ#YO ZVE~x9cN?ۆ̻BFp^[۔'N@vOBaVQnf6nӟBYy9'%&NƛL{&ǟjbH8JJ) lk{hZ?mE !sKD+Uʌ8L\T\#e֓6)/R\smmپÐ6b1S+Zw^ P$-k9x͘j8Vy{b|>/ϸo3ICi_~mN'*W?***Nj |'jy睜=qu>D+xPs7\o g}@P]iTSW~BF@@d*QVq©ũVZVZ.mjֶW+ZjUB TpVrϾs} ;Y3ܫ<&ٕ>ޜs6> _oFސR|9qgX+yb"D\\.GsM >л !=^IF9ƌ{/_QJKf{{|m;BvKPqe4pҥͰT.{kuޚ:!wBXmMdpJ󇽐v\즛Ph1cTu33[{-,zۣ Sh4/fM_h}ᜢRė_C,7 %K`ڹaF3;*Oer,W=O)~?_xKꊒDz^j.JfY# HO)?7o DºlD"neyP2=*}v[fYh%|̖5@E 'fL( ١bH21|H|͑&M |}}'  4e, A+2>ðe4TXas? (UJ|j&M|BZC7x:xx'ڼ1'l6IdQzRgglf͎S!Pn;JE>[1 O-ؗ$W2qPӧL@·[i/F雾 B|.Z}_2ލ]bCb7Jq(vh¯IR)qw*8QAzJ >_C`ER?~ 5-|v&|Yh4ph27|s08pQ1]Y\BQ 7nCai"@EE*\Ƽsޫ._sI=f6zX`т ~̩Ψ>qJ:q nS^JRF K+ƈ#F5`/#GO|TWWc˖؞*dyp+%<4p>dRʻ7NWGͽUZ"h58{￷Uv( odFV 1 .h46~ݏwĵ|NPB&_QsI 11y mnDrssбc'؍<|=yq7)ԁ. W*a#d27!!c0xh0[ΎÐDQR?[ z#)ɞ 8/QIxϓљx.: {w! DRA\ΆJdX\`\pɒf3K'`@z~<.F x\h;K[qvė*|ݺwG=л7|<qkr40sBZhυL b.+Cu)4V{ϗDx5o28ˍUwuB 3z?+٢KJJ !uqkZm-~?r[7YYжZ.Am{GUp^` zT!QjjV aZ.O w2@.d/`1Ȏ)S6@tJۯ'zzH(b-`M&*~×^h.Ny@|8z@Q J kj@Vu>PskYy'2 nj,7o>3cZ~5yڛ4-1[k^2f F"m`ȏ[ґ|Μ=BTJF)zW @zK ƿՁԁ6 3Agk|]vmzX,F||`z =ΰ)22 \C.בٱcEFFRhh(#s_۷of-b @!!!ԡC@u߰a 3gO;w1cH$tF]QQˋc֬Yd2sSSS),,BBB5L&-_PǎiƍO?ѼyΎx<}w͎-TWW7JdkiӦZ-ݹs\BbIII!֜nݺ|nZh4>}D~D7oӗ@ ۷o3myyyO ,YȞ?޵FϞ=~6oXJJJ=z<֜{=WAѣG3n64h49:`ܹ礤$#w^$3dȐ[W=CH$5 JKK)))ҥKx6Oe˖푉+h!!!lϽdãPM>7O6mv?=-~: ??I si"t:={|Vhj `$7yڨa4o֤+KgǏ23P(tNb_j 52^&ATBVC.PA6 V5ZvfS)((qȑF媫'~P^^&&&2!,AdddlȖ ^ "B\\C~Axw˗/odYPn̙O?Q#G`֬Y͊/m۶G5*wQdd>iIQEE͟?ݩUV̅ #&+uWwޥ Zn#c4??&kg} k7U{c޽{I"o555O_|EDDYb9r$ѦM(>>(::uVoز fAff&I$Ņr9 H$R* sδtRtT\\LJHHB*--%|hܸquC~~~ hlD***"Z\HDǎtTZZJNbdݻQ-_(/z6mh4uTҥ cRMM KEYYYq ˫wׯSxx8ye2M6rrr-X^ӧOcǎ5_aa5/Bcǎ%777p8$im6FS>EѢE(Z\Ҡf޵kL&cb@iǎM<Xxd,Y`̂Kd,X"`̂K&L@UU{#X"ظr O@!-- l͛7DGGCoUbAmgo'm JeeтCұcǘ k׮}7Rtt4JY\\l%r3ZG;wjDD{PQ^(77u=,[ aaa1cV\3rssѿp8_Æ ֮] G̞=qqq{.͛ŋcoKkgO^W6٦h'OAAAfMPHtiZbE999LdLL L&pq8R*4g裏ƍ@f͢d""hԨQMF?*bd<-??ʕ+̙CiеkW9sPjjj@ubsrrH*2M&]t\\\D #2N>>>BqqqԶm& `%##kZ^Ĕ)S(k1w.kZf /\xjkky\>}PXX;wCm8\nY GTTRM9$$6mddBLL gVB&APd2!!! .l!,,PFn ر#Y&NHWf[PTT/"" hٲe"##)//ƎKr DB>|84i$JOOo>&Ov[j 2e ͟?iϞ=9j#"RT4}tI&Jֳ`M ,X"` ,X"` ,XDf ,X<#?:bdIENDB`kraft-1.1/reports/pics/postit.png000066400000000000000000001217631450127457600171730ustar00rootroot00000000000000PNG  IHDR/f?sRGBbKGDC pHYs  tIME 9iTXtCommentCreated with GIMPd.e IDATx̽[k~U+UmmEK$`"`Po x^;/ x€7QB!\*BP/$[tөꪽy;~?ךk4ijac<9TPUW@U=?wիFڟU".F.?KKKUo zqPHAo C 0IPM}@ϵ>I]~-5#|υxS_5_APw;|G"3R\%jWaD (@#>?>g6}m ڧ)B?;ECH:|χ=O?߱U㧺3J1S}GN C5CMO=8oxՋKun ׵z)I?ҳ:_/~U8,\Sy=?[kLx9lk(E|ޕHZwk?ߴ he#^BÓ{5͟LoQ{ͮ`L @ &O'SZ1,@'@9w$]CP3kVIҟp#[ZťҬ @^<=_\`@^&wR^^ji+ɺKsѫ36^|0=^wx$p'=~w._?2H*$u]9 =ɋa(~-]恂~BR4?+ Tw=t}:A4ta0"P^UW]#xў\Ao xB.6Is=SZבjV iΆ9gpT碽 (X "NX+"Rc% cWzqo'h+( K,Nqvi+Hϵjd/ڡD􂼃T&TﵝӾ^5PR&H(P|o_>$ /Q;oG{_a pͨ:_u fW6 ϲuQB ɡba3.I0Nj-lfhtew/0I|FQ=L-4Lva`( /Ң`KӋgrLXkχt w`zLgX`!;q٥3+Ʈ#^ _Lwsm@`" a0]pWtߓA6ZP~<=<СS+UֱJ=htlfAˌN۔i HTg{mDU7;B ȩ{'ݣbA{;T{;}y+P?OF]TI=oO9{_<5OFY7[dU{]|vD|1O *W25PDZCPGNN Щh37Pk`޶;6DGE#J/eSO] yWP}X!mῈ6y^ٰ^Ǒ Prǹj}aVfP'᝵:9gN CvLi `޵V )N [sIPG5N`?.CEŤPMMps?@ĄfA$8m _8vVQp;{lIj.g( H9q*:l6qd "$>h˧xKO Hexܲ`s4rI %c|X TuI@U;PdLN_'2gTImOnL9q=Xt@jFԀ;G ;w+&`ߝGC'Fk5}e?/0[oB}&v #M?5ſ_!M`j$(F7? ~ǁ}- ŏٺ6"#}u*=Z-kc ׿3/n}s F EBK^>)SĹW9C^UୡFDW9 ڟء eZ]8VE n-81{Z~D;5q ׸}};eq|UB51,mQpzs Yw.ͯǏH}5/ \e63dؙ*Xf%7Z.m+`46FcvဍO@`:l`a3A'hOfU:xY~؇)8f9rDUjLɒXCL CtT,! hŎz08hJwc^״1D " I!W%%s*1d6H$1@:8 `  .P.Dlggg_(1ϴwJ0͟' fq,8Ƽ~]j6dlbϘ8vt(Pt%^5w-N_ɾ\و٦7Ta#KWJpCYû_bQ+Dd' k{-wOjKqsF5Ru.k]8> Lf?(ZD bq L ʂOF<#17m U` ^Ȃ4\l, SjEw`M̊R~F/U&P}` z_\'NΉ]v9"IDoX+m`T4tڠ`^0ӱ ~cI!dOR76T=9#& oɢ(a%bxSGo](RE!ٺ))cԺ^)l׍y4,!Y E7=a]#c?i|9?{k䍯c~305aJ,#O{!\FNe(* `ݠٟ%$|`h2Tf :A!Y15lkQ Pt>dz Ĵ " I/i Df3(:E9FJ!^L:KrΉ9ϘsdNc)-P]_zJ8pu@kʈ% dkI<- nGHNM :i'S ]hDlRI*jh E)ᇟտ}u-pz ]ϗ?IO<~i|Sg?x^mD~*~ccPT;Tx+AH HyGA~ J"g83蛢20.{î/bZpuCNjhumAftئ/}F>'쭷S"wcγqߍE D;j5(a*X N5Vsx dE7r^PPChL2rm_/IrmZ Z/Nk8fa¤J"b9%jd`cزY76`<>e~ W )>xɷ㯃V)/_w[-PbH1 Ħ(^Llj+OԷFf":As )k$?' O ޟM?@\n},_k%ܟϵ;WL *Ftޮm2''_J%Wv_2}pܪ 6^L!t+~TLkxDI)HZ Z8'pNZPpH"ې odP,N];qVmX-h7sǛN ٺ}ǁ _nZ2u+@&^&>z4 PLGrY( \);SP:m`gA}e(+\,RAPP,&h(rM,bmHg ?#1Wwή~Ɗ'~!pfZ9w}e ]vT"3b2"3Uw#G,%\bl;ZGд/𕕜.[#XDap8%Ic*DCƯyp܊7='!7S-} %8y3~om k`u?3G??^r(jf1_fe |xfǶ1fss ؕJ0ilVDsD8c l}+[,&:/E:cblw _cGmۖ$]t?H_+;C3_dhw:Ƚ Ve[f」-5I]ݺiM['n(KS!piP^^)r`xbrL!:[ HDJ zf{qH L cR(7BN7xS(XȋO4cEv]- ^ç^?xo~TWm!;0v m\ <V4VPԋT|['N l.ٲm;Cdk 0κ: $ԓ+lC)  02|„Tݯ7J[q2S^b;G1H㟮-iM$>5k:EGju$/!EVTǃWsm\H0$ ͸`w6̔< ;#J 6xQLҴ"p\vKuG2L;/R<趺:ެs4R$Yu`4 ~Lrj 'v /0:~$eIq1={W/θ۷xP0ϧt/#Dg|0^k/#| ^]}g'ܜ0( r Nb63?-M.m5B o6ObiO)c#<xtHswASZ"" "n O?“nNضf2FYM[1y~` z7f# Éeϩ 6n@v IDATpx1ߠ4]H;2V|<jna]V>[Snۼ1Jj%^`q_K>zD;`G`Ǫ`(qQ+DiJ+fNіs` @ZPGblaZ8]'l/qƪ6CcCֳ:ܐ9Y0N`tt!+n q6V!鄧O(pssGgy}7=@x 't(̔(IC`5+rsd aT@t $pmTXzkJA ݯ 6]mʉç³޼ٱ8/m'=zOn[<}r>zǏo no7nnp6cNKR{h+BK6r.>gdHk[weKDoseӽ3t5rG ?)(%RjfF"}Pr٢luYW^wBҶJ/t̍!yؤBW[n&u Og.Mo63l;4rujk̤ eX\!Q NXiՂwd7*Fz: <|s{'7k+</_g{Уoiͣ O'On-<9#>N÷+18=HB!|`JDEw\Vdis$bQjVl(%٧+@J  Q:~xIs1%4kܓ"pC\aaf6mQ!sfRC#n n}zƍeY_ݞ2OQYK:!Дl(^0=3}bN6bO><=ѭa٪񆛛 7N c`ia^Vߛ.|R5E=jB6mteJ4SsBl(@lYl',6 0ВdY*f9) C9JYWAS˜IZk(?ut/Yea0 軆qo"8RC;1C*-m"ch/.3(jA(l=5Ls4-k2 ˆJl79?L"%*ڞΥ-쵎6oj/dlct"f1p6nxwOvwg}ƤA86ܞN8N8n8nm03͋ċ8(ׯ9Q#F$C\G!!gR` yccQjǘ7Ž^~,)QN_^")ǻq'Q1p̱^oC)0|^hy~/h0) 5ʺRƾ!u;gSZǃV4 H@^ĉdx߷kjJH'] J+sBq3QPkQעUtvXZ]Bԩ<ƁYyױM($aF-7Ցvo\/=O%-nӎ-o6Pژ䠑3ѱNiSh*eшwrG&@LȌWj`"UĶeXp sVNX]r@c-ͽ-MNDȸA58֚k9/֧]Ӏg49msRn$=z^ S2?03cU*aRZTQ I3.SHn[ X,H2S:.uhb4Դ$/K/2i89nh_Qc{ڨT+nnD0▗"DQ,*m6{D߀Nt"Pku$j[Mr/iA٥,mF ;:WFO /u+v2\3Y(О|($u&C^b׭(2.^rlhuҋ $D8 |xAcIuW߶(L1%;*UqY{~D\@Lg]g=KeN^&Dݡ(\ [ohnr.ڗh7a VC[∜8~P3MqVb(A4=xiFsP)QI~_F4qyY^ْ;9t8x88/'ߦOpcJSgS3O]dԈh6p;dDU`YS(5B}YgȝYMM /+&AJ'dy|~oZhg-Ӭ_$pJə7Wt+|h*a[˪FKOc7Ed&}~s:M2= ^Ogrm8C !&r&nlȻ:3vfi~WSi4͐3?̩g2@ -Drzp^ w!`)`nV(L6ᖈrR86h#41_pxQc!r mOԚSWb%nLn` BE+M*xS@ёtV0Jem yE*NK!ʋSsY6>h+ͫ0"AH25:|Ѿ{^EEG3+9MwN@ q%9nsb)DNT*J( z0ŚO-= S _y4]սaTx `m[F.XaT ٫`UL\0,MгD JB}-aFUv٠bs.W~bRY]Ai Mg+gZ:| b6+aIۏ4aX$B. xmŖԔ mTZW.xP NLXXIe;y"8= կRE5&},7yZ`!Ip% ́)m4*m%xj#Iqsa }&3 t-:[ϴc4ޥPےd5k70\xu>T2fnA/^dD ǵ]+(#%k@7>p.IbӒdR}?mQB[R5+:9<=w9SY FvG1mW^KRvtӢjwfY%H^#R[N<\rH7OI0tw׮qpD XHy-x,Wb'N}'^:Vp8xx+L`&Z&F0Dq&WAk/#ܥ99N=0n5}psmtw8^6G0EG{k<ѥOxp$}!',e("vܥ% _`P4%ie WD1(5BDыYhTx.?<.7 צS{ɸG]T?kq̆#ڐ` 3'򘭲-'gӪ/" 86^fXI@9,#S Sދbqpu6|7 n7.hSj uIB+PBbA8٬М(I>,$ =m7X2-SE MJWWڀoZb&RLR@o\)m hM;fgUkeDx4LK ke.Ѧhyж+lT#b~`486PƠgaR)3m`&5ceK2zxrLqqt+-o)Fb64kH w.ad*%@,3#7JNBL 9 1yV-}_Y+SbTn_ETN4 $4R"5cv56HZٳYNuz _rXۜ 6o廿Kvn.L(Ki$XqMШQe4,Eӈ"G&]9LuGCۧi mS\שk5'ZmLatY14?^wZBm %1#+7 *? s$"!)'[3 A0#Otbt3U/+Ԇ/S]5}I$S/r]Mܞ7tZ \(QxudD*^gçZcEyQ!75M`蚎vƄ]&ާ`{JgjHZ?9k1\3l$eNRAI}iKۼWbe[e4TbTl#l(:+-ʤ"r0yUd%$W8!)| v!~p qiat(u-p#ğ):V=AniÊ0͓}nB\ToyuF&i \x-Bݛy#XRaauHm[Sgxv:b*4GʺeBo֢aQ^}bSXvϩGJYxvzjXp f6r!F(dCKlhTs Ni*Y`'Lar^Lv!(+"ʦ1hJڰ5P #?;)%uHSm@Ճ_ʽ!j.@(紨IfFb ,%nb2U@bռ<#1m5BZ+IԋteKs}ےj-% ے]F^.ޠWE]Bdjs4v-f Z]ї!!VO顪\]]0qwQ+z&D` GY:1鄩'}-Cvbopy)7 6lGn: 2#gZ: FX;لlZ"ъӀMrbA*KJf$e(U_k@dCb+ʼn0:h-C["|[4Ee +Õsp\#F.~ pwg,F=W:H3@͂Qjlx3Wĝ ]A8BimG0yFgK#fYDA A5G4.FFO)TIpgo:mvwzBT AD \UjcZ2W(f](CHǯ:Ry[isVk< S8]Zp3]Az`u.rmt";@kN2?(Azurh  +V`-^t RTW)E0i{y%7J@8՚C/\O0^xP\m[r:6'e2Ӱe%}\cĠu,Vz u1Ճg7%)AkLv0t7*$J6cF[xv'`+3Zwg#Jqv_vwAO)$~_g%lBZPRc+=Ƕpv*3ʼn{LkZȑ NKlum$Yz Z,HdETlá=ٳ,KJDK˪*`yܠ 8jo#l(mUj!֖Ttm^ psl6+YY< KQ00#pwtXci#K!>Pn:-PD,!֪̊uKmz n;k1QZ+woKph$msYՆʇ`d6)qU{k$uߍTpn8|UNmǼN`.: -\b֒z w^t= x/v`*;*t)_$"ֽ3-U0h"X]/[y4V@,[DșuiloO_C:ߪ{}GeN>3zm{K.a{BN΄Ǯ>tn ^cf,FkwۍFlZH=MPiN4fV&E" 6gdsqIJ"\f!.}UyX+3Cà+ՇѺ=֦V9 t F˓i]`5䐵 FU{jrjޖWudU'5*r&3ft2EZO%ƈ*&߳.ܺ ;wf $ڥ̱BH>8āV%/Xͦ:2ֶ*J|  T*SW6 Irt% I4K0M/Yi4 sf+Lɘ9/I/uK1`yTgk( %0=b>+8y5{w__f\ճVs~L˩LoXhCHNj D$k{<7kHH(M}+bR\^ 0DixR-2v0]A3H`L'>>2kq9DloM}$@ŸO10a S-< aCz"B[SgɁ[3Zꓫ `7bD QMXsCH#lzɴՠ =z+?s3 [!wBK)ɂ|q5b!((Y-Z%L#?5"S8ҟVVvzjmQ]XԼX(5k]1Z,'qRDt0iEf0ݼgC)ڹ#~a! kEHܰVy^S&Fsvn*Y"Wf 'N3lm3`FjSjosP%R] l +SSiC'P8-mCmo}RF/;k\?qi49- QwM:Y^PW)N8]GMÞk|a9JN )JGTt2jܧgA0| >AGhFOy(=i(s ?i4X֑]˞E[:IJcgصGG}*$=dpY:)IbEےv~;668TH1ӣ:+ _ej;JJ\s;v@[_{y$}1GtJeBW5g+]o a\պ4S`Q _/pk ^WP*-\̻eճHY,VNJl=^pb`d1 V"Zb;N e*]t m6cQXطh 5ϫj01=xEKTMOI( q|Jh:ծ?O%HWԢ MQ&9ኂ\MS3z@/_td‰ UPsOWz|u?I=\%ݏJ0mm M5PiE)2]wX5Q5zxK/a$r5|T@Xp'mnD'cֺ!N a[RT :YYdgfς_nUZ`yFݯe$CBX4ذq?Ysf4[̊0th4NTM ߨ~M~#lI #q Y`jqFl@#sBը5_Gb)j-Rg gլA J3ks<5%Es фQ)ۋ26dAT#"\ - ٌ{50|;Ch+F˨QM 1J'9jg^Wz+s4 |"2Pđ!S9\՚xzYjpc8i"ލ8s,銽[u [AuZv}%k?Rrx L/Тa,"|9٬ڮHczδ3GK=w98`/z$t RnKǰ|;^iq1?N5alA:+vncFR|zDƍft5 (EP\s4niX 36S=<7ɘS [I5do%KLU|*U/JtK/ "",Hfb1cC䨦eH]9 i埊˴v&ɮ b&:ON ./!sᕆOH:[EΝ>-A{>sh-Q Eb2ӖOO9 &73D(2v˫`6͐ܣe‹$.!PcB$Un3t{aԨ=p4&JMcR.9Xpط;aG)u؜m-ncʔ6i8H9M6$=7mÁcō>[1m39/TA^OFuo5=yWt*V.Tg^ 8MЋvOvjr^ Ej3+U훭pbnQHOE0F`OIs"*¼{݈7=Dl;yLl1YZ=I| 8 ^Qx)0</Ӗ2X6cۼΥ6D?Rl,ܮüej[W`Y e* >]up=#uRZ,ҩa447wE1$O mp[qV0iNiO4_< m /\5U0RO.V%so3 M3Ŕ¨8l7 9g.0d1P gEH% t[sQM6evlH1ExEb4 .`ʰ^B{Xk:땯׽*3贈kHbM-m}Ig8[hLG{H-e_WJg7Rp; &/97,E?32[q.NEHXV2Z!׿#lZ2Pl 0n6Tt9s},jv;7vX}lQml'i4b,ީF?i$mSU >&'hZB ;^@]1C)nܗ.s]vnnZET>Sx۶RkZ W\nRaEڄy)OḴ NZXÖeIh1eOtam//h92ړ|[.Z[mujfŸ'r]Ѷl 5r쓔>M%H!XsԎ QFm^,Zz Dc/$!e~I1x6<\ MIg2Z(u":an[`Pӡ['Y1)*) L5]EkCzQd&rijZ&x,,fi 5]ǬC˗`R=tӉAՅ$ef_d"XC&M 6qL34swtST˘>w}隓ڨ`@=p$ 3$[NjaBƻc^䶗TR4}q! 4uZJ)=0zXHwە[VmT6@Q\ NF zw(&ѹaPA e>4y;z;e E[bzޣKG۴5萞MKT!3UC JS*͝5[3]Rp2Qi/DVjBT/d >0*"(S"6geGCgÇFbTN]ee"bCDgjt+0o$@d-]̞WO `?7lXs$l2\Gsu'uVl[Y _2/) =NC!-JCӭAînbG'nZ[1RP"0_EŸe &)gݲ7zgQVp*n o~c1ʳs-{. by"4٩ ÏJ9{s֕G{ 㹝n٩4itJ<a+c`r˚*wp nA)kK#8Vk1J,+u6g )H$Ȁmejtk'<c!25TB ;TMDg0ܢDerc<,'yZgDo:kU 3Ha甌uw*.+ NlPȹ£6o.DsA$!nmɈf;0قjD2ܶŒF2>My!G?XCzdAI=T{"d70k84J?7_RՃYH3O U^٬tv% \S.2Ag6vX3l/@{oDz6ӫ6b)te, dfիa4J,O7y_-Sǐ)U\EgXi 癛A:N#EmNXl&Zg-Hv] rmٻqUe5Cv{7L^3(q]X"P;Wo_\%;̜E aѥْlm<(tQXo_>h^7Cf:iMy20Wt=*ՍOIg _܌$[ 6|/+Eny(yuZUJlJK%"RUEO/Zfմ7?]NW-XmKzme1Nn# 83U]k_;r@3l/|ӨkD˷gؼ@.J㻨H^YR59vn (yS$oN6pI6„{a6If^NOx)lLl v w0E Ve7ɥfU8g 9X@4rw;ٌy\'P`D<!%irP*ؽ{=+,FBͬVys1b5Dmw;Oj] tk`H(TiQ=zŷok w$?fOil  :HAx r%xLm?l, r7of11̔ :o2$]{GdB37)I-eSjI1][dq:Q|StӘL Ȓ"{*SYl^D{sM9[$r}uO$ o#ey&vd7F O?aW|Vcsy0#NIM>}JF]bzvDb+F3IBNIRQ m 7fd'>փ.a'ZxR+Xo/Qjeoriabxy iF z{/,\vuR^5$i󔞷 R_ƁULdsI B-`63ޔv`AmrK=0:jtks^@gЬd땯Eܾ\~q8&9eNjn(Q2- xfx#Hڍᩥ=͐rR@Lj3Sv:U 7b#2&G穲DZčMreEźNQeK]TV.chBk mɸm8~ ib5cE$_'77{/g x޼ 7QjdҏLZm䔶]Ľp;8rBʿ5Y;24@?:uS%PHW=ani^khHWNv4^V@j+6%ޒ4j.2׈su kLy "^0]@f~w;Y)]ޠf"c;Cs(o4mJ$`!7cѹc :|3C!O삈:lBx9exR;`4j v~iaHL"ś+i?m(/ɸH1J3oH+DЍ31 Lpr+˹8^Tze [HEMqFB6$ ϲy)`G$bP,Fܜ(a|LjXCFL )u}0ٶ )MأI!<Ŭ4$"1^s o^!ZƩi%`صP(:@jmjhdTٳGc7}5zdoLbP h# &#^(NY _܁ASGi8H*WDu e@ӛ[; ͢%š%%<% v"sDr4 P;wqkt0,/MƓple`Dt _Z!Q7ar RY_OLÄ*mׯ}/P4].i73S:uvtaEFۃ;t9 3Gzf?ŖLQ# qފE\հ)`Vʂ:~'aQu,["kTorU>y[#7#;=,ICH|)ɓafH,Ui*j9s!Ztc6"9Dr;Be*G&aK؆НR/wznj_Z+}q$[ Fń͏5B%4l—ivT:s׵w38^Ȋxz8S+Ok|6'9ٯC+bwo:zVwN\i>EeyO8\Jȍl%X&"%WjIa U0, Jkj Y)9ROg5URDLfDJlfSfJJ=L8%+F/P֎TajZelpX׈a)цsΥɉC3,A|zkH+Պ^-典"/Z}\A;0O7ƒ `$FMzY P)Hl[nEiK\#k0F?Il:/!ǽ;њR~u=l9X8 ;SNs.z,\o?mwN"8R--fqs+;J?hIm|HkFOkbњ8R7_!r ͊ظ)7 &'tE+m[1/ܢG܌⮎WD ]1Z~O:?[T=Z3C|6n꺈ٹ vEy d7} ],"U}:6G%4δowKM؞;EgmFZ")I8+& 6%['i.%IUoo.Dꯊ5h=-Nᦉ]bá8zQlcq`cD'pܔH ͪ0142SAȂiAJ*_ִ 8Uim&w6aq]W?4F\*lފwlk/^0 %G oJS׿ Vֆ<ᆘ 3NhI- 6=H)["q0Oo30Ȉd3zlt~*ffn.\>.ѕL ݝ3: B$'Xi-@k$y;cDFNJZ 6jrV dO)`PX޷E K'{53UL*;y+=6S|"_5M .~MxY4/?BKCpDw{kŽꄎ/&͢vGdCł,4YlJxn=Cw9B!Cxr5=wQ{Eì)#'h{1DXO;i[.qH.#Oϔ`YY(u_aVzx$+9n)ԭo k'an'$:s;I zzڶw h[[mVoMs2'+Ek ƳغJKX ߢ\ >r\oa.u Ӟq]74oqKȀڐ8nrk7wv_֘ÙfQZ8$%5(9#c,ZI4[[q8iUzUֳp] B6ͅ$J$KaZ>I'O(]ɱ;>-/t 0m.WuUM+\ؘݑKײ/eĔƷku?iTpq$#iYKI Ej4p،sB3LY5z+:^*uX$]D|+oq ;dKz+q&W-$f'1p2{!]֠ܤ:r|bk?uh_ @ i-lYRKٌЙ' 5{\Tbjc kI?P,97j wP>iN 07V2?ܬ^ Z=lBͧðs "a(^xM<\Ջ >)3K=ɋmM#>iX8/Q9geP$dxI6T}~&'ߢ_ P|2|w ĭjs_?:˱FAHԱv˔icdgQ"EN̹o Hy+!ev+̐丨`Dn`r6#$ퟱ&)GF|\JF}bh͈=ʂb8W]f^`_Rl,_S¥)hhrTqw dqVVeB7{|a٪zpC˖Nz^,.rigNRs^syr{vqO&fW 7uͥρ{e彞b:res+2U}FBm`} & c3.S؉|JuyD$.g(cg֪mbMWڀmO#Y℄ #z<(6vv2Dk͉+3;qT\붹wKt/GF0Xz:$KӶEl؆[:FI!ݶ w2|x=gȼ/korϺfZI*iNN;+K~V76. BeH'R "Yp;fXW Rr.r!nd'$t9kef3#T$}u$ M<8(7\kaFJ& )݈v&zu񘙾v:SWXy- 4^muU<ҰG}D'Z'w8ZV:|F+#(jA%TSp__!@&-:3+>i冻$|;Cjk7'"ZP9/y3XY V[9똑WUm) nI=ev f'Ǒy=Q6٣cXqzRy{9Zm<-odz_޷bq:HV$-@$/3p@V>Bȋф/$1]9q= Gc6}4򂗖I,,o&Bu 6FاOӢL _WX\l~ovR*_>~=iN7φUiWPzhgҹIqٌQvq|=׬ق)U0vc痌M*LWT.RqpRE;}93~!6E8v7t8g W>2X_PPV j%br%D[5sdә4""Ĉb߮%+I \4,)*ܒQ"ba=Q6mFr59txMVxݍ@ 8j IDAT1?cH7-{|!.1eq:DK?kQF#PJE+*yPn`^~B4@F-{NEiAR:KK7>B-W=pi3ܒJuO~9H>4VzM-]b*O{ZqNēWSi3AI-׾̛|_l1E\l{jѩr'M)0`F7ڷ+$C#1E|69(ʹϰ51]7x8ڀ,Vo>'+/m2mJMHwo>̦/LQ [PXD/y* 8o@ߒ<$aT ZsA, zqT!8' sȵ'k'1ŐCv 63i)8\%G.g(nSV" jA Ө[/(yޚbOdN,+QQ!s;EJ3zU6W@mI]q\Ȣ>y(CJWi ,$V?2,/ɘ Wƫ`29Kki 5P1z-jR1 ZSSؤҚ,::`y49ZAJ6ªFK==m LiAKG"عE0ݛcV9IPu4.27mKs7Qפ ПgtPPDAwӭx0Î $ļX|Ϙ/8Qewc Y,ߎH,M=ev)z@d6C9U&ITס0EԧMM;_jK=`ʔԯ4--Q$:i3U e9‚2wC38yJyH%dX;8wzIܳ4&"!sZ70L\`_Ǟ;1.\0.uy ,GʩtTϺpvYj`yGz(<ݧYuo[7vYu"fZTn3ؙf#tQjUM۶^@9#ÚisY\;VQRY'gJN~AI~,lN~w0sN`֤XdAEfynQ^\%$}smyvM㜙I)2OJfk=>w\IĻHN&)+#<~?TxkǑMxx|q<@Ԛ:U|&tq`Ea-`iA-h|$I':Yւ9Rcqghy1A3tk?!kU,Yo<;l<5zHa[C- ^pN4k=9BalB KE ^l"^By{ VJMcF"ؕ fɦ 1*hekMs)hZ$Ii?ÙMH 5/-QnZr!eU:.\1~e.aӿ%: myͧN]\ÅʏȌ//v"ԑ O1ZH F(dK%\m/wVTidXmG͹@e>jyRqS`Qٵլ(ͻuwDK8B|A,MnNIyq A-o8u<|| E␁~3sGs7!/!5d)^2J+qt47"׵‹_Tpbxl>+G!OLѡ<Xm͆‹䞖ͷrfWeSztui.nv a"/wn}4­|IJSYby_n[+<ĸ(ͅc ;\?<>/b p]5Ĭ3Ik )bLL&AJc,4ř,NnWQ@u=nË %.U5g'-\K(ce5`mЬє@ݦeUZ3ؓR u7ѐ)FqLpREm(jCv[&SYoxW[SxZ̹S0Lkmp9\f?V9 KR4+Ӻ&DKٽ :e m0oJLOX.^N5 a:u?;?{E#V\x|oW<kPgn;腥dHu(g41p/jwE!Jl?ݞb-&7-2ԘBbū5͛=N5-TI N!L' SqlX&"Raga~@/&٧Mrb=n6} v^׼{y|n-d,PZaR{,[)F{X[;t_S9CT) b I3ՙfswA5wuv; eD0_Aʺ&6pKGJR[%V*./_yHaW@M'wMQuY-yr扡i($:I. # /cL#z@6/D䚞_{.fcb`%>pkjۅ =x=!j٭s=AukT1Ù-WEY_. ͋TB? p:d܉ЦNGVz'qJrԴ U8ސ.xxx P~o<$5'+S:ф|jު4NY9/7j2M2Zl]o{ |?VAW(o}s9Q{7! `z|gȓ7Q/-<;c%trH;DNWe`Iݰ*5ByvHv\b1W2vuSI!4?¾]n]cq*"Q@ImyJ7A_ _bnmLw2y\aPRilW$Ӿ7$qB1_h~ 0瓳9a+³Sr<Ʀ c^ob8 *)–}B]=l'%3Gl['{z =A>79@Sx)u0;RWo݅q8lw̰qyIhm/k(rѽ|XRrZ7b!MH)ZSZS8 Nj6@ X3h+%ѺҾ})+,;(z +EFۜd)=ٵg'mo|L%gq`nciuiȑ$ؠ$WuT=Ż`8~k )fߒiwWI :4g #~)n_7-ߑ ܾgIU|kry\>}O*<7IT4'\De6 lt8lamĞt[B8D:/:ͬu#}B!2Ȇ/6 =ӵ-\`gf2(+SZ« 8lw"U ݢ5MR”S7SaIu]j-˳d]unncэ @8f[  #Bv L8 ~gk "Yn,=#V l^ËL\ވ\p(0 ߭vGH;q4(mgIt֊OsRHxfjv\ kZ1/̝C();;/ڽ/C<ҶKh÷2 x wHhA!j{,V39:#.)hڼ @!"I+[eoԼסc[Bu{EX7䶖Jo~-6l5aTYpn:5m:g]П (??Og8n~xG[7 Lh5$iIRwь;4vQDmʜ:uRI⓺,mQSEEй{c Л.WzV(#3ľEmT;÷kҡH'8+JSzAtz:Yv'3.abM{yq4{*2r=y=EsƼ1e(Ma?Dm[[m_0/<'=c[ϮFDjT8Z4»w1>i(tLy?u` F-k Yy$Z)ݵRD-̪rd{=BjtaȵIWE|Xh`޶SSul4- t>[x4߽זxL߂Sipgp <'›BC{vXt+1c<= 3(>NkMW Y`b9:eV4yuLpWL?<2>8 2!:¬xY-0|H71wOL!0||ŗ/Jwf̉SI8T 3Vo,)٫ZYhlPԵ4$^kROb`= 6IE N. -6D G&MCeYԒl{gxi)[ȸbvƊxDu9 8gelXn 3)'qm>WNL[Zؒg2Ns'˓,M-ƒXic@e< ވJIXLU4vՁfP)~76cFƷVDY+U_uVX[nsRԧ,ll9~2b%RkljۛCL4QB-IE+|V<:PEȈ|݀?Ȼ38zVocTY^x)2 VuU:员T!P7DVrئ0lm%XB1Av](ʙn. nԫÃwDg<. I ĢX1K\&|}: x&x*X~XZP=b7X,T*@Dka({+ڕ .<\ 2.?p5J8-\p[[Pc#6PA؋#ti"M.btnҩI Qzv B@qtJTLvP(Zfd#VWvD%t$5Ba2.SNu=kYk{HPeT CGt!c\0. f<,LXCDZpſHIϏO  _ A6`y yRJ)@I VB_Jx`{ٔ@Z)7RB ju`JGz jM ӓo3'>/]J $ػB29gyQw -z^i_wU ѐ|*CuW:ԡqt1VW%4&< ITV\=kVqy=޽'\&f_6IJf8 lZ.q tVk|1 Zqx8mP:Fl&W"!v mDCH\^{GV5F-֚$e4ZѬ&=,7˶CR_?}>:[5Kl*9HU>}iD[dדO~4P#ʞ>6}e[Mx vs\a^uj$Nmy*S0m,Dt=%}QnsluۭG+UN '5mŸ&˨']DV֩ݜBn*5Gtݠ/u5r#=V'g'CPe`+Ȗg$9h_@t&r*kP~*/vgr> fd\[;!0|UڰxcD߻"Zezl1wqնZ!nLo*mFt\8 *B`ĄGr MIDAT?ӯ-?^H|x)\b.c.O)jg)]&J$ľR3kk^CZ=?=N@)K¾ڐ!ާs6hl#u9ƕ[{s2Z!;="l]z疮Nɉ{-n# N#{~dd[%db`>}TrQyBHYQ1%~oQR[MCu811~ p%ݵaо 嵻+FG߼;U A]N8Mзo| /mD8O<8eD;/`:?hʛA\Qg۱Neރ{-"rs.3-"7)Pn:M{|+S a?i*#|1OIbeBS l s1b~[NV՛m@)B){J;!϶m31^~'^O;HY^eAm<9w'wos|#6l~>3O7nU^CmNJ[&w>#Z045ǸǮ6`bi3;uS \|3n7wV=uԹ9I7]_-^9#p98ķQEvY F_\s_W!\}$6~>;5{൯? LIENDB`kraft-1.1/reports/weasyprint/000077500000000000000000000000001450127457600164005ustar00rootroot00000000000000kraft-1.1/reports/weasyprint/Readme.md000066400000000000000000000013151450127457600201170ustar00rootroot00000000000000## Weasyprint This is a kind of case study if the [Weasyprint Project](https://weasyprint.org/) gives a viable way to use it for Kraft and lets us go away from the cumbersome and weakly maintained self knitted script based on Reportlab. ### Try it! The example here can easily be built: 1. Install weasyprint preferably using packages from your distro, see this [Install Instructions](https://weasyprint.readthedocs.io/en/stable/install.html). 2. Go into the directory and call the command with input- and output file as parameters: `weasyprint invoice.html invoice.pdf` 3. Check the output file. The appearance of the printed page is mostly influenced by the CSS (Cascading Style Sheet) in file `invoice.css`. kraft-1.1/reports/weasyprint/invoice.html000066400000000000000000000141731450127457600207300ustar00rootroot00000000000000 Invoice

            Kraft Enterprises - Seestraße 23 - 21843 Bad Beldorf

            Bernd Bolzen Bevenser Weg 4 91221 Bad Bildburg
            Dokumentnummer
            7-2019
            Leistungszeitraum
            12.04.-28.04.2010
            Datum
            31. März 2018

            Schlussrechnung 7-2019

            Sehr geehrter Herr Bolzen,

            wir erlauben uns hiermit, die auf Ihrem Anwesen erbrachten Leistungen im Bereich Garten- und Landschaftsbau in Rechnung zu stellen.

            Wir hoffen, alles wurde zu Ihrer vollsten Zufriedenheit durchgeführt.

            Nr. Posten Menge E.-Preis Summe
            1. Website design 10.0 Std. €134.20 €3,420.00
            2. Website development 100 pausch. € 2.345,50 € 4,550.00
            3. Website integration. Items are evenly distributed in the line with equal space around them. Note that visually the spaces aren't equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. 1 Stück €2.225,75 €2,575.00
            4. More Website design 1465 Std. €34.20 €3,420.00
            5. More Website development 13.20 Std. €45.50 €4,550.00
            6. More Website integration. items are evenly distributed in the line with equal space around them. Note that visually the spaces aren't equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. 102 Std. €25.75 €2,575.00
            7. More Website integration. items are evenly distributed in the line with equal space around them. Note that visually the spaces aren't equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. 100 Std. €25.75 €2,575.00
            8. More Website integration. items are evenly distributed in the line with equal space around them. Note that visually the spaces aren't equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. 100 Std. €25.75 €2,575.00
            9. More Website integration. items are evenly distributed in the line with equal space around them. Note that visually the spaces aren't equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. 100 Std. €25.75 €2,575.00
            10. If you mean that Caption and Enter here are not vertically aligned, despite using the suggested 'vertical-align: middle;' you may have to look into giving the columns a specific or minimum width. I am suspecting that the elements may not be perfectly positioned visually next to each other on the 'reading' level, due to the columns adjusting with top/bottom padding in order to maintain vertical alignment. Therefore being strict about the width of your columns may help. 100 Std. €25.75 €2,575.00
            Footer!
            Netto € 10.545,00
            +19% MwSt. € 2.003,55
            Gesamt € 12.548,55

            Bitte überweisen Sie den ausstehenden Betrag ohne Abzug bis zum 21.01.2020 auf eines unserer angegebenen Konten.

            Mit freundlichem Gruß,

            kraft-1.1/reports/weasyprint/invoice.pdf000066400000000000000000002711771450127457600205460ustar00rootroot00000000000000%PDF-1.5 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xY[sܶ~ǯ`J";ɌG8Qܤ[[xqdK+9֮li==/Ej!A\sU!Vp*^{x/|H LӚ0i]!}quZ(6B6~xp,)um.\imtIkhn&X$7VYh~>+ 4[7Q,nM];Д|Vhn&X$54Y]ęYsq&qfERAȶFY`S*G^+H@TR[ˑ2>qѮZXGk`UZ8Z˿U-*ꧣ o*.*J򠪍/7U\/O+z}\y]YZ+*JLL MJ@1mXK Dip=וLPK;y*hTu; pUW^­ *Jn4poW|?8Y<)Wn!G( ژ|8,}  FH (o~Z_nNXچ7Q]Rat5[Nƴ+d|$@ە/36. DAD j%/=d?5 m,_UmlKTDvЮkzǨ] wU%]{{M-rw׀0J5mPg֕-j&Y /mPy[|hZf8 |Qs_Y.wde[>8g{FB 4nc*U5*/M%j 9auD=Lgi`[񳀁 Ce#g* 3 ({b憈mYJ粊 zq?9*a/W99["DkDia== I|KO٘sx^頝Ɇ2W|XE"|e"P,/YwǛׯ㋣_j%_f*|PxMl%v #A&w"Gx2r"ba[`˺d"2B~\2h G?ԮڎHYM@Ž4qbk+Cw0wϹu7nY"[t?'N!"(KD*+OA$lo`R\fk5)CJ ~F4MٕNbWV=tjQi=OR:!/?%BAQIE%Y\X[,H<~@3?3 endstream endobj 5 0 obj 2699 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-0-1 7 0 R /f-1-0 8 0 R /f-2-0 9 0 R /f-2-1 10 0 R /f-3-0 11 0 R /f-4-1 12 0 R /f-3-1 13 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 595 841 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 16 0 obj << /Length 17 0 R /Filter /FlateDecode >> stream xZ[E~_1>9m`51<>,썄sݳ ު]5āpUUWYd+w/#پ6.l\{jǽmεWgv.ڇ'.adr)Pl• f"W4V6rbo/DB` 7J(JjJb5:䧄ٶFh A%]IPmWIl^; *aUJʮ,B {&W*ʂ*Jb5*읺dZk9]INmW lϢ/1zRߠT 1f<C;8UZN&-$7\n@PɂŏQIk(t712##b)s&s%=ԎÝR$:6I'nsIGR Y 7${F%oMv|N `2RsZ]jl98KH݌H5!ѻII>9$fq<8V %zv&YDgf7s6hmz)n9`FȺ$tO :D-ږxLZc+03NG-WKRT)Ybd}^@sJ+2qͲv:J O!_$5$aj!o@[1'kC ;9ZoGzJ>@#ylÑ( )!pShY3^rhW\z|yK& }--xq9𠼄K?۪C9?[f~u~Xu~XuۼCT}ތ`U©z!YG#:Bi.{3BX2NąuXG?BuXGuXGb.>B:r-v|*ƥ|P?=3xçN[/HD\Ah⯼F%U9s aL/Gǥ\<ԅb'kLǷf?ħH1 )Cax1ǐd*II̠GY%[ cqdôu? endstream endobj 17 0 obj 1439 endobj 15 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-2-0 9 0 R /f-3-0 11 0 R /f-4-1 12 0 R /f-3-1 13 0 R >> >> endobj 14 0 obj << /Type /Page % 2 /Parent 1 0 R /MediaBox [ 0 0 595 841 ] /Contents 16 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 15 0 R >> endobj 20 0 obj << /Length 21 0 R /Filter /FlateDecode >> stream xX[sݶ~ǯ`:%ҐƕLfi3MZ<}%)Α#  Ē=C v߷эGt؋bJ6}04W7A׬ͳs\?j0r}msS.mXySR ?x8=zgŽ*[AZގcS7N~/W1 T6< PLuzh%(6UM*y7<PLah%(6UM*<Ndx7T/W1 T5eP\cu0Mpz`3t Y`ViDlhPP ʡbڳ\3rnΡC!ՊfKH5*[j/ػ1CcB*ݐu/UNz"ZO~\5!Z˭0MU oJgn9m(q71юH^Y9tD!}p=b{/&4GS#g{T=Ffo#8IW(M@ؚ[Xy;I x n&CW|==Jtuř+&zEkN ;2ԑ8ڂ:3~PJd+J(mOd!yOYE/hTI+jw)|ڈ)@W&Bwf(IQ%3\\Hx\r"8h4{,gyz\8$AI3a%lzOi q${N:Mй QሌdL:PEMĘ>

            }rWl%7Bu'iÂ1EE;~C9@PPb%#,Xfy>tLq]$^wj OO.t=z~0ISR2v;d'>]+w3C [=%)5?Mlg|g>mt><ʼn.R \إw^B δԧQs RdPC4ʦ1!{#%"tj>%IF)\iVʶOjY7*l6q>Z畆댎Ǒ"rO{uwv ڝzmt#Sc DIGV,#S١@OXlVfOnh7 a|:~~#@ԭ1ygNF|m 3GOx:|TMŋE*ozѿQc%G Wr)?ĐI,y"fOe:Lg:ED_a`:o^N5:*ǧ7}BpO.wvϩ q-:en^LPV&"T_*8\mU1pP}h[ISQL;ij/x 7]EZ Ot^O:TCX֑~z(yTgzj\DLAidʻiSO;5P69 >|㦈WaWP~]@jL Wѕ8yyt(.e>;|)96`8uO.9='4瀝=%xOr.0,9\2m2~C!(|z`>HPc `CoiF E9 [mͮx8+co賤oYOBD endstream endobj 21 0 obj 2023 endobj 19 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-2-0 9 0 R /f-2-1 10 0 R /f-5-0 22 0 R /f-3-0 11 0 R /f-4-1 12 0 R /f-3-1 13 0 R >> >> endobj 18 0 obj << /Type /Page % 3 /Parent 1 0 R /MediaBox [ 0 0 595 841 ] /Contents 20 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 19 0 R >> endobj 24 0 obj << /Length 25 0 R /Filter /FlateDecode /Subtype /Type1C >> stream x|w\620Vd]{(FA:".VP" *EcA&E"5j,1{!߼gy>|~ٝ3w:E,җbKd|̊ %1CVŇLj"HL& H *&Z牕AʼnDCjQ&8Ա/9f g$r0( xrБ}zu_\vY"2&*2?.(P:B^ZwG#Eƨ#'1q1bΈZzUpzCtุÆ%&&6tEdWbbm"#ԋÃ}C*:c"R􈵼D?rDDENbSx8\-N[zEEm;Wפת\J%xdjId$S')8+C7ׯoֿL5N-b3#zNot'\*JRT#* Kk҇ҿ (.> b NT4<21fp: ; 3bƒ82 Le3Lf" BF(G=D/F&FFVFj1FSe00j2btg#Ӎ6~ (,sˢekdked1cgx}}zMLLLL6Yhmhnl/+7oJ }}gjhjae`ZnZmz{?LErc|GM&?OoPa /~N;ׯ߽~O}_ bb_8RQ~}y&O_l_ן? 7NYMQ짶0naTcK(AR2+v6F;ePZʧJ;)i#4J<* ` NpxHLcéx#{< ʎ啗准ŇK(B Ab!NP@m@W<< c8#;w&uöMl?g(O~>8CM`݂WtzS &13+ñzvLãx?AyGjgoTZS:DXZ/\Zb;~y犟?onIޞD x^ 2l: I@5W!E>CXnnY2N 8$4)ne7?Rl,ZIMt Ntݬ 5m(A.RTFx qC /$v,LlEBIPzu @?D:Km4z ymu[թlaW ri[gy)BPi|$HCmg;8B Qӛ  4g'%?YДڂ5gFVT\'>>k4)xn_#}-~꫆$,uvv&I̔Δ)4z81eZ]sm,>ć,~-!ЅuI8[\:=$́ޥ R{()Hy2?&SۉJ+ONݥ N g=k&|Z;,?{gϔ*,orbL|cEjXnfUZN"d L.WŬ<\VLb$lx:STZls>;g銘ժb(f9| w\m~oΔٖFp͜ .REy ~6Ҟr*vך}GsPm>KM更BPa pL!hc$$8-0rH?i[O]o⽛( xyxe)n^a>᪊`,D9[[d"lrXWUTT80#}+b_-YSğܷnJwP>[}n'躝 :!Itݢ;_M''ț>;]=tSyսtqmaU1k´sݒ_V{4'mQћ@xcH\N^ yC#_{%_* 5OeÉx1f.Wh<&0d3vQͧ%NXɻ79}zd]p^ ׵q:+NX r rh# 8]}+_hVU3EѰ/dVs$ 2Zau-9В{-%H`K^F2$)bĭ ZJ!m]9qLgەt pMU 8]ܒvu,W|4=Y:t,cJBo Df'\$.LN\hKht̺< [0 n5j?8?$b#1cx h.ˏ޾/nIJd--E[genhPaSJ9'  .11:&7GU*+N$!I~͆-*$ vgP؁IQ!ܐ KarN/h=+T23ӰGgzz aPF>+Hܽ_M$\ɜӅkmj97 TvϤѺB$v2|J %%~s2t: >JќyWp0u0:OA>%f/xHy9,:oѐ#?cG74v0S>jMAĊu%#a0f; o?BRdtQ{#rsLg$ڪ#q.ő(;L.2` s`o +=rĚ#qkcb&e<9q#@5=k* Vx0]׊tI\J8)UkD$MeU{7FSY4]j:;k_R?s f9x4Rx{E{}/+)_+/_yp߷qʐuёݵuW¼9|A u8>;h#\P6C#`43FGRKo9Gq); rb4<%E)G)NyM.*fI\&3 ƕI";=GEnc8ۖC8gU/gͳŢ;_2ŵ='O^`,% Ѵqu##յ`pFWxQ͠3Ou>_̤d8*Ώ2F+1dZdS8pWޑ4‰PHbg8W[~)<=`.iL/BN$R]򟺱۞S55 59p_^yiJ_Ny˔l{ Q䑰?FK-qW` !7=dсpZPφR|׎[x½u`keFPY58MɎp2@0oDqfO 39 $L?5}ZʓFDTġjx',nZ\uI$ ypHA `(J۬n%lI)ߎ0OOGRlR; ݒw}G L C{v݆;M ϵ*]plF -8H^"y?A|2V{b d,mm6KY"mH Q0 +{`A*y^.<t?R~t K^^FUTr|9>˰@W7O= )Uu7V RxO1W0ӏf&ԉ3Գ/'65kHCa[b/<o\@*kAnNaAbNttRRtTN)G)z&#GcSlk% ؉ZUUJބf&r˧n~\}!'t +iiޯKڃw)`|W(AsO„%Ec 0h4 *iP@UA0 X Ã)¬hP<A7d4roθu}f z= %]HW+`>]0B0~t'N0ܒջ\\v酪kRiWUK+W]OG:y,xؤ(2|AC8?bjŠ#s~$Au3$88bѰD(#|"&sh!Qs뷥o9P;vl8_ѓh6- hkecKyy_̥##W.UBnD399+H8Ӡ AUq5E3~ K4:˟_8$NJDB*SHE6G*(0i*< dHuRʤC0 LsdOiwfaR5^买D- P )> m"8KabKGocYmiCS=~}9 Q'fJ#UA˕K=IKaP`\1n]#+G UT ('b<YiTi֑c$C*eő׺A "(e >aw=^?|dk_t=)xݐup˫ok3o7Aڵir6%Etc:J@չ*. Ra3/ k|~顨=atŋ<ި:QY;FN7HnUwqhRතNw] xcchA=pN*{!7iNIX g†C.k}V9*?w#J ,g6Dz OB &M Gn-!K'*I2ZTCmԮߊN! =Ԭw(慤A_<䀹 W )kOZ>733Lն5q+ d%(tC]`ġfhA$Gރ'G S|,WQ-RL*?<|$tN} nph-Eunh!'[afD< @3lVۮJx3H"ϢҒƱGN/d.74LV=nR$itO(ĐL$@q""]rƪ(MaXDy q SCR5nOjOK6MY&fLSfPgv{Vm!89D` Y8s͠eF8(:uk u p'2tf`$00|U 10j-$H@~#A<(W/lNvRG aEgܚ 5)OM.q'EElݴ>EKjWפ:+S NQھhs@Yt"NզJz˒H'OIT:75Q/TGۼC)uB ?`-R|8}#H]M0 +f0 "xثs.$4?}% lيUoNP{Cƣd#Z =eo{[}Y[yُ,z##@SoOWMo-M+<f(Z<( %Tlwt npOwtAmlH`@?ɶ! {?T+d |i5bga ~,!BfbdVAӍ[s$6vMr\>6d7u#´hF" 9X~ $KnCz;LW!wss   fH񶭔{;(bMsĠ 8J L+J_JVԍ4I9IhUCbS)Ġ"y0G ZEgE=}ȏ~P@rBxO_AeaaKIҿ8niK:^ΨE }9bcol܇q- `ccP__-ՠ,@$}S5g(Z OCP){ R 'rvglÓ>{"vמ}?ZN?qhx.)A R,"BQnƶBem!e;r$< hE<WFGK 06p!O۠m ebXFhٷX\NsIXlO?U"8M 5CՓb8*9d}LaAkOփW칳Ia:cSܡ'Dp+ojvE KzܪtJ ̪I-?ukF*+`7 eeeQ"bD G9 ظGQ!QC 捠m0'o0 ¸vhZI>A H<2=swO|JN#܇w"f;LdDk'|[ىͦܤ`v{p? KQ Ym"ck&$]Odt)-kn8r߁0)AtH`zz0·OaQ'PPi)Z؂p_ko aLkɩ)¯Pq1?z؉mq/utoUTDUXR5Ca9B]={ a)v.[q[sB;|R6I`{ZH{C8sôpY$b,6r-!uadN^[Rw'tZh5kF9GA=?lFXpօY/%3¸D:/ ,&dj"= LY[z6~݅aPl1oH4=5Q~sܷ)5(%>v?fK88*c {ImnwI,˃Hݷf$Aܜ R9ܲbnHTӓ /ףDƯZYXms ǿZKp 6ɀ%6k jN$7r=ƿ> "NyȚyad?~r$M\v<{M , o`nυDCSE6>}.?w{ͧV˫)1 nJaAo?qr_ƾ`=Mȥ;/E|}UbV^͇ #;k2RS ZՒ4J~ʯU{5Xnʆܷq# ( OΖʻ ߯ Ս$+/7TFQ2E!GO8NLcN18Eh;J$R!3<4f1 g_ ɓ#a7/N=uWӦ'; &VX&MRnֈԊFr*P2; 4 ģ%O$hurE-&Mw-XZS"gY 7;ܯߙ~(Cc݊|EmLi6d6lD9fffkͮ3vc'{6/0/605jieBbd Wh8rj/-Yj)44k9reZˍ-wZ|eW/iJg_R+)7(7+)w+**Re^yU٢lW>P>U`e#XO6nc36a+M}>g߱JcxiVVVV.Y]zh{OVXqjΎ̍&r,n>\q\.W'% Tz*T5D5MX UE֨RU[U;T{U٪<e Uꑪ['/弒ct~`>O7,~_6oT-SkCc3Knj/ u:B^NSTSg&um=cuԽYg`=zRk_hMiֻZ[nlbn}6z6}m6JFc3flE666a6166Z46{m)9ms%k6wmۼ^[Va`;v$i m=lllmm7`m Slo޷Wۿ4bhkkFhj&ifk\4PMFi5UF MO;;3;Nmgg7nLvRRe˳+;iwήή]]=.gv?#{Sg;{ڇ''ۯh~>4Ȣ8}i A)8wl8C?J֚CpA8j+6T<-w8&r,ַ'QGn]@: uZ68ͮZ{!&LRD*ɆFqF6a&WA8p[`no0IIT}Ӧ+2'G'Uwu7+6Ϣ\X(a%T-lq}UI3۞o/<$?me>̿+#rQ( T5RS#*^H%^xZ1?aԫ%҉kʇPm]J]N/\]|VnYyq,4ilZ/|[p7h;D Z\ID**}.Γ-%\`1 (4r ͩT֞)X~JUu*r*88qߊ.$IPz^ZpWLN|6ŽNAN Q=ÒisԲ|7ܻq!6蜪ukVjP-u s̞[^p\yEל^J 6wTKF9,Q  my>ATkڴheԿL'p꾋ľ3U=uE+cbU"dN!3bCs+ ^#\Pm[D=5K޲Lhk:VxDŭ \MFXͱ5|~񔻭m;nC#=Amn;Ln2V?wU){mk=I炓?p*1bAf׹9#|xybnsVCEInsO07kFAc <}|X8yt~0jve#Y/C^|%jcw28Q8p`Y{}xtÄΙB'7xo7LjMjvD;Z >ucu37)6C Hh3:UiPSh$l7/?Tl(bngҠei0|oLf/bis`ǜ-Ү8K4S~7W]0Yyt0R@bjcCeKu; bTW~I1eIcՊƓO'({OW02ũ z[sc)l3vnﱉB4hC,JwarVfr ly$?+S9yyO4u9GqT?G.9=X,.̾H O_t{uJ6+iJ:ߜNe*+aѾ=g%'pOྀ' MM]T׍.\\wy3 z:>e2NmN+i'Fm-Ӯ&T3Mm|Wʥ9m?b9gW Rj֥lџFkOy[[;:Bj|| \UѤ26WmJ` 1=bJʉnMw[Ք(SKKX<)1ќ>LN+ܺi]"sW(Ɩ'XSCsc=BTnͩAA#p@r2Lgnn]c%P*Tg=8S ^H{b. ã!Cd[n^|&.&B.poq})yUܹq66]jSh3(AHN|ʁ;Le/I5֤`0ɕ}[!řyjc0G4o{Ӗޓ WG}އwo72OR|+fMFW=-]r/63#$#88A *̀8z$nGn0HeE;I߶;:5U%xy0!'F9s/dw&ܸFHT9始~$ld|o=O]~ͩfЍ#Ug[e?. fv$(}"nPe˅xt vQǖ;[Htb6^|LohT9f uncP&f@FqdCs/ÈfGOP_ȅKj&Ĵ O%OVE Z*!rl1l'#+),HʉNLM*eqTI{( )y mO1pk^e3wP\FG%Fk}7?SE2(,C0V8h4LܚUfN'Wb?Xi=u Oy"ORciLohP`P#iݾ.Z&6ŏMf{AWq J7ܺy/TgNVr s @ %pɤCCC*&Xhi~Q'N5bRVtt:zDOO j c¤o{iCC H;}(!K3=@j iiWr9~.UИgN/+;2(&6-/Qt=8gi€'u&趜 /[t'w9d3DؗۄGuYutN|lF^?s{*`n[5UEa8 8q(F[~ Ņǯ)/M!*O?Nht⺨̈́'qB?]?unl.z #q Ɠ,:joJt+U؟FGzſ{*{068 \[: Co¬ڽ&vg;`kRhܧw4~l ǜ}xHP#[/ocg #ePL:ړoávmn5q߶>3m}y Fx)'W ftHJ~lh˷SbOu*5  9(l6UMin;n4:& n4*& *"D]Ѩр .@UH1FcbLn1s|d%3;Cs8U_\DEPv fH_!/RMv I"mFl.}r:N'y(E|{47};MT( ۅaP:~JoO)o1w5l~[ J=ͻ6'2A{WnNUdT 4ORs] 8'cjFXg,d枺n}g`Sdt,]Y X!b>wSڏ.Ѱ6*5]זfg@~5ɽLmչey?q[=@>ڶiN9ZV[Cѷ-:=$(s)ꮸ653|Qgғ(F \f5^VL|#NyXж.k>]A/^0%0,8@u]*8SFʹKjJܕ-鄿AFKۏj*a?8~"ƻ>/< y䂓BO:]$i䵅2@'գPC*op] qwEz(s͌dRɻIcL5n(Hs4fq ] dhϋ8u 7Ѐ߀ pBî2ڬŐ_Ш4}:҆L'_ġnuG$|V7іWcQH̄vW]5֘IdnRJ+ff}4#k,ۉ?W}u1{e$i,YCzLVrԺSWE1k֭?wX6"`Q&6|>D䙍,t"a쩚bWkz$hJGF:kZ;J~(ꘪ0rUKsW:%=FTYK8O%@0Nc;ꧪU&.NS87@ jđe^c#H"k7)~{I{'Kv;X6]_8'Ë" xT:+kۋ7/]gX!=ҡ~C7'>Iyا*4W";! 0-3RrゲJ jkI3p*: *(8΄EEj哜0,Y *W]ݲK>%Hv~iwHhƩrm+b#QڅVO lǾOB ID|y;%hFdFFg `ytG ꅂ0X["v' |]Fo nY(B}h<,U^"*.Jn_bv'b1iaTj鲢raE%YsB=\$5=WP}.L'jkC4X`M|m@@枨γ 2Y~(^ ;M襯Zo GROHy7ai+O.1$&0r,Ցi2#N%:rѲ3Lx gbEBw!H2S<3f6);w~ N%Eh b6Eg rh'?yųW.bpR3 e> ~Z0j)ӣ #{\I+>㗏^ŇV艏l>4ތM\>ԩ}zaU/= "55㛏^xHa$]5v&rQ6qH0%3T$:*TP.*B aNђ?Yi@2g5"~&% WMo&KTq5<8&oFq\LDOl Bl^R/"JvGߏ gk &ӯIrmjdHlŒ9WowPGG%]pg3iga`ݼϝ*'&SQ7d2G,u[k*ߓ_dQsqc`ʦe䎒3Ԇ j~2Q`$~9'+ōEqErpLj`=u$ۭ`o :?&L_ʶZ'H%vq!e2;x@&>f ˝Z%,f]rrj4l GE-VrAIks63mFvlG* LSA- $Pr"LcL,U!շx "\\]B{B8`|Ϲr:)u">aW5dXAD+`TYآ"?M=v:mcJ̐V#65]sYKYXĕAV*q,8}<3/R (bE 2:$Y+ٶh*L(Pˢ}R@#i|(Fk1FOeW|)ةu*&֑Wzy 35{s{:K;I14q?ChTZF:.Uln$d$=v}q?9G;QUMT,̪ǚG x9޵c}t0#LPU4-@ۓjN')tM]3yq endstream endobj 25 0 obj 21794 endobj 26 0 obj << /Length 27 0 R /Filter /FlateDecode >> stream x]T0,/A2 .<' KO@, \9\6Gr8~swʛƩ_m]|'sIk$-_0V>tO_O '_C)]l+M~>=K?Ưǒ%usoK嵝.4u}0Lޥ){kWsuYLⲘ&4V\p29qr"8 ąqA~P\ 9P@#Quv0+F-u'C>qzx7bĞ$uFQĚI?QӻȞDijG:uq<; q`x{ѫ~3uz=G +]ݢ#:'t6+Q^%*rn#V?HpF< = > endobj 6 0 obj << /Type /Font /Subtype /Type1 /BaseFont /UCDDZJ+SourceSansPro-Regular /FirstChar 32 /LastChar 252 /FontDescriptor 28 0 R /Encoding /WinAnsiEncoding /Widths [ 200 0 0 0 0 824 0 249 0 0 0 497 249 311 249 350 497 497 497 497 497 497 497 497 497 497 249 249 0 0 0 0 0 544 588 571 615 527 0 617 652 263 0 579 486 727 647 664 566 0 569 534 536 645 0 786 0 0 539 0 0 0 0 0 0 504 553 456 555 496 292 504 544 246 247 495 255 829 547 542 555 555 347 419 338 544 467 718 446 467 425 0 0 0 0 0 497 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 576 0 0 0 0 504 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 544 ] /ToUnicode 26 0 R >> endobj 29 0 obj << /Length 30 0 R /Filter /FlateDecode /Subtype /CIDFontType0C >> stream xP J[ E, *lؐ *,.b7 k111b$FAShovMf̛77ϗ杙sgGTqIC1Q1h֏Ϝo xY5X|i9x?mwUYUTvR>zִiU5vu3?dHG&L)РА֥du&c|>58Qg{橋0S3tico'RtdnHZ}cmiI`[1 i&c>#!=ۘ2>٤ i < dJoow J47iJ1%z[!ͤ5 :[!e'p@# pꨁpԆ'. :C}4?#MB0BhVh6C[C{t@GtBgtAWtC8z"胾( D#1 #2`B& SLC.%afbfcbcbKPXX(*kQ ؈RlflVl.>!x587&-x'pN=Y.Œ>%|˸ >u|rM|/%-|opp-;|#~P`+*+7PE5YNt 5FWVg ֤Ewz6=YuEoЗ~Աؘِl¦l d eKbka۲۳;; ٝ=ؓތde?F?p 11!aXHha2 LdLf 'p"'1i40idMfq*its ˸+\"s5p-q=KYM-m]=}/[=UVw=nRԑV*kw.wK檔TkMQܔ\R|xmT[SVfs2;tyt-M8k\E"M5K_>C1 Q1X#H0HL$" I۱;K/^,[|O$Sy*ե ah#q2I+*!bb7OerwZj99^1Y)OS~^dQϴzҮ۟$u @? endstream endobj 30 0 obj 1879 endobj 31 0 obj << /Length 32 0 R /Filter /FlateDecode >> stream x]j0 ~ CFw ]r6[N m琷&A_.L`7KXI#89Ϛ_*2a[νu\mpx1a#N ߗa/ k?8O `qWԌ+|M2"B[f%*9$t6dͿ~S7EUdOVyL2WަZ+bt? endstream endobj 32 0 obj 237 endobj 33 0 obj << /Type /FontDescriptor /FontName /HKBHAD+SourceSansPro-Regular /FontFamily (Source Sans Pro) /Flags 4 /FontBBox [ -454 -293 2159 968 ] /ItalicAngle 0 /Ascent 984 /Descent -273 /CapHeight 968 /StemV 80 /StemH 80 /FontFile3 29 0 R >> endobj 34 0 obj << /Type /Font /Subtype /CIDFontType0 /BaseFont /HKBHAD+SourceSansPro-Regular /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 33 0 R /W [0 [ 653 594 577 ]] >> endobj 7 0 obj << /Type /Font /Subtype /Type0 /BaseFont /HKBHAD+SourceSansPro-Regular /Encoding /Identity-H /DescendantFonts [ 34 0 R] /ToUnicode 31 0 R >> endobj 35 0 obj << /Length 36 0 R /Filter /FlateDecode /Length1 2336 >> stream xV{LgvECVä" w">X,h+(m1mC 5A[5ڦ+TH|=45iw3~3n0LI_mϿn:x@s-xD)3߳;p۬#:e@wpQc\(&X;\crįCN @&j@- =%Pѣ 5ɕ;[EϛL ,UNK5:V$T X́% 4D4HIk1`J>А00V~'ao+,.,F^5}u]n_>Ɇr蘴cǿv\o`H\c&$-`V;4+UMM@1.70RP@HAhgCM͢ov}9,Ho]}ݺ z-FpgoIb[0&e+ =,$0le#o_*82eQ(m3E)Ní6UIeӫy[r dԜ,x8j99kwDL۾ uE%k#bx̎Ȑnkp`KgPQ4JPB*FO,T'v8aj_$+dw6摍XM3Bѓ¬nbS;07c_rVVJyn/]]-b=Wv3}I9KgLt@:Ij_N~Nl{Zv=-KX"1VzTTVU)ҨHz5Lc HײM}qYΝ_XALtRU &'Fɕw}G9-;_9.#k^%+25|2G_j`~__kY(_ "[@k#HA\v,Mԟ-gwL2 jL4oҏ"/$N*y. Eψ܉)ݨ.>7|K^ 3$^`*n-8mԩ+R:AgϹrU~RW]!Z (xجkz O\g`.rfcI^҈jCtO$XFD<$*"rU Q NDؤQ[`Dc ] endstream endobj 36 0 obj 1533 endobj 37 0 obj << /Length 38 0 R /Filter /FlateDecode >> stream x]j0 ~ CMZ0]r1{OJ;YKXRv^:kd~Q='cEQ6*_VDF;;.BJ>)Y/|{ v]͹EۂƑʽm4MBI-W7(P> endobj 8 0 obj << /Type /Font /Subtype /TrueType /BaseFont /PSSRRH+Roboto-Bold /FirstChar 32 /LastChar 117 /FontDescriptor 39 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 388 0 0 573 573 573 0 0 0 0 573 0 573 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 614 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 521 0 540 0 571 560 0 0 0 265 0 560 0 0 0 365 514 0 560 ] /ToUnicode 37 0 R >> endobj 40 0 obj << /Length 41 0 R /Filter /FlateDecode /Subtype /Type1C >> stream x|XW7 ,́Kaf{Ʈ+D:RwUDłbJE,Xb,ŮIT,1;>ogLy9.wsn\T*9Isg&PZ( %.q U) 5θZ.v5C E [yl'oKV1lMsxk(ksTRWzүW>C ֥$/N/ҍ LN _ OJO N ER"u9)$y<.w|.\I҅Ƨƥ$E'קo]Og˽"SR+XWh]{ңR"uÓÓmRtӃw럮OM7k3# Rd(N**)@QnV()ߘu1lhʬԬ옹 ̟Yt`kok¢bEP3Lj Jڨz>K_,U*wd *C]U:g9r,˹!-ZZ<`lnayG_h+JdLVVY]z`'ƜL`Tfe0!`AHO*kWZn>m}Fo3f4Y66q6y6%666m9cs͏6լUWUQOROU4ju`նmmmmEkwl;ͳ󳫰k`~X)AY+ߴ`!a֍ճ]14֏co_XŢG^]w%K\]6tY4.A/4h6kkji^h@/G+G{GgGqli&U9ON􅓷SS -N85;pqx3@~8?%[SU.ſ'A/ F Sق"D BLX)|#lꄋ-EHEEC 'bXL3ĥ6J<*7[Ft>񺅺P].Mۤ+Ujtq9e]m[[[jnwkp;ven޺;nŽ`Gǻܿv}{A#߹?p[w<==\=<=yL1###cGG]u=z\7yx.FϾCZOgM -}6w['7zI6  F& CaаPf62N.n~5|0ed88mnmo 6.2, 7-=rcaxxx8/`q^3y%xezzk1iε] gq|6N s~T;|k$- MwyC妳Mo!>@;5eqppz뵇 X8AQzƁ5t(8(]`؍GH>{IFD-[y^_\ #Pvw [[sasE?3H}ۅ􎯊lI ݋A`zSn9|ڤ{| Ca(|쁇` 1GwzsgȋIJzXĽ c@EK^o UQ?G?Z6(is>%Ra9I~ܲuKE9?JQ黝G`G4gH?rWB^L-/3 %ljl P2ٛKE논V6S;B\c/:_B(DŽ.^ ?#tAo0CLJ  -[HӇx/{7mb4j1\_w;0"DW~e x/SxSLᅊsa%iP}u)]"#_6)F_b|p6<}O~Q# ިm{DcF /kXğ#3 9!ڰͨli4m$֠센-8]麔Z/Ѡ{rx S< &=E \ٸ{je{N.?jgWa˩^ 6E<޾$Z.@Mߊ!XtQ&(e5\|zQгTpGAOlJ`R))`:_c]Cx6v$AP֚1G~-M͍3K?suЂ@xd@=[/d]LKZ%c*pXFݗ/5vӊIou0;i*BFH7oM׮4-xM`R1QR).♚ߞwب8SjxiSyشt=UQBf=ao)́syhھc.}^m0ˏ:l ^˹synD^%T[m <{ɇak7}}ţ|RLPOyX@TI* ;)1WB^Fgaj瞝q51 Q;j)騯YȫDz-1"NM/*۵pV1oo(<4wxr1t o9C7m ҆Ýa}Qx2kfd䲽nGFⲻCwD]a'w(ܗ ,^$Df-?lFkz'%_O@c <|njm\z >L(EWر5AEN>r$Fp.:v_۰aITMi9ɡ˅m7Eski$3A?fG헦oy֔KYZ-E7N X28HY4A2ʭR,>g[+*jGoѸI>t䜸H"%9UJ~tƃh[(G)gonA6wN{tQ-6[/̐qjy6kLBOwRق1^-i[d$e&4v*-ԄUv8t*qa":(=Jai i:*| 5tӠSiFL:~4vcTHtbia4#1[+tYYֲs?+MbܥV4J  &:s՟9it7Q0 |!`!`~#qZ0;;Kٗo+i+G`ZPڰ9~!QW6l^{x^ˍzљRxgDfps5tEmXM IPÓ$jѪELʕwzFй%_Bw%=]ߘq7)+0cmRiaCE>$pPx53Oo'.iZJPCkU I & ?yŵL]Ɂ"*߂nZi#g"B36*oSa %p$C2g{i!8Y&,\E:1E( B6plõ6NK1n⯿-S\E嵽<ת\Em޷U&kN>9P_ &0-|B;w2-"yfH]xBGhH:q xsߏ/jYG`ֵ#Ծ$}v0 ^aebZdq+  Dg⛗҃{67pGM5y^@e}݋mSW0_G$jLDj׏wOCGv<~4b`#B+r|f Oy)W <[ K{Q _Q,B &[i7kA߰4ĶTI݁woq;Ɣ OpVffҡ3"L'-_@w FU+Q ~s$G} 0X!Mc􇁷!N< )<՚3OjPO1T}Ci *wLUI>O>UkYI]ŎB(”`s>Cb4D\@*D2|Rr`/)g_HǍ70  G I2eߋ?ր }同X`(u5Պk\qܢВ4qD*񻈟8c"+ X]! <=D"5{EuhĉaÈ{Dn&a/N B! i<:H4 syhׇI`{{>x}DiŹƈDF_x<XL 9|$B=2SH O)pgqm*o⸙"Z$ y;`lГ,dA'iؽm$aB C[';|M*o9(:넰OT>!G^d1?,W%VD" &25/Sڐ5A(*!aVZ {"9P$ 'p`V3*G=A{Et5I< erCG(rp;Uquz!"vINp$%_G *`?\04;P3["q3LS0A!MŨ3W|0Mo*ٗ>H¨&&$siK $R+w̯$6'2i}QKt]#" ґo&A]^{6C:x\T'4a8e23 ,f@%w%b`+Υaty) D<+ե#wY^, nI1+ k7[~HyĮM Ƞoxl8&0ӵii}4(܍2`Tx`n!0Cx`!Sϳc~[ގ$~? &w{I,HoKriE"Z~ q?/83 &mrY-1 Q#z"iHͩ[B8ns2 S`/57g.?+w*o ;o.HK0{I"09p z13?Tļ PU]U}?w"h<ɯxbdFVR $, MzM]bff(_-\|ǖOZj4OHC?aw1(tï0شpА&Q]˼A0 C⿇RowlOFniL}" qF ͑|&q%rk +p¤@0AO$͉}o%p( ]!hzJlj*-^bO^A$bSP24I{"SccKSE5ћ7#%m.0@ 0ۉM<)y>] W21 ֔^^A_+)sm:wnm)kn+F%raZ_#A ʝF-N) r3D߷[&. 1%슈6gpJ) L#RNHځaDWoߘc?Di$mjfdrFƬ'a6RF(2FZR_YpadL@@}L qQ?U"I J w8+ )8K!gYso[?Dj[EJgsL峧Oa@*;),O&p&;|C(:Sb1$-8nZwb4GuP!R euVJrx[OM՞;&ME&gssa-o.)A s5 _cY|a" BP lv>F,\ Oh)ڋPq'.cDq/[bX/6m)xs={,t:ӹ&|u!EX]nnk]Pw@wXwZwWSfp6mt7n%nݎu/n޹}t/w wKwkw7w{wc}Ccܳݗt}vr&6ܟtGO_zL#cGGG#czlCxQd°ACxvAH,^?x5EyH^ը9䝮obj qn1=i[dC_rnq4aiŒxmbFF<} ~x/*ԃ?q( T5+-57rsPJ®t%(䩎JB cҾh q>!'5i[4 } _1.!|pRl:;U(/ΰ Eyveֽ2*(,.5{M؈ϫ]˗ YY߽Ei#/keQM⑶r]?jcЦҵin 8C g %%Yvd%,R&Z~TAw) wĺO&C$ȏo?M*Ukߏ-13hVL:m̈Y?R8 N䠙\XvBVSzXU_ؤ8\k5>,GJH&?*n a+DR yuKCD. vɧ6-9#ײA JH$dL/R%7oNTqQu;#u4 {wUU$dd-Ob2ԉF&݌n#bT[5UE{Cgs E3IT3Y)nv7u`'L}iI,᮪8&_LMѭGL5Tzӆ-ڢ s6O L'Zhw o'gB1&$7zEc2 Wk~mmǦY~7녙g,Ќݍ׸ƪͅ$JN Fz̙k e&PC׌oV&Fp>/ЪyPSF%sI [4& =Gl.o]mg}ΠVM kk\CcZ^pb[^7؊XCGJ-ԐK V4ysI2'–tʨÃJx6v͓޸{dnGY$g댔x_ewzy<9%Pu&ͩ;<  _InD rGk¦؛Ո/% j.\B i„Bk܂؉$ֈ BFoeGx9labRtVÐ _ly=3$~J͠Lq\ⲂP+:A|փz/W.Q<GbKpcAKΊ=* "4NDFE`TsʌpgjC*.C09w)gX!V1A.Z">t7+ q1^̙$[f RsZ+zk)Ar$ia8 }U~bE\i0;5Лf_Ouн#';[\6:7+Y8͔B@P;\A Octg㇜~*A[Ξ h0 `Y UU{KKe')`XOJw`qw;q鶊Q  V=65I#o |'2PhëWTJrj;Kӝ$wt?%1tȗoڳWSRgN- $3ÝN7@"{119!_Kn?ϳWL}^h(%#BR*PM yVBջ+h9jz҄d0y<$d܉d%וv5O+4ީeVb+*DZ4{%jC7(utr)C)ry2E?Q'&N.#|2͎@d(JjG8b$͔}b7vZalf7À=yao]H ]C3nyƒTEEŞ"5d6.ƼlBuvH?sӻ[=6,m.ŸbdPNȼ?2@kN`${bN?!k4qkoU?:q2>$O@)U$’\q pzI!LM IAOY#S90l>;v2ōEP#0V[W<jm~_ Ok]rg .*&bi#SKW&sAѻV0.MnA7'BiSiq5׸}q \SA/۷%G5}:Xy h1žTd\x]Bk2dǏ8m!Av-c$/J= tcxmXr`IBH^? R^@sA<91D`Tl\rGI w= j#,I6Ͽ!\؋'! :X|.FfvyLSѺ\+"$٭dr ̧\Eͦ`fr8ȼG%S $|Cx޸=Сwl8J暃ջKK KDQ?,w߶A_e& ]5*Ed>^˶;;&e}{K.o窲.O{h>9QUU 1u 6;tAchOʣj-,%tעµ;d.m"86Y.R!(_\SW)a/LMH%`<3-7JJk^>\,k.4rͅ皋/Qe\O>y^@\sGyǩ}׾ūW.SeAG";n2 ԋoCS,=ڤ}ݿ 8B.Ѽ:jۓxqz8 k@A5ޔ^'B<>g{'aN~̸sPK!V,TiUlADE"HfB iA !,=})bT.QR'}3}~>3s{ιپ9$Ȏnc#}3A8평Y:S pyl?iٶMBQk";POV6-p8.fC!#swЄK'lI[Y %ZTfVɧI)yv̞)(n0YЎB;T!к.Gʼn[MM2]{iL A`0B@.E JUw!  hܟr^CΘ]"zu߬~4(yYl 7dz4 偋Cf#慇YB-Z 예pr_t5Q~~f`Ô($=qEqyPW'D*(DO/bVoũ0A8tQv}7'C4&@!K"Bmk~»#_ >/Gݽs{FykmF&EXq!a-T]MO= o\j| ir -\ .,TeovWimJYm!f< tFXם7{ڶ߼ dׅ5:nRokȜHmzl]~o-5s ^IxfK-#|ZmH,~^5 d6$YPc™(Pfmc8@/H0؟"6տ[3%+x&Fqn8`G͘G#7j*PUfqNŃG ~X8zIX)^Xx-8_*QVk0‰4C3$IJxZI16YMhX\,fb7a"q6=Xyə;~mQ?N/NMff]S#fi}+`N 50M;*-"d^ВVoR Ȟ;TZB:[T@:1xxoe[dtXЗ/qfOtrd0HQZ0^s1*=|:n.߼'y%`EXI,Q^Kl%QYW]r'B 􃍲5iBzjB+5#m26|q%3a x]8XTˍ΍șJa n `On=(FQ 6HddsY5h-ڜվ eFkK=Ұ;./pjB#PdBlff>nCJGr9pO_[E0| E1*-G+dNj=?Ɔ3ĎW1iԿ8/`鹁G4_cHLqy$j['٣JZ0?lIpE^}LhddLR5FȨy鎿noQ&z^hO>_o(U@u`(_vڱWXuϋX[-|[t8XC>D;#F㍸?7wMud"4 ֩ };˹;v,c1<^PC`;ys-Z*:q\0^tK[KQ~W1ɂ;֯hh"AsMfBrɤe\F؄cn3BDyD((3w' P! UBdS/eKUpN4xף|ӝzI/|>(+;uEJ$bk`ŖRvs 7Xk֑ Rd4+Ջ| _DBrr}YaGxqVz,?#LHמQgsB ,E]"؅/⩚t#0BgN+n̋N;F< 1zV&s[%a >|!xb%6UjW.P{=JJ{7e?;c$ ks^xKzWrAK5&Qk9c҂E1[#AJZy˷s5ZB1Ov+Pe7Xʺ: _DQW ?)%oTWPP!7iBghJOsu%ZOل:"Մȏ` ҉"D|+ǘ3*fVbmx(Q@Ri(:q\k'sYDrv= =$ZVM t|ޑw "𹮃`:D!PC1JqFP΃SjOGc*eN TQ3DVtSHAUX rUeQn̗ndtg;N\.돊.QL@ 72̊qc`.2eHz]ҷ/c`0?lb>gapN Fw]xNc__NV~'F> stream x]Mn b"2&YҍQqj; ߾ Ra=\֏+q0E\kg^ h*v(ۖ0q'7Q@_qhp8$>BŻ֥qvI%_[0R6`ݿ=uGaԪdoaRIe3\^+fE,%##\?kf3IzȜ&a4kY[VYR%ɼ'ؿ"t{j#푵-󞿽ƘϏ3G"́T{e endstream endobj 43 0 obj 326 endobj 44 0 obj << /Type /FontDescriptor /FontName /WGAUVT+SourceSansPro-Bold /FontFamily (Source Sans Pro) /Flags 4 /FontBBox [ -457 -316 2157 1008 ] /ItalicAngle 0 /Ascent 984 /Descent -273 /CapHeight 1008 /StemV 80 /StemH 80 /FontFile3 40 0 R >> endobj 9 0 obj << /Type /Font /Subtype /Type1 /BaseFont /WGAUVT+SourceSansPro-Bold /FirstChar 32 /LastChar 128 /FontDescriptor 44 0 R /Encoding /WinAnsiEncoding /Widths [ 0 340 0 0 0 0 0 0 0 0 0 0 300 0 300 0 528 528 528 528 528 528 0 528 528 0 0 0 0 0 0 0 0 0 0 0 0 0 524 638 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 527 0 0 0 518 0 0 0 0 0 0 0 857 0 555 0 0 398 443 383 0 0 0 0 0 0 0 0 0 0 0 528 ] /ToUnicode 42 0 R >> endobj 45 0 obj << /Length 46 0 R /Filter /FlateDecode /Subtype /CIDFontType0C >> stream xwl9n^ L5棚SL1/ x׬齙f{キ$T$$@ @B.C<齿דH>ܫs盙+|?$'ٓ-Ifkfw-mL ]cp;n'yW <[lT7Uu^n+`BKIPGRl- )#͑FZa6vs%lmFfIٙKz`M3lvÒbY GmMg5%f7llgu,1ml#>vu SƱYYY1foZL-=FH5zZ2-6H4[ȿxhx O/B   #EP(0D)FE9<"P** "Q5Ph qxA]C}4@C4Bc4AS4Cs@KBkA[C{t@G$: "=I胾3#)`F"itXaCŽL80㑅 DLdLTLtLl\|,B`c br+NZzlFlflVlvNn^~AaQqIiYy\E\e\ x/*^5W^x;x}|q7q c'O>]|/=7xOS~/pgyoxY}G`X!,¢,Pg $K4˰,1 4XXUX(F3cmƳ [[ ۲۳;2ؙ]ؕLb/fe? 09L#8L(J38vfq,N`6'r's rsgrgsrs2K˘\\tr rs7r7s rswrwsrOO // _|W2:η6|~[6?~9 ~ɯ5>>||=ȟ3n>c>s.|+?+@ ˤ QU1J(L%UJUFeUN*UʪHUW T-E)Z1Uj+^uTWT_ PXMT\-RZmV^Q ꢮJT7uWTzhihɬJV,JUFi(]Vٔ+Sxei5Q4YS4U4]34S4[s4W4_ P9ZZZ\- *SkV^QY[U۴];S[{W_tPtXGtTt\'tRtZgtVt^ .Pbž]9cc'>Kw=9zر[':QXsa,x皙5,+/$?$俀g:yLPh4{ss?3艝v^vzltg+ a[5昂]M&WdpOOGtYWo?K endstream endobj 46 0 obj 1623 endobj 47 0 obj << /Length 48 0 R /Filter /FlateDecode >> stream x]Mj0 >`g!P,C0,r*0 l̳)܀B$ϸˆS$\GWnYim)8j[П".78=49p k7 u1s6AW{c΂9p}s%[liB )$O?1݈kG(2Kd )T=BTp endstream endobj 48 0 obj 223 endobj 49 0 obj << /Type /FontDescriptor /FontName /SPALKP+SourceSansPro-Bold /FontFamily (Source Sans Pro) /Flags 4 /FontBBox [ -457 -316 2157 1008 ] /ItalicAngle 0 /Ascent 984 /Descent -273 /CapHeight 1008 /StemV 80 /StemH 80 /FontFile3 45 0 R >> endobj 50 0 obj << /Type /Font /Subtype /CIDFontType0 /BaseFont /SPALKP+SourceSansPro-Bold /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 49 0 R /W [0 [ 690 200 ]] >> endobj 10 0 obj << /Type /Font /Subtype /Type0 /BaseFont /SPALKP+SourceSansPro-Bold /Encoding /Identity-H /DescendantFonts [ 50 0 R] /ToUnicode 47 0 R >> endobj 51 0 obj << /Length 52 0 R /Filter /FlateDecode /Length1 12272 >> stream xzy[y߽o `{6f}0`̐CDRBmٕ:*N妉oȒ6v]u||Ҵur׵[Z3{fҜ?;{wB!CF|Sy!cg9 }*gch!+kɉG`uS8s~;#R}3С-07v̹G.8}C sb-\xԅcO|ah;Q/K4]Xa?3az]Fr<7r<{h(FP "buqk4yף #FuD ?NR=VA5tjv`hg8,Q6 ;vP4b *ڗez.3ӛ硋td!a8Fa\.y?՘0{N,;5nߢ?Ey4\0csl4x1]Eb8y(77cr <Ţh"zNneR^B9|[Ql>חr?vFZ+MF;ӔmR<:?>,>7udt"_g.m6yKHWF!:}zV괘a<5WU;AQMm: y-O'hXa xj޼hs^y7U X XO;EbLE{_jkxҎb7Qdܾ}Of1[.m0Ͷ`ޔ]k#Y6'#:/֞wf&Sɷ+Uu~pV}zX GՋF5KCj0ƧT4ǃ0,V [ꂜSX< DX(Tc*nDe.'q\dESƶɁ/kÊm^ݫ5{4V}YaE}Nt+N'~ z ǾvxowuEOӅ2HiDc,d8լ4S0ÀG~Yjaak}Ij!6PQ3MoQ?Pf1`zl6g'*tH M$bCCN|;_[t-lH )l?%?9{m+۷ehVZzDiy#4ܬl@T _<  1Ϭhń:۹ a#׮6a[Z!4? wFQz?T5R#ʺCx{̄]X%#@pqlkJC>):&4HGyzFF{e =bN'e#}_k߾(:D'^oEǢ}Շ>X~l׵]fACrrEPo(ρN0V~y"0FֽD9#Ȍomͯ?2xz|pr1dR`QfhaWˏOʫX?+J?DC@TZCaDǸB&Ff6`װu(a:aͲk-kY a Wkkwpc .W,FCd"Ll\+HDwo`|>1ZLnyo[i:5TOQJeqG:iZ6{eBճNunsؓuV2$hh ;Pۿo!F !R6LcP9zh J<e4^?CVX?ZAh<2AtIĒq-T"3ᛍ؂qRw#E@F&;'Od Gy}:tᘳM49i.kGQ:/?t\t<슔g>=04鈿s=:Da0_nͻo?mNz< xM#~y(T1;rCZ>̜;ct,Zbœ'8VI0xp)%I= Yz_:(P]!aOulKFǫ)v0Fa wAH`05p훈F](`O Bmn!.;u/Iџ~G.qS2ңNwӐpPQi^ Y!C'{6 k.S- K;#lrfe[fͥ`X=LcƻsG_)x抒,{ f;aFQrXT@ u|ɨ7v֎x p71koY۷h^B#h0چ9" G0%69ēXnPey^)P2#b8bdMvZ"9AzY,>qKǮvࡳCc^:SɸW`ء#Ns=\=mD78prO釆<44vكpjzkVGSXKdn} ]pBGYP"vr"GV*R`s&̈QoȞ=v鿺utt›X ٞX;9${f.f!1 Ϡ>rȻ 6]*@nF0ؔSPˤoc^vd{ş,;'x\. /܀(4vt63}@0z`t| tħ}3y% Q^r)f!o,]ZG⒩#GBTCp*Bh3 bh')[wNhTL8EE-u|l5=-nǮOzG'N_``J& L͖ X OwS{ /dq_柾8ћ?$P'^b[I9@KD6 prVG3 #*&AE XkO!NQTnިXuDhrirq 9щHLQ) {Wdhjݚ?y}kgk~xgivEzqwj?_6딭/ck˿q|`,Uݷ~9W_LŧE E == I1xR hW Ϊ4+Q1 V2n?- muv{-];6cuѦl}aos`˾ČRWo?G;]#iqkF+0`!Vy\ 'cTaT`=y{wjiQ H]IGyNM[JʷIrcǣF`+>0zqL@Uo vwŒV7~|AW{6O- 'zBEEoDzxoL*RK咉tp1# 0-% bp9m]7!, ~CFo^Q{.1kֺwӑ@t$`ob,.B}j?s Jp$U9Rm+sXbdq}$g<O?QOGgz ;U Yz+ضxa;% ?&uR{by$ z?EkA`$Ct( tQ"޼'jD~A#HS;H/y7Lt)OG#M[>T +3OD#"M/>596w|'5NSH>l+O_MV ci5 il {y8t}Vւ>_~Ū`ƙ[5h`:a;\-hX$Ƒk y.) ͖tV`3Pm٠/{[@Ԙ ]BbV❱ edȝ ܎b lM)9¥yLbXAY-8pqѐrY!GwjTs^!oxvaj46:wk\m}Kl/Ù{A<5X{>OQ8&d~PB4"xCG1g6>2?A} !*t 6-}/?@k`!BZв(j,R*Yn+Մ5And4{ɜe)rJI+NOmJ]DҡʦZq(%Iȁk7_2v-Re-^ k-ӚG'S IO$OA^cÄP[DWIF7+rHhQ*l3rvloPlX,Ma#0i$$=!Лu$SK'OIgɐGd+mr6yK HZLJb2WBZIҮAgk:5m > { Ld}C[ 'B y yA>|3g#N< y%aX. ^^ ZI-Dc8o$w%.)f"!6mi& dG"efzœ>e}Sw GSĨؿ"k}5Ү9#BZ"T;s8ɤ/~v $16jDa4/%O]O0|&d-5\ +7<7(Q--*3ɚ̕nI{jybJBuaT]#)9uql,&Iҕzwy&Wñw +MD&hnԝw# 7u!@/mB5d2>)N+THQ5-0 )}5L!sh1 kv4W En#M8)J%Wav=˞=Ż}%IL '$y(yF| '+4-wÌ"2Ϩ: *:qP' ?)m4#]zH!U`)HɦV5 4i`TP` D-- ݣvzN1OXu PZC@.J7b L , )ONwwNINBi NB"LкJGy &V}\i)3.$qE% NI$ O$axxG[]UZ 3*I7Tf6ޯ*I>c)-Y$RIa`xN% u$ n+s EiZLʚS2^,)Rb_7O!n7bw?b}8<ֵ5߷`gSw1mԁzw/,~/+9Ŀs_o?'zϢD^K5)S(Miψ/P u.h$Ro2PPSm3qo'8w࿪j^ֆu辨ɀ e6f: &bAnTCCߗM^!8@s8@\D| 4, tA7hD3FGU:ŷ- -dzŷQ!=_ 71a?\!q~KfaՃ_W2\u)޾&3虸ɞ?8MM endstream endobj 52 0 obj 7357 endobj 53 0 obj << /Length 54 0 R /Filter /FlateDecode >> stream x]Rn0 +rl+XA+EH¡ 1[j+$3Nvn[?m2{`]uF rűnmvPsE#<\ˇ' ([t'_玷k?0d.F:1K^dć1>H#[5b/ L7Ҍc#gʼn%h(L9 51S cFƀX3)S".1S c@~0kkj״1 .9OX[˞ ؏"?(ʣ.؃"%{(C͵TgS-S͵4ժ8g?zd7e|5FmzTi4݅%*} endstream endobj 54 0 obj 363 endobj 55 0 obj << /Type /FontDescriptor /FontName /ZRHPJE+Pacifico-Regular /FontFamily (Pacifico) /Flags 32 /FontBBox [ -593 -457 1660 1478 ] /ItalicAngle 0 /Ascent 1303 /Descent -453 /CapHeight 1478 /StemV 80 /StemH 80 /FontFile2 51 0 R >> endobj 11 0 obj << /Type /Font /Subtype /TrueType /BaseFont /ZRHPJE+Pacifico-Regular /FirstChar 32 /LastChar 124 /FontDescriptor 55 0 R /Encoding /WinAnsiEncoding /Widths [ 265 0 0 0 0 0 0 0 0 0 0 700 0 0 257 0 0 0 560 520 577 0 0 0 0 541 0 0 0 0 0 0 1014 0 0 0 0 686 0 0 0 0 0 937 0 0 0 0 0 0 0 693 0 0 0 1217 0 0 0 0 0 0 0 0 0 470 0 0 515 393 371 0 0 246 0 525 0 0 496 451 481 0 455 427 413 462 449 0 0 479 412 0 326 ] /ToUnicode 53 0 R >> endobj 56 0 obj << /Length 57 0 R /Filter /FlateDecode /Length1 5328 >> stream xX[l%I$%,R+R2im%%;JS2%NlGy;o5SAS(6?-QȬN P Eڟ()QEa4깻,'v Ι;gf=J3ƎRSc5Mxv&áKQIm >>6:z@!iJ(511>jCy/>[ۛ<=g16F|?X=mJ q&]Rv יc|,2/2  L^%t,vk,73y\ζaAgG2 &|WZBĊ%$ H!JW=iR};m#9v:Ba5:4dzNޓNi]@^Y,mp0i:yFTv|3Ώ()s)Ξ$Ԑ1 #lO"<$kfGE4ؑ7_ z$e2^5~o#xLp@q3j#;#^_`jxFl:v#hE,%b@vˎ dHrҺ^EV(͊e7;=bqZ)E\43BV;oܻ}ǺZNCw{  x%T55M3=O(Mu:iڕ+ln$Zfmk>_kK=/Jsh9#@Q_vF."6~b\א5,;+߶yU!msfo=ʫ˘`*RWoa^((.WVɒbwj5m) VߨRBkQ-._!3DV*9S 93&B2N\PE`Txa 2"%/s*+Va.Y:t!'E(~"l BD]V{E߱1یB B)*XyȑzI"LYrY5m6<S鮊 1+TQ[,U`QiKhD%R)%Z`%E^㊓-ղrAY]F`K* 2Q*y[1KD EZUx.XE-Ե*%E(!BɦHV[d,I> r[+ %E _7% 蠪ȐPov,DQA ;v+hl)ѡϟ(|yPhRS_((읖=8Y2;: 9ў#ʙ~ K0r!NJ%C:2miMi N2Yʈdz}nB:2;w+[!L*(-צPAX*ݜNH t't #P2%tS ݡ2=6Nj{uSvnM76kD55-tlRB6|Lmo >h:X߲c@E|*@|jAGm QG|!>j GmZWgݭcۏW +8i*ތ.v'n=8sMҪU4῔G6}JJOIN*p;RgLW-DZ)|qOBv~z<hSQTJL鮙OTTx H Դ:Gw=\isLJxţiP %]9p,rHӚԱ45m'[\ թF.;Ξr\/no͚Vb|VڳO 'vpϩ5<YX.Xh#N bEr"FNn\B!4PauZh3i֐ZmJY<%!c+-؉RZoU ;%N⍪-JmtUM!7S&gEQ*FpUgi3Ã8]p0t/eu171uS*(X!S}mxS١Sj8>i<{YӜ?)&f4\U%Zn9 x_!QK#- C}Zޙ8>xSL^4GIVgnuLGo7(p ,8qNI8_]henmwxx*,tYО'%ړ@8C`8VCW3_"t_Y~:oE~h<5' $ˡ 6$#78bUz֌ 6ېO`I)iplճڐ6$0AxΆDxކDx[ֻh,6$mHK dC"mHW( $r.)+B,^h>So?}SLuj>M*O9 $sv}6=7?e#5埰ktߔ| =~9CU+ 7_.G}̕{} tqkm ^%uZܻus3kş{e?dy;9/-ֹTr7 /~^gܑT;OkHJtWEx/e9, endstream endobj 57 0 obj 3058 endobj 58 0 obj << /Length 59 0 R /Filter /FlateDecode >> stream x]n <ݡ"I!U%}hɐ@9GYg/~{g#wj:Mˆun@[o5xqiE7HMp5!.Bń&{U> endobj 61 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /PMLOMO+Pacifico-Regular /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 60 0 R /W [0 [ 265 393 394 495 411 484 ]] >> endobj 13 0 obj << /Type /Font /Subtype /Type0 /BaseFont /PMLOMO+Pacifico-Regular /Encoding /Identity-H /DescendantFonts [ 61 0 R] /ToUnicode 58 0 R >> endobj 62 0 obj << /Length 63 0 R /Filter /FlateDecode /Length1 3616 >> stream xV}p{'Y6DQȝ8dL$G`P_,!W ՞L0 v+4 9 L:%@2|t$N'$-N64dM$4;w{{}< @GVK};Ͼ2F@z o*LP2bkĘ[NI'p$"U1 Y~z#Fvc8[A8RsN`P`3'-U> L8q2l!ӛ>XǴCxGL.Yak#Zs'_ZٻyVr5-͋o&בZHn񦡻[:'mX 7"oq#wok{z5|StC,[~Ykz(|5;p7o=vfZ !L _x ^ xvi/|Ss! CpZѝ4q;e"0a X]pan#~od#RTC؅u} ?}g$mk"^ b^؞s?+GP9Cxq dvqYIhh{|#^UBuw׬^kqyg-8:춺5*IM!IM R8t)@ IEԹ>TLn\O=KUObh$7C'=1 !)!K|! e>*n7F3)I ULJ2|nAh4#!plX{T?4%rMZ'  JZRƦĜoZߟC_[/(XWt RW>@}RH^xugCj%Q sT/ULI=/f$.Z}D CTè|'\Tݟd-/V76ib:^mv$*>3&Ӂ9ueCfcZI5 ߛ\Y+EqfV,WÓfKө/)})zζBӺ]nI_' _gѿML F]Bt}\z\r 0ER & {K[߭Q9*[LjTh[>FB~i)ۺ4#F)$_ EEOJS`\RL;-řmL sb]5(?HOڠTN'$m 3bs#R.حEHGk-Od`t&rJ4Xr걊hG@TQSNJnTF\Pi2*1}S0\ab*.w]jM>by`+&ރo81 K'yQXz,a似Wski7+ K&UkKU5|buT&yVre~v%5Oq,fV:uK yԵ"$×Y{N"{c9ߊ[L'rЦ[aC)i#*VuNV<V0[\ W01S 5%gsoEgDZO&XC=f/B#VKFjgxJx-X4vvEl2>vG[2Qy&Ydʏ~gnuz69u`q2M ><8a?~wɯ z F2qR ?!‡jWR]l–Xa`7 zOl=^xwF\)LuFu bw񋄏[[ɿr?#LF_mH4?|qZ.4TTSSg'$o$zLۙ>KRiz 47}iwE2}Is|l6^7=s|=N׎cG -WqCdd,;#cƸ[翣o?Jʹ \C]-H/8>^kNm M=a74/1'f>>sX1ɱխ4(PE!PErY7/;-no(NͶŶfN۰mvVY+a zb&yr0F"~l-M쥞.˱ZBg#@mhrI"BQE$W^HIQ7aad3$͠2TF73J2QȌ"!(g2 ;-#"v%L3qb F+ endstream endobj 63 0 obj 2438 endobj 64 0 obj << /Length 65 0 R /Filter /FlateDecode >> stream x]j0 ~ CqXO!0KƲ=c˙aS6HAs=fTU 6]dqG4?D3pxvq9kKJ?8!e8^{5f&]SDy= \B]Fs2Ј9KxV!N ~.JT|O>BمYM [@XVi9qpr endstream endobj 65 0 obj 226 endobj 66 0 obj << /Type /FontDescriptor /FontName /ITGVDT+LiberationSans /FontFamily (Liberation Sans) /Flags 4 /FontBBox [ -203 -303 1050 910 ] /ItalicAngle 0 /Ascent 905 /Descent -211 /CapHeight 910 /StemV 80 /StemH 80 /FontFile2 62 0 R >> endobj 67 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /ITGVDT+LiberationSans /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 66 0 R /W [0 [ 365 593 ]] >> endobj 12 0 obj << /Type /Font /Subtype /Type0 /BaseFont /ITGVDT+LiberationSans /Encoding /Identity-H /DescendantFonts [ 67 0 R] /ToUnicode 64 0 R >> endobj 68 0 obj << /Length 69 0 R /Filter /FlateDecode /Subtype /Type1C >> stream xzX`,à8;Xbc(Dzo{_l.U."{FSMg|gͽ{=ϥeL&@d%M2EOE?މŌxxx8@%Θ;a]'P5V2Q2M2WT$IH:$=>ɰdLB1_cFFu4j`)NP:@߀JF͢L( j'@RY=1=wM&h*5hjjjZVWkq\m m]mF{vv1CWj?~ACZ6}ct]LMt'}!uS.pv A/Cau:Bg·:sux׹.ԝ|kttfVѽToRXQ$HSiңVi_z_Jg7Koz6K;wB^^%o~i7ߨE[O?X?^Au?N g0`AAAAAA9^! dL&ddVLe2,RW_vT#˓*enٰG /eF(Bf)cX0$2t3%L%S˴3km yƨ ņ!c8P0 2\opanÃ' Ol-h}np6T%ܵ:A"o#:csz*N?{Bh? )Md\_3i؏@FAzIWO-U-gZM !XW"@[O2<`n!t:Xm}gXR%xKA#\5jb SݹH {+G@GUgBKK#Ks)JT!}+4_~@2LJ?!Wշ#B0怋s?w2P7h}ȐކK(90yƸ|m>"X{+Vᠸ6*ףiH ~Z T Kٯj$^x HH]GpDysՊe3n^u^TM ߵfX35q_ke.l)e7Z5ߺ>V/wZ|B(sySXW]!uW^'T׃~܌Ys9-nR?%?g%hx)S>TS(ueYe\}QW|! 9KyU#aqM!'SN):5[._uG c[d֡fa;pMQBO#hv7 fVeW# jeoH6"eHaaOQW^jcW*BV<^hvr*u`Ju~kMɃnݟeR/rt|N`o/E7(=[_5yݰ/txg4N\ȡ^z+*‘%1zJǹւh=yU2f<}4WQkS}-WDI Ar4ai3*F Ч xp{ Z mFj]K .UvS'v#gsӊR[AFbzRf-YTq_O,q-dGl4Ԡ=s̭=>ڵa x0G~,]&[t+fչ%F kp/ℾ4Б#Hj)Bd%E<Ǜ,ƿcW t}5SJV 0֗}d,7cU;Hhۨl>`cb>-aqw` ӿ\[Y(wrVHCbp`d=<㴋gjЍWX>07\ Q6 ,V4T P@’Tu uKN [Y:m -RHxL0k~k;x -)(.)ω@ EP?pE4a [BVQnph" R05ԝ:].D  nkI9V\*0b3aNu7q-wy'LNKKU,=HI= 4^hrse 0_K LY6j2 "g}U5P7?؛-8CHQ&)j\߃B-l{֣74{}*b;wʝ΅*Q;)r/Mc1Og x*1wtʺ "A#Lai[xu7%UD n$O,Dх˲M&Ib\yzoi˼#f6qFϮ3?E!چrlXb l5FRa{,pTP!0;3Ryъ-<.,dZ @KO =!^}@9y>` gvgow+696s.棓Bh&F&?|>Dpr97GÁn5͍; ^2?фC iLzNF i8 Cx6/H_bCs?p=O;bmu퇄)`]j,㡬'uIG]QdzWe]#_ɿ5dukTw7pWܭښ0eKy[[w`~o8)(`d->BP{D#^%Kk[3)9B)ngxkUWҫsNW@(SN#ZVR W$s+#w3|nFF=BRZ|@`GC`E*2ע;u;dq"iwJ07pr;ۈ>Z iD)8df|+T4ǘV#8i)|׭ں1M8\UV krf?ܥV41OF~;Yh~Vs9v[<ȪLicIIRd7.$ԅ <]LB;ջ(v?jvQQEI&Z_AUb5qxWH!&)dhQ t…?>TwƊ]ܽ*8#itd 9LSqypTU8BGԹva$ӡTE8kb ɠ-+=ߚӆ1x LB8 ?RD:,P|!.U 刘]娪e 28\`}8%@?!I^ެPxzЗV8X+6/ҰC^哗e$/F;dO~JIհiWr6;bcfW+4ke*g)dRJa% ) P/}Vv<%V)K>-l|+RӃHKe sm}KC蹼JbUD 2ߑTx3x0WhiA̋wHxi+/x3䕄J'@yA3^̳x*dɖ='#Nj_=1k+èְ7g:p,KG,]iI'^)8[X S&|9j ɒ3](9%i|1CcFn"'/4^lA&ȣ)_*:K]RQ47iZkzjjfkh^ռ7M5_kZvZ>Z!Z{ ~UC;P;Avo A'5PNp Ctlq щIѹLw"]J]kO=ݗ]R tDj#͔6KJH_Xo^^^^E7z}ͅ]=C#goѿPGd9K 0Xo`fj`mAA[ 2zlLf- )eYlDv[OFe ɌάdV353qIcҙM>yihhlÕ m C c G OV7l32e++eX~e+-%zldY)-gaa_oYl4HHjdh4Ha4h2#S#s#;#O@0hFe6*4*327j643l4btC#<Lԛ8y"?qę(Z^+.kA{'xs/brt:YW/.cOKltw TLEmOg@ xB d&0Ɵ?bqPߢr|IB ҉u~#|x_Օ!A7q{RrxjB#7*;WJwQ_4›@Dg=e!m- t=+5~֍+ SHw˖:ؗ{v{[{oW+@Ɔ-huE_# j|ͶKm.`E]9{n=PP9ڄ;NNRiD%Lq1>`~T)nRsn--|7Vg0/^D`'݃<㰋ghF8km Y{BFk:iw X%*i냁vU-k\] kk[B*΃^;Kr X,1#q-;8ZA?\wl+hB;ܳyY\SYν(p䥦3) Hp4pbcצTCo FtfJb}C*[Nrr BܗL2ZJ`9s˙deO>{oOl: ^P/Yo ;գE^unB<+rySoTsFN6J9S%/<]pbo|i?yKNź5&!AGXIp|f5`~öy[;6 3mFȍ|=A٪E~񺌗a- % į Yg@z+*/ϵ6JqKւĐJ ʊrydf">'0UgנB4m+&Ԥ;C o)4ez PtXPxh n$SV=(3Z3/D<]r>KIHD'h:O:OP|:vWbCaC!6k7AAQ°]'eƒ|%{s`]t:7t}p#A|ɎkHrF@,uw%A|Vo 'pc&bKD4%X&r.o݋'bczUQ6: LMZ ۷q(ų?_$!!-Nw+wy8{98Սݗ{ʷ5i dԲ eUUAA~G{˃h {s=AoŽ53E;m40S jZnCEPw   $JVd5ЖgjvFȁDwh>vk[Kb>;ZF^Nrs rR!8ZzX=+eiEp!4g%j%u䟯)60ΫR+LKN;s䑃38B}@[n(ھt-K#Y3ΑI8m 5t~Ղa42;.(o8XW>}m-+*)+N=)ќc\CYO яQ^~[^g~C9I)B{-*yXHwsWBRwiQd0F!NYS$ՃĤyhO&NEY9(h5_> hC~>[uʌ$Z&lH1I٬OCSh&; E `E!1)ʉd-5, ;7g&z!Y6Ӌha?T ji/)QTON!spTl5M 1>\7p\2({Ӓ;W\@p``l SstbeE%3m"1,ҽ1%A!4-xWRVN" Ae,v_-U0.!q$L^0X-)ے";R]#7ߡ B0:œ d7 _UGBL=]щ~EϼFkhˇHkge}cߘL5{߱8o *jmf;rc1s_XX4^}I%M*gTK$wۃJ#ۗAy_"áHN[ yFU,VZ_P>~GhF.e tH@KmZp-iFf]CiiIջtҮEWPZ3*F_ߓ/ s4˟(Å K}B@acqVwyUhjv O$hj"PP}.@ CSܼEteE!/}z_##|:weHOTFF&Ղ }mSE8^Zu\9N'y|}.$'h,Q `=wPΉ{\$Gޤ :9QU >J(ÂH2_]vg|Lv g#-O =_١!+nU"Mj|'@QM"ag޺wn& xb{c+#ɒsڑ 4|rDNS:'agϢKn 0RS)WYİn5 B!0Bgzv"G^KL…dPn{Q~QSqf#Q6.]B7l{I}wrޝAg` eJ(7XYi#KSc- ٽ#E *k۹ܔB)]ppdǑB}_7^y' %ǒ SR!DKI9< %JY鹒i)[N!֗hzXH%_o-n $!zחrA)Hxbw  eC|kuЇĩԿZ4&y l$ GEEnH|xEtm.޹C< tʹ)Kf=} (ntӹkR~x,ȥB[E<<4Ь.Zr]ȅ?{Z5>?D'}4zJɵ7]K_) NAyuS,rXܸ􃇎("I(s4 ~8+Ub쭪`ﷴT5wZu*KfB"Dc TqWY&ngyG`W/Pp<b<<,9 pwZ"2!Bf }C&H6P-hnV?${QhF34m8-:rW;.6!=cI%2Mf#2KeaJͦ&yO8)*@C!jՖOW O|uI~HtJp).1c&/'r xX4iZP]TFAp1ZDr^P9?J2__9$ꩊQMo)sHϜT:4iɣO_M_8EKqAUx2( u˺Ab])S޺ ڠd!zyHOXAU4x @Cէ49/uzj`$F,?]PS8L%{n ӒR!5sa- .5/5R&hLM=I)8~촐Rw+% Ȑ9dh)prb/hʋ!Jeˑx]ޝJ+ZlqRm,4:Ux([[ޅFܰpb<6҄p4O~$3~.fDrfξ>L+ m7(T>!]v Bƒhs=3M_4d)m_fac.^by;Ð &m7(H"hK߉PrŚ=LV *aH4-o ؓ1a1ytgOtq$l75V$H҂uBpha=2 <ވ&wg(E9穫gB?ZV.7݄r7LHJOQYQH6S0F`0?; N<-(&:.2P(xCt)Ted խ- ZS#Õ{j2(Smk\NcT% T*{)#gbn4 X(8>`=hv RۜKs(i1Vޥe?dPGuPY$Qq}yWhJe0@!vܹ2XyYDa``DDP`!?(=BMϩyװKdy$4BmEĭ(j}$oW\#YEN>E]³[xoACؙ+(ve# @ P'hT͓ ̬={T!XwYlCDʡ.L$1Re@K+s!Rj$wZ9rO]s;o+5Rw>mQ1dlF ͂C&Cb_$A* HoZF endstream endobj 69 0 obj 11788 endobj 70 0 obj << /Length 71 0 R /Filter /FlateDecode >> stream x]n wu8D Qd50)R!o_3>dCuk"T#hcUmA"L8].³F\:>ưI ToAa0vu,G.h#pPu/¿㠨n~$۟sMҒt W/$agd=tZ WyLZ~&)//0&>>7<3=֙)))ohحbzr M?'W^' endstream endobj 71 0 obj 270 endobj 72 0 obj << /Type /FontDescriptor /FontName /GDKIPY+SourceSansPro-It /FontFamily (Source Sans Pro) /Flags 4 /FontBBox [ -323 -291 2077 969 ] /ItalicAngle 0 /Ascent 984 /Descent -273 /CapHeight 969 /StemV 80 /StemH 80 /FontFile3 68 0 R >> endobj 22 0 obj << /Type /Font /Subtype /Type1 /BaseFont /GDKIPY+SourceSansPro-It /FirstChar 32 /LastChar 122 /FontDescriptor 72 0 R /Encoding /WinAnsiEncoding /Widths [ 200 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 510 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 536 0 0 481 0 531 523 0 0 0 0 0 525 515 0 0 0 0 0 528 0 0 0 0 410 ] /ToUnicode 70 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R 14 0 R 18 0 R ] /Count 3 >> endobj 73 0 obj << /Type /Outlines /First 23 0 R /Last 23 0 R /Count -1 >> endobj 23 0 obj << /Title (Schlussrechnung 7-2019) /Parent 73 0 R /F 0 /Dest [2 0 R /XYZ 68 591 0] >> endobj 74 0 obj << /Names [ (information) [2 0 R /XYZ 380 731 0] (items) [2 0 R /XYZ 68 451 0] (letterheader) [2 0 R /XYZ 68 751 0] (to) [2 0 R /XYZ 68 730 0] (total) [18 0 R /XYZ 380 529 0] ] >> endobj 75 0 obj << /Dests 74 0 R >> endobj 76 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /Title (Invoice) /Author (Klaas Freitag) /Subject (Kraft Invoice document) /Keywords () /CreationDate (D:20200315114801+01'00) >> endobj 77 0 obj << /Type /Catalog /Pages 1 0 R /Outlines 73 0 R /Names 75 0 R >> endobj xref 0 78 0000000000 65535 f 0000092370 00000 n 0000003060 00000 n 0000002814 00000 n 0000000015 00000 n 0000002791 00000 n 0000030656 00000 n 0000034341 00000 n 0000036834 00000 n 0000059686 00000 n 0000062744 00000 n 0000071131 00000 n 0000079223 00000 n 0000075655 00000 n 0000005009 00000 n 0000004820 00000 n 0000003278 00000 n 0000004796 00000 n 0000007585 00000 n 0000007356 00000 n 0000005230 00000 n 0000007332 00000 n 0000091950 00000 n 0000092533 00000 n 0000007806 00000 n 0000029699 00000 n 0000029724 00000 n 0000030350 00000 n 0000030373 00000 n 0000031460 00000 n 0000033445 00000 n 0000033469 00000 n 0000033785 00000 n 0000033808 00000 n 0000034091 00000 n 0000034512 00000 n 0000036141 00000 n 0000036165 00000 n 0000036544 00000 n 0000036567 00000 n 0000037255 00000 n 0000058951 00000 n 0000058976 00000 n 0000059381 00000 n 0000059404 00000 n 0000060141 00000 n 0000061870 00000 n 0000061894 00000 n 0000062196 00000 n 0000062219 00000 n 0000062501 00000 n 0000062913 00000 n 0000070367 00000 n 0000070391 00000 n 0000070833 00000 n 0000070856 00000 n 0000071598 00000 n 0000074752 00000 n 0000074776 00000 n 0000075101 00000 n 0000075124 00000 n 0000075398 00000 n 0000075822 00000 n 0000078356 00000 n 0000078380 00000 n 0000078685 00000 n 0000078708 00000 n 0000078984 00000 n 0000079388 00000 n 0000091275 00000 n 0000091300 00000 n 0000091649 00000 n 0000091672 00000 n 0000092449 00000 n 0000092644 00000 n 0000092857 00000 n 0000092893 00000 n 0000093110 00000 n trailer << /Size 78 /Root 77 0 R /Info 76 0 R >> startxref 93200 %%EOF kraft-1.1/reports/xrechnung.xrtmpl000066400000000000000000000136611450127457600174530ustar00rootroot00000000000000 urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.0 {{ doc.ident }} {{ doc.dateStrISO }} {{ doc.dueDateStrISO }} 380 EUR EUR {{ doc.buyerReference }} {{ doc.projectLabel }} Hans Kraft Str. 1 Berlin 12322 DE DE343244324 VAT DE343244324 Goofy Enterprises Goofy Cerbuchcicz +49 321 23321 goofy@kraft.de {{ customer.STREET}} {{ customer.LOCALITY }} {{ customer.POSTCODE }} DE {{ customer.ORGANISATION }} {{ customer.NAME }} {% if costumer.EMAIL %} {{ customer.EMAIL }} {% endif %} {% if customer.PHONE %} {{ customer.PHONE }} {% endif %} 30 DE55700126000032144324 Goofy Enterprises SUSKDEM1XXX {{ doc.taxSumNum }} {{ doc.nettoSumNum }} {{ doc.taxSumNum }} S {{ doc.fullTaxPercentNum }} VAT {{ doc.nettoSumNum }} {{ doc.nettoSumNum }} {{ doc.bruttoSumNum }} 0.00 0.00 0.00 {{ doc.bruttoSumNum }} {% for item in doc.items %} {{ item.itemNumber }} {{ item.amountNum }} {{ item.nettoPriceNum }} {{ item.htmlText }} {{ item.htmlText }} {{ item.itemNumber }} S {{ doc.fullTaxPercentNum }} VAT {{ item.nettoPriceNum }} {% endfor %} kraft-1.1/src/000077500000000000000000000000001450127457600132645ustar00rootroot00000000000000kraft-1.1/src/3rdparty/000077500000000000000000000000001450127457600150345ustar00rootroot00000000000000kraft-1.1/src/3rdparty/qrcodegen.cpp000066400000000000000000000652721450127457600175230ustar00rootroot00000000000000/* * QR Code generator library (C++) * * Copyright (c) Project Nayuki. (MIT License) * https://www.nayuki.io/page/qr-code-generator-library * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * - The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * - The Software is provided "as is", without warranty of any kind, express or * implied, including but not limited to the warranties of merchantability, * fitness for a particular purpose and noninfringement. In no event shall the * authors or copyright holders be liable for any claim, damages or other * liability, whether in an action of contract, tort or otherwise, arising from, * out of or in connection with the Software or the use or other dealings in the * Software. */ #include #include #include #include #include #include #include #include #include "qrcodegen.hpp" using std::int8_t; using std::uint8_t; using std::size_t; using std::vector; namespace qrcodegen { /*---- Class QrSegment ----*/ QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) : modeBits(mode) { numBitsCharCount[0] = cc0; numBitsCharCount[1] = cc1; numBitsCharCount[2] = cc2; } int QrSegment::Mode::getModeBits() const { return modeBits; } int QrSegment::Mode::numCharCountBits(int ver) const { return numBitsCharCount[(ver + 7) / 17]; } const QrSegment::Mode QrSegment::Mode::NUMERIC (0x1, 10, 12, 14); const QrSegment::Mode QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13); const QrSegment::Mode QrSegment::Mode::BYTE (0x4, 8, 16, 16); const QrSegment::Mode QrSegment::Mode::KANJI (0x8, 8, 10, 12); const QrSegment::Mode QrSegment::Mode::ECI (0x7, 0, 0, 0); QrSegment QrSegment::makeBytes(const vector &data) { if (data.size() > static_cast(INT_MAX)) throw std::length_error("Data too long"); BitBuffer bb; for (uint8_t b : data) bb.appendBits(b, 8); return QrSegment(Mode::BYTE, static_cast(data.size()), std::move(bb)); } QrSegment QrSegment::makeNumeric(const char *digits) { BitBuffer bb; int accumData = 0; int accumCount = 0; int charCount = 0; for (; *digits != '\0'; digits++, charCount++) { char c = *digits; if (c < '0' || c > '9') throw std::domain_error("String contains non-numeric characters"); accumData = accumData * 10 + (c - '0'); accumCount++; if (accumCount == 3) { bb.appendBits(static_cast(accumData), 10); accumData = 0; accumCount = 0; } } if (accumCount > 0) // 1 or 2 digits remaining bb.appendBits(static_cast(accumData), accumCount * 3 + 1); return QrSegment(Mode::NUMERIC, charCount, std::move(bb)); } QrSegment QrSegment::makeAlphanumeric(const char *text) { BitBuffer bb; int accumData = 0; int accumCount = 0; int charCount = 0; for (; *text != '\0'; text++, charCount++) { const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text); if (temp == nullptr) throw std::domain_error("String contains unencodable characters in alphanumeric mode"); accumData = accumData * 45 + static_cast(temp - ALPHANUMERIC_CHARSET); accumCount++; if (accumCount == 2) { bb.appendBits(static_cast(accumData), 11); accumData = 0; accumCount = 0; } } if (accumCount > 0) // 1 character remaining bb.appendBits(static_cast(accumData), 6); return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb)); } vector QrSegment::makeSegments(const char *text) { // Select the most efficient segment encoding automatically vector result; if (*text == '\0'); // Leave result empty else if (isNumeric(text)) result.push_back(makeNumeric(text)); else if (isAlphanumeric(text)) result.push_back(makeAlphanumeric(text)); else { vector bytes; for (; *text != '\0'; text++) bytes.push_back(static_cast(*text)); result.push_back(makeBytes(bytes)); } return result; } QrSegment QrSegment::makeEci(long assignVal) { BitBuffer bb; if (assignVal < 0) throw std::domain_error("ECI assignment value out of range"); else if (assignVal < (1 << 7)) bb.appendBits(static_cast(assignVal), 8); else if (assignVal < (1 << 14)) { bb.appendBits(2, 2); bb.appendBits(static_cast(assignVal), 14); } else if (assignVal < 1000000L) { bb.appendBits(6, 3); bb.appendBits(static_cast(assignVal), 21); } else throw std::domain_error("ECI assignment value out of range"); return QrSegment(Mode::ECI, 0, std::move(bb)); } QrSegment::QrSegment(const Mode &md, int numCh, const std::vector &dt) : mode(&md), numChars(numCh), data(dt) { if (numCh < 0) throw std::domain_error("Invalid value"); } QrSegment::QrSegment(const Mode &md, int numCh, std::vector &&dt) : mode(&md), numChars(numCh), data(std::move(dt)) { if (numCh < 0) throw std::domain_error("Invalid value"); } int QrSegment::getTotalBits(const vector &segs, int version) { int result = 0; for (const QrSegment &seg : segs) { int ccbits = seg.mode->numCharCountBits(version); if (seg.numChars >= (1L << ccbits)) return -1; // The segment's length doesn't fit the field's bit width if (4 + ccbits > INT_MAX - result) return -1; // The sum will overflow an int type result += 4 + ccbits; if (seg.data.size() > static_cast(INT_MAX - result)) return -1; // The sum will overflow an int type result += static_cast(seg.data.size()); } return result; } bool QrSegment::isNumeric(const char *text) { for (; *text != '\0'; text++) { char c = *text; if (c < '0' || c > '9') return false; } return true; } bool QrSegment::isAlphanumeric(const char *text) { for (; *text != '\0'; text++) { if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr) return false; } return true; } const QrSegment::Mode &QrSegment::getMode() const { return *mode; } int QrSegment::getNumChars() const { return numChars; } const std::vector &QrSegment::getData() const { return data; } const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; /*---- Class QrCode ----*/ int QrCode::getFormatBits(Ecc ecl) { switch (ecl) { case Ecc::LOW : return 1; case Ecc::MEDIUM : return 0; case Ecc::QUARTILE: return 3; case Ecc::HIGH : return 2; default: throw std::logic_error("Unreachable"); } } QrCode QrCode::encodeText(const char *text, Ecc ecl) { vector segs = QrSegment::makeSegments(text); return encodeSegments(segs, ecl); } QrCode QrCode::encodeBinary(const vector &data, Ecc ecl) { vector segs{QrSegment::makeBytes(data)}; return encodeSegments(segs, ecl); } QrCode QrCode::encodeSegments(const vector &segs, Ecc ecl, int minVersion, int maxVersion, int mask, bool boostEcl) { if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7) throw std::invalid_argument("Invalid value"); // Find the minimal version number to use int version, dataUsedBits; for (version = minVersion; ; version++) { int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available dataUsedBits = QrSegment::getTotalBits(segs, version); if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) break; // This version number is found to be suitable if (version >= maxVersion) { // All versions in the range could not fit the given data std::ostringstream sb; if (dataUsedBits == -1) sb << "Segment too long"; else { sb << "Data length = " << dataUsedBits << " bits, "; sb << "Max capacity = " << dataCapacityBits << " bits"; } throw data_too_long(sb.str()); } } assert(dataUsedBits != -1); // Increase the error correction level while the data still fits in the current version number for (Ecc newEcl : {Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8) ecl = newEcl; } // Concatenate all segments to create the data bit string BitBuffer bb; for (const QrSegment &seg : segs) { bb.appendBits(static_cast(seg.getMode().getModeBits()), 4); bb.appendBits(static_cast(seg.getNumChars()), seg.getMode().numCharCountBits(version)); bb.insert(bb.end(), seg.getData().begin(), seg.getData().end()); } assert(bb.size() == static_cast(dataUsedBits)); // Add terminator and pad up to a byte if applicable size_t dataCapacityBits = static_cast(getNumDataCodewords(version, ecl)) * 8; assert(bb.size() <= dataCapacityBits); bb.appendBits(0, std::min(4, static_cast(dataCapacityBits - bb.size()))); bb.appendBits(0, (8 - static_cast(bb.size() % 8)) % 8); assert(bb.size() % 8 == 0); // Pad with alternating bytes until data capacity is reached for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11) bb.appendBits(padByte, 8); // Pack bits into bytes in big endian vector dataCodewords(bb.size() / 8); for (size_t i = 0; i < bb.size(); i++) dataCodewords.at(i >> 3) |= (bb.at(i) ? 1 : 0) << (7 - (i & 7)); // Create the QR Code object return QrCode(version, ecl, dataCodewords, mask); } QrCode::QrCode(int ver, Ecc ecl, const vector &dataCodewords, int msk) : // Initialize fields and check arguments version(ver), errorCorrectionLevel(ecl) { if (ver < MIN_VERSION || ver > MAX_VERSION) throw std::domain_error("Version value out of range"); if (msk < -1 || msk > 7) throw std::domain_error("Mask value out of range"); size = ver * 4 + 17; size_t sz = static_cast(size); modules = vector >(sz, vector(sz)); // Initially all light isFunction = vector >(sz, vector(sz)); // Compute ECC, draw modules drawFunctionPatterns(); const vector allCodewords = addEccAndInterleave(dataCodewords); drawCodewords(allCodewords); // Do masking if (msk == -1) { // Automatically choose best mask long minPenalty = LONG_MAX; for (int i = 0; i < 8; i++) { applyMask(i); drawFormatBits(i); long penalty = getPenaltyScore(); if (penalty < minPenalty) { msk = i; minPenalty = penalty; } applyMask(i); // Undoes the mask due to XOR } } assert(0 <= msk && msk <= 7); mask = msk; applyMask(msk); // Apply the final choice of mask drawFormatBits(msk); // Overwrite old format bits isFunction.clear(); isFunction.shrink_to_fit(); } int QrCode::getVersion() const { return version; } int QrCode::getSize() const { return size; } QrCode::Ecc QrCode::getErrorCorrectionLevel() const { return errorCorrectionLevel; } int QrCode::getMask() const { return mask; } bool QrCode::getModule(int x, int y) const { return 0 <= x && x < size && 0 <= y && y < size && module(x, y); } void QrCode::drawFunctionPatterns() { // Draw horizontal and vertical timing patterns for (int i = 0; i < size; i++) { setFunctionModule(6, i, i % 2 == 0); setFunctionModule(i, 6, i % 2 == 0); } // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) drawFinderPattern(3, 3); drawFinderPattern(size - 4, 3); drawFinderPattern(3, size - 4); // Draw numerous alignment patterns const vector alignPatPos = getAlignmentPatternPositions(); size_t numAlign = alignPatPos.size(); for (size_t i = 0; i < numAlign; i++) { for (size_t j = 0; j < numAlign; j++) { // Don't draw on the three finder corners if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))) drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j)); } } // Draw configuration data drawFormatBits(0); // Dummy mask value; overwritten later in the constructor drawVersion(); } void QrCode::drawFormatBits(int msk) { // Calculate error correction code and pack bits int data = getFormatBits(errorCorrectionLevel) << 3 | msk; // errCorrLvl is uint2, msk is uint3 int rem = data; for (int i = 0; i < 10; i++) rem = (rem << 1) ^ ((rem >> 9) * 0x537); int bits = (data << 10 | rem) ^ 0x5412; // uint15 assert(bits >> 15 == 0); // Draw first copy for (int i = 0; i <= 5; i++) setFunctionModule(8, i, getBit(bits, i)); setFunctionModule(8, 7, getBit(bits, 6)); setFunctionModule(8, 8, getBit(bits, 7)); setFunctionModule(7, 8, getBit(bits, 8)); for (int i = 9; i < 15; i++) setFunctionModule(14 - i, 8, getBit(bits, i)); // Draw second copy for (int i = 0; i < 8; i++) setFunctionModule(size - 1 - i, 8, getBit(bits, i)); for (int i = 8; i < 15; i++) setFunctionModule(8, size - 15 + i, getBit(bits, i)); setFunctionModule(8, size - 8, true); // Always dark } void QrCode::drawVersion() { if (version < 7) return; // Calculate error correction code and pack bits int rem = version; // version is uint6, in the range [7, 40] for (int i = 0; i < 12; i++) rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); long bits = static_cast(version) << 12 | rem; // uint18 assert(bits >> 18 == 0); // Draw two copies for (int i = 0; i < 18; i++) { bool bit = getBit(bits, i); int a = size - 11 + i % 3; int b = i / 3; setFunctionModule(a, b, bit); setFunctionModule(b, a, bit); } } void QrCode::drawFinderPattern(int x, int y) { for (int dy = -4; dy <= 4; dy++) { for (int dx = -4; dx <= 4; dx++) { int dist = std::max(std::abs(dx), std::abs(dy)); // Chebyshev/infinity norm int xx = x + dx, yy = y + dy; if (0 <= xx && xx < size && 0 <= yy && yy < size) setFunctionModule(xx, yy, dist != 2 && dist != 4); } } } void QrCode::drawAlignmentPattern(int x, int y) { for (int dy = -2; dy <= 2; dy++) { for (int dx = -2; dx <= 2; dx++) setFunctionModule(x + dx, y + dy, std::max(std::abs(dx), std::abs(dy)) != 1); } } void QrCode::setFunctionModule(int x, int y, bool isDark) { size_t ux = static_cast(x); size_t uy = static_cast(y); modules .at(uy).at(ux) = isDark; isFunction.at(uy).at(ux) = true; } bool QrCode::module(int x, int y) const { return modules.at(static_cast(y)).at(static_cast(x)); } vector QrCode::addEccAndInterleave(const vector &data) const { if (data.size() != static_cast(getNumDataCodewords(version, errorCorrectionLevel))) throw std::invalid_argument("Invalid argument"); // Calculate parameter numbers int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast(errorCorrectionLevel)][version]; int blockEccLen = ECC_CODEWORDS_PER_BLOCK [static_cast(errorCorrectionLevel)][version]; int rawCodewords = getNumRawDataModules(version) / 8; int numShortBlocks = numBlocks - rawCodewords % numBlocks; int shortBlockLen = rawCodewords / numBlocks; // Split data into blocks and append ECC to each block vector > blocks; const vector rsDiv = reedSolomonComputeDivisor(blockEccLen); for (int i = 0, k = 0; i < numBlocks; i++) { vector dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1))); k += static_cast(dat.size()); const vector ecc = reedSolomonComputeRemainder(dat, rsDiv); if (i < numShortBlocks) dat.push_back(0); dat.insert(dat.end(), ecc.cbegin(), ecc.cend()); blocks.push_back(std::move(dat)); } // Interleave (not concatenate) the bytes from every block into a single sequence vector result; for (size_t i = 0; i < blocks.at(0).size(); i++) { for (size_t j = 0; j < blocks.size(); j++) { // Skip the padding byte in short blocks if (i != static_cast(shortBlockLen - blockEccLen) || j >= static_cast(numShortBlocks)) result.push_back(blocks.at(j).at(i)); } } assert(result.size() == static_cast(rawCodewords)); return result; } void QrCode::drawCodewords(const vector &data) { if (data.size() != static_cast(getNumRawDataModules(version) / 8)) throw std::invalid_argument("Invalid argument"); size_t i = 0; // Bit index into the data // Do the funny zigzag scan for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair if (right == 6) right = 5; for (int vert = 0; vert < size; vert++) { // Vertical counter for (int j = 0; j < 2; j++) { size_t x = static_cast(right - j); // Actual x coordinate bool upward = ((right + 1) & 2) == 0; size_t y = static_cast(upward ? size - 1 - vert : vert); // Actual y coordinate if (!isFunction.at(y).at(x) && i < data.size() * 8) { modules.at(y).at(x) = getBit(data.at(i >> 3), 7 - static_cast(i & 7)); i++; } // If this QR Code has any remainder bits (0 to 7), they were assigned as // 0/false/light by the constructor and are left unchanged by this method } } } assert(i == data.size() * 8); } void QrCode::applyMask(int msk) { if (msk < 0 || msk > 7) throw std::domain_error("Mask value out of range"); size_t sz = static_cast(size); for (size_t y = 0; y < sz; y++) { for (size_t x = 0; x < sz; x++) { bool invert; switch (msk) { case 0: invert = (x + y) % 2 == 0; break; case 1: invert = y % 2 == 0; break; case 2: invert = x % 3 == 0; break; case 3: invert = (x + y) % 3 == 0; break; case 4: invert = (x / 3 + y / 2) % 2 == 0; break; case 5: invert = x * y % 2 + x * y % 3 == 0; break; case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break; case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break; default: throw std::logic_error("Unreachable"); } modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x)); } } } long QrCode::getPenaltyScore() const { long result = 0; // Adjacent modules in row having same color, and finder-like patterns for (int y = 0; y < size; y++) { bool runColor = false; int runX = 0; std::array runHistory = {}; for (int x = 0; x < size; x++) { if (module(x, y) == runColor) { runX++; if (runX == 5) result += PENALTY_N1; else if (runX > 5) result++; } else { finderPenaltyAddHistory(runX, runHistory); if (!runColor) result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; runColor = module(x, y); runX = 1; } } result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3; } // Adjacent modules in column having same color, and finder-like patterns for (int x = 0; x < size; x++) { bool runColor = false; int runY = 0; std::array runHistory = {}; for (int y = 0; y < size; y++) { if (module(x, y) == runColor) { runY++; if (runY == 5) result += PENALTY_N1; else if (runY > 5) result++; } else { finderPenaltyAddHistory(runY, runHistory); if (!runColor) result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; runColor = module(x, y); runY = 1; } } result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3; } // 2*2 blocks of modules having same color for (int y = 0; y < size - 1; y++) { for (int x = 0; x < size - 1; x++) { bool color = module(x, y); if ( color == module(x + 1, y) && color == module(x, y + 1) && color == module(x + 1, y + 1)) result += PENALTY_N2; } } // Balance of dark and light modules int dark = 0; for (const vector &row : modules) { for (bool color : row) { if (color) dark++; } } int total = size * size; // Note that size is odd, so dark/total != 1/2 // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)% int k = static_cast((std::abs(dark * 20L - total * 10L) + total - 1) / total) - 1; assert(0 <= k && k <= 9); result += k * PENALTY_N4; assert(0 <= result && result <= 2568888L); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4 return result; } vector QrCode::getAlignmentPatternPositions() const { if (version == 1) return vector(); else { int numAlign = version / 7 + 2; int step = (version == 32) ? 26 : (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2; vector result; for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step) result.insert(result.begin(), pos); result.insert(result.begin(), 6); return result; } } int QrCode::getNumRawDataModules(int ver) { if (ver < MIN_VERSION || ver > MAX_VERSION) throw std::domain_error("Version number out of range"); int result = (16 * ver + 128) * ver + 64; if (ver >= 2) { int numAlign = ver / 7 + 2; result -= (25 * numAlign - 10) * numAlign - 55; if (ver >= 7) result -= 36; } assert(208 <= result && result <= 29648); return result; } int QrCode::getNumDataCodewords(int ver, Ecc ecl) { return getNumRawDataModules(ver) / 8 - ECC_CODEWORDS_PER_BLOCK [static_cast(ecl)][ver] * NUM_ERROR_CORRECTION_BLOCKS[static_cast(ecl)][ver]; } vector QrCode::reedSolomonComputeDivisor(int degree) { if (degree < 1 || degree > 255) throw std::domain_error("Degree out of range"); // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1. // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}. vector result(static_cast(degree)); result.at(result.size() - 1) = 1; // Start off with the monomial x^0 // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), // and drop the highest monomial term which is always 1x^degree. // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). uint8_t root = 1; for (int i = 0; i < degree; i++) { // Multiply the current product by (x - r^i) for (size_t j = 0; j < result.size(); j++) { result.at(j) = reedSolomonMultiply(result.at(j), root); if (j + 1 < result.size()) result.at(j) ^= result.at(j + 1); } root = reedSolomonMultiply(root, 0x02); } return result; } vector QrCode::reedSolomonComputeRemainder(const vector &data, const vector &divisor) { vector result(divisor.size()); for (uint8_t b : data) { // Polynomial division uint8_t factor = b ^ result.at(0); result.erase(result.begin()); result.push_back(0); for (size_t i = 0; i < result.size(); i++) result.at(i) ^= reedSolomonMultiply(divisor.at(i), factor); } return result; } uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) { // Russian peasant multiplication int z = 0; for (int i = 7; i >= 0; i--) { z = (z << 1) ^ ((z >> 7) * 0x11D); z ^= ((y >> i) & 1) * x; } assert(z >> 8 == 0); return static_cast(z); } int QrCode::finderPenaltyCountPatterns(const std::array &runHistory) const { int n = runHistory.at(1); assert(n <= size * 3); bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n; return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0) + (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0); } int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array &runHistory) const { if (currentRunColor) { // Terminate dark run finderPenaltyAddHistory(currentRunLength, runHistory); currentRunLength = 0; } currentRunLength += size; // Add light border to final run finderPenaltyAddHistory(currentRunLength, runHistory); return finderPenaltyCountPatterns(runHistory); } void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array &runHistory) const { if (runHistory.at(0) == 0) currentRunLength += size; // Add light border to initial run std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end()); runHistory.at(0) = currentRunLength; } bool QrCode::getBit(long x, int i) { return ((x >> i) & 1) != 0; } /*---- Tables of constants ----*/ const int QrCode::PENALTY_N1 = 3; const int QrCode::PENALTY_N2 = 3; const int QrCode::PENALTY_N3 = 40; const int QrCode::PENALTY_N4 = 10; const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = { // Version: (note that index 0 is for padding, and is set to an illegal value) //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High }; const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = { // Version: (note that index 0 is for padding, and is set to an illegal value) //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High }; data_too_long::data_too_long(const std::string &msg) : std::length_error(msg) {} /*---- Class BitBuffer ----*/ BitBuffer::BitBuffer() : std::vector() {} void BitBuffer::appendBits(std::uint32_t val, int len) { if (len < 0 || len > 31 || val >> len != 0) throw std::domain_error("Value out of range"); for (int i = len - 1; i >= 0; i--) // Append bit by bit this->push_back(((val >> i) & 1) != 0); } } kraft-1.1/src/3rdparty/qrcodegen.hpp000066400000000000000000000477171450127457600175340ustar00rootroot00000000000000/* * QR Code generator library (C++) * * Copyright (c) Project Nayuki. (MIT License) * https://www.nayuki.io/page/qr-code-generator-library * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * - The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * - The Software is provided "as is", without warranty of any kind, express or * implied, including but not limited to the warranties of merchantability, * fitness for a particular purpose and noninfringement. In no event shall the * authors or copyright holders be liable for any claim, damages or other * liability, whether in an action of contract, tort or otherwise, arising from, * out of or in connection with the Software or the use or other dealings in the * Software. */ #pragma once #include #include #include #include #include namespace qrcodegen { /* * A segment of character/binary/control data in a QR Code symbol. * Instances of this class are immutable. * The mid-level way to create a segment is to take the payload data * and call a static factory function such as QrSegment::makeNumeric(). * The low-level way to create a segment is to custom-make the bit buffer * and call the QrSegment() constructor with appropriate values. * This segment class imposes no length restrictions, but QR Codes have restrictions. * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. * Any segment longer than this is meaningless for the purpose of generating QR Codes. */ class QrSegment final { /*---- Public helper enumeration ----*/ /* * Describes how a segment's data bits are interpreted. Immutable. */ public: class Mode final { /*-- Constants --*/ public: static const Mode NUMERIC; public: static const Mode ALPHANUMERIC; public: static const Mode BYTE; public: static const Mode KANJI; public: static const Mode ECI; /*-- Fields --*/ // The mode indicator bits, which is a uint4 value (range 0 to 15). private: int modeBits; // Number of character count bits for three different version ranges. private: int numBitsCharCount[3]; /*-- Constructor --*/ private: Mode(int mode, int cc0, int cc1, int cc2); /*-- Methods --*/ /* * (Package-private) Returns the mode indicator bits, which is an unsigned 4-bit value (range 0 to 15). */ public: int getModeBits() const; /* * (Package-private) Returns the bit width of the character count field for a segment in * this mode in a QR Code at the given version number. The result is in the range [0, 16]. */ public: int numCharCountBits(int ver) const; }; /*---- Static factory functions (mid level) ----*/ /* * Returns a segment representing the given binary data encoded in * byte mode. All input byte vectors are acceptable. Any text string * can be converted to UTF-8 bytes and encoded as a byte mode segment. */ public: static QrSegment makeBytes(const std::vector &data); /* * Returns a segment representing the given string of decimal digits encoded in numeric mode. */ public: static QrSegment makeNumeric(const char *digits); /* * Returns a segment representing the given text string encoded in alphanumeric mode. * The characters allowed are: 0 to 9, A to Z (uppercase only), space, * dollar, percent, asterisk, plus, hyphen, period, slash, colon. */ public: static QrSegment makeAlphanumeric(const char *text); /* * Returns a list of zero or more segments to represent the given text string. The result * may use various segment modes and switch modes to optimize the length of the bit stream. */ public: static std::vector makeSegments(const char *text); /* * Returns a segment representing an Extended Channel Interpretation * (ECI) designator with the given assignment value. */ public: static QrSegment makeEci(long assignVal); /*---- Public static helper functions ----*/ /* * Tests whether the given string can be encoded as a segment in numeric mode. * A string is encodable iff each character is in the range 0 to 9. */ public: static bool isNumeric(const char *text); /* * Tests whether the given string can be encoded as a segment in alphanumeric mode. * A string is encodable iff each character is in the following set: 0 to 9, A to Z * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. */ public: static bool isAlphanumeric(const char *text); /*---- Instance fields ----*/ /* The mode indicator of this segment. Accessed through getMode(). */ private: const Mode *mode; /* The length of this segment's unencoded data. Measured in characters for * numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode. * Always zero or positive. Not the same as the data's bit length. * Accessed through getNumChars(). */ private: int numChars; /* The data bits of this segment. Accessed through getData(). */ private: std::vector data; /*---- Constructors (low level) ----*/ /* * Creates a new QR Code segment with the given attributes and data. * The character count (numCh) must agree with the mode and the bit buffer length, * but the constraint isn't checked. The given bit buffer is copied and stored. */ public: QrSegment(const Mode &md, int numCh, const std::vector &dt); /* * Creates a new QR Code segment with the given parameters and data. * The character count (numCh) must agree with the mode and the bit buffer length, * but the constraint isn't checked. The given bit buffer is moved and stored. */ public: QrSegment(const Mode &md, int numCh, std::vector &&dt); /*---- Methods ----*/ /* * Returns the mode field of this segment. */ public: const Mode &getMode() const; /* * Returns the character count field of this segment. */ public: int getNumChars() const; /* * Returns the data bits of this segment. */ public: const std::vector &getData() const; // (Package-private) Calculates the number of bits needed to encode the given segments at // the given version. Returns a non-negative number if successful. Otherwise returns -1 if a // segment has too many characters to fit its length field, or the total bits exceeds INT_MAX. public: static int getTotalBits(const std::vector &segs, int version); /*---- Private constant ----*/ /* The set of all legal characters in alphanumeric mode, where * each character value maps to the index in the string. */ private: static const char *ALPHANUMERIC_CHARSET; }; /* * A QR Code symbol, which is a type of two-dimension barcode. * Invented by Denso Wave and described in the ISO/IEC 18004 standard. * Instances of this class represent an immutable square grid of dark and light cells. * The class provides static factory functions to create a QR Code from text or binary data. * The class covers the QR Code Model 2 specification, supporting all versions (sizes) * from 1 to 40, all 4 error correction levels, and 4 character encoding modes. * * Ways to create a QR Code object: * - High level: Take the payload data and call QrCode::encodeText() or QrCode::encodeBinary(). * - Mid level: Custom-make the list of segments and call QrCode::encodeSegments(). * - Low level: Custom-make the array of data codeword bytes (including * segment headers and final padding, excluding error correction codewords), * supply the appropriate version number, and call the QrCode() constructor. * (Note that all ways require supplying the desired error correction level.) */ class QrCode final { /*---- Public helper enumeration ----*/ /* * The error correction level in a QR Code symbol. */ public: enum class Ecc { LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords MEDIUM , // The QR Code can tolerate about 15% erroneous codewords QUARTILE, // The QR Code can tolerate about 25% erroneous codewords HIGH , // The QR Code can tolerate about 30% erroneous codewords }; // Returns a value in the range 0 to 3 (unsigned 2-bit integer). private: static int getFormatBits(Ecc ecl); /*---- Static factory functions (high level) ----*/ /* * Returns a QR Code representing the given Unicode text string at the given error correction level. * As a conservative upper bound, this function is guaranteed to succeed for strings that have 2953 or fewer * UTF-8 code units (not Unicode code points) if the low error correction level is used. The smallest possible * QR Code version is automatically chosen for the output. The ECC level of the result may be higher than * the ecl argument if it can be done without increasing the version. */ public: static QrCode encodeText(const char *text, Ecc ecl); /* * Returns a QR Code representing the given binary data at the given error correction level. * This function always encodes using the binary segment mode, not any text mode. The maximum number of * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output. * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version. */ public: static QrCode encodeBinary(const std::vector &data, Ecc ecl); /*---- Static factory functions (mid level) ----*/ /* * Returns a QR Code representing the given segments with the given encoding parameters. * The smallest possible QR Code version within the given range is automatically * chosen for the output. Iff boostEcl is true, then the ECC level of the result * may be higher than the ecl argument if it can be done without increasing the * version. The mask number is either between 0 to 7 (inclusive) to force that * mask, or -1 to automatically choose an appropriate mask (which may be slow). * This function allows the user to create a custom sequence of segments that switches * between modes (such as alphanumeric and byte) to encode text in less space. * This is a mid-level API; the high-level API is encodeText() and encodeBinary(). */ public: static QrCode encodeSegments(const std::vector &segs, Ecc ecl, int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true); // All optional parameters /*---- Instance fields ----*/ // Immutable scalar parameters: /* The version number of this QR Code, which is between 1 and 40 (inclusive). * This determines the size of this barcode. */ private: int version; /* The width and height of this QR Code, measured in modules, between * 21 and 177 (inclusive). This is equal to version * 4 + 17. */ private: int size; /* The error correction level used in this QR Code. */ private: Ecc errorCorrectionLevel; /* The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive). * Even if a QR Code is created with automatic masking requested (mask = -1), * the resulting object still has a mask value between 0 and 7. */ private: int mask; // Private grids of modules/pixels, with dimensions of size*size: // The modules of this QR Code (false = light, true = dark). // Immutable after constructor finishes. Accessed through getModule(). private: std::vector > modules; // Indicates function modules that are not subjected to masking. Discarded when constructor finishes. private: std::vector > isFunction; /*---- Constructor (low level) ----*/ /* * Creates a new QR Code with the given version number, * error correction level, data codeword bytes, and mask number. * This is a low-level API that most users should not use directly. * A mid-level API is the encodeSegments() function. */ public: QrCode(int ver, Ecc ecl, const std::vector &dataCodewords, int msk); /*---- Public instance methods ----*/ /* * Returns this QR Code's version, in the range [1, 40]. */ public: int getVersion() const; /* * Returns this QR Code's size, in the range [21, 177]. */ public: int getSize() const; /* * Returns this QR Code's error correction level. */ public: Ecc getErrorCorrectionLevel() const; /* * Returns this QR Code's mask, in the range [0, 7]. */ public: int getMask() const; /* * Returns the color of the module (pixel) at the given coordinates, which is false * for light or true for dark. The top left corner has the coordinates (x=0, y=0). * If the given coordinates are out of bounds, then false (light) is returned. */ public: bool getModule(int x, int y) const; /*---- Private helper methods for constructor: Drawing function modules ----*/ // Reads this object's version field, and draws and marks all function modules. private: void drawFunctionPatterns(); // Draws two copies of the format bits (with its own error correction code) // based on the given mask and this object's error correction level field. private: void drawFormatBits(int msk); // Draws two copies of the version bits (with its own error correction code), // based on this object's version field, iff 7 <= version <= 40. private: void drawVersion(); // Draws a 9*9 finder pattern including the border separator, // with the center module at (x, y). Modules can be out of bounds. private: void drawFinderPattern(int x, int y); // Draws a 5*5 alignment pattern, with the center module // at (x, y). All modules must be in bounds. private: void drawAlignmentPattern(int x, int y); // Sets the color of a module and marks it as a function module. // Only used by the constructor. Coordinates must be in bounds. private: void setFunctionModule(int x, int y, bool isDark); // Returns the color of the module at the given coordinates, which must be in range. private: bool module(int x, int y) const; /*---- Private helper methods for constructor: Codewords and masking ----*/ // Returns a new byte string representing the given data with the appropriate error correction // codewords appended to it, based on this object's version and error correction level. private: std::vector addEccAndInterleave(const std::vector &data) const; // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire // data area of this QR Code. Function modules need to be marked off before this is called. private: void drawCodewords(const std::vector &data); // XORs the codeword modules in this QR Code with the given mask pattern. // The function modules must be marked and the codeword bits must be drawn // before masking. Due to the arithmetic of XOR, calling applyMask() with // the same mask value a second time will undo the mask. A final well-formed // QR Code needs exactly one (not zero, two, etc.) mask applied. private: void applyMask(int msk); // Calculates and returns the penalty score based on state of this QR Code's current modules. // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. private: long getPenaltyScore() const; /*---- Private helper functions ----*/ // Returns an ascending list of positions of alignment patterns for this version number. // Each position is in the range [0,177), and are used on both the x and y axes. // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. private: std::vector getAlignmentPatternPositions() const; // Returns the number of data bits that can be stored in a QR Code of the given version number, after // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. private: static int getNumRawDataModules(int ver); // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any // QR Code of the given version number and error correction level, with remainder bits discarded. // This stateless pure function could be implemented as a (40*4)-cell lookup table. private: static int getNumDataCodewords(int ver, Ecc ecl); // Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be // implemented as a lookup table over all possible parameter values, instead of as an algorithm. private: static std::vector reedSolomonComputeDivisor(int degree); // Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials. private: static std::vector reedSolomonComputeRemainder(const std::vector &data, const std::vector &divisor); // Returns the product of the two given field elements modulo GF(2^8/0x11D). // All inputs are valid. This could be implemented as a 256*256 lookup table. private: static std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y); // Can only be called immediately after a light run is added, and // returns either 0, 1, or 2. A helper function for getPenaltyScore(). private: int finderPenaltyCountPatterns(const std::array &runHistory) const; // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). private: int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array &runHistory) const; // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). private: void finderPenaltyAddHistory(int currentRunLength, std::array &runHistory) const; // Returns true iff the i'th bit of x is set to 1. private: static bool getBit(long x, int i); /*---- Constants and tables ----*/ // The minimum version number supported in the QR Code Model 2 standard. public: static constexpr int MIN_VERSION = 1; // The maximum version number supported in the QR Code Model 2 standard. public: static constexpr int MAX_VERSION = 40; // For use in getPenaltyScore(), when evaluating which mask is best. private: static const int PENALTY_N1; private: static const int PENALTY_N2; private: static const int PENALTY_N3; private: static const int PENALTY_N4; private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41]; private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41]; }; /*---- Public exception class ----*/ /* * Thrown when the supplied data does not fit any QR Code version. Ways to handle this exception include: * - Decrease the error correction level if it was greater than Ecc::LOW. * - If the encodeSegments() function was called with a maxVersion argument, then increase * it if it was less than QrCode::MAX_VERSION. (This advice does not apply to the other * factory functions because they search all versions up to QrCode::MAX_VERSION.) * - Split the text data into better or optimal segments in order to reduce the number of bits required. * - Change the text or binary data to be shorter. * - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric). * - Propagate the error upward to the caller/user. */ class data_too_long : public std::length_error { public: explicit data_too_long(const std::string &msg); }; /* * An appendable sequence of bits (0s and 1s). Mainly used by QrSegment. */ class BitBuffer final : public std::vector { /*---- Constructor ----*/ // Creates an empty bit buffer (length 0). public: BitBuffer(); /*---- Method ----*/ // Appends the given number of low-order bits of the given value // to this buffer. Requires 0 <= len <= 31 and val < 2^len. public: void appendBits(std::uint32_t val, int len); }; } kraft-1.1/src/CMakeLists.txt000066400000000000000000000106511450127457600160270ustar00rootroot00000000000000 include_directories(${QT_INCLUDES} src) add_subdirectory(pics) configure_file(${CMAKE_CURRENT_LIST_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h @ONLY) ########### next target ############### qt5_add_resources(KRAFT_RC_SRC pics/kraft.qrc) set(kraft_SRCS attribute.cpp einheit.cpp doctype.cpp numbercycle.cpp katalogman.cpp stdsatzman.cpp katalog.cpp templkatalog.cpp docposition.cpp matkatalog.cpp calcdialogbase.cpp timecalcpart.cpp fixcalcpart.cpp floskeltemplate.cpp floskel.cpp calcpart.cpp kraftview.cpp kraftdoc.cpp catalogchapter.cpp addeditchapterdialog.cpp unitmanager.cpp stockmaterial.cpp materialcalcpart.cpp flostempldialog.cpp stdsatzman.cpp materialtempldialog.cpp timecalcdialog.cpp fixcalcdialog.cpp matcalcdialog.h matcalcdialog.cpp templatesaverbase.cpp templatesaverdb.cpp materialsaverbase.cpp materialsaverdb.cpp prefsdialog.cpp prefswages.cpp prefsunits.cpp katalogview.cpp filterheader.cpp kataloglistview.cpp templkatalogview.cpp templkataloglistview.cpp positionviewwidget.cpp documentsaverbase.cpp documentsaverdb.cpp exportxrechnung.cpp documentman.cpp docdigest.cpp alldocsview.cpp doctypeedit.cpp doctext.cpp portal.cpp portalview.cpp archiveman.cpp reportgenerator.cpp htmlview.cpp docpostcard.cpp catalogtemplate.cpp catalogselection.cpp kraftdocheaderedit.cpp kraftdocfooteredit.cpp inserttempldialog.cpp archdocposition.cpp archdoc.cpp materialkataloglistview.cpp materialkatalogview.cpp materialselectdialog.cpp kraftdocedit.cpp kraftdocpositionsedit.cpp portalhtmlview.cpp templtopositiondialogbase.cpp textselection.cpp newdocassistant.cpp docassistant.cpp texteditdialog.cpp templateprovider.cpp headertemplateprovider.cpp footertemplateprovider.cpp catalogtemplateprovider.cpp texttemplate.cpp grantleetemplate.cpp tagman.cpp itemtagdialog.cpp tagtemplatesdialog.cpp importitemdialog.cpp importfilter.cpp kraftview_ro.cpp taxeditdialog.cpp numbercycledialog.cpp impviewwidgets.cpp setupassistant.cpp models/documentmodel.cpp models/documentproxymodels.cpp models/datemodel.cpp models/docbasemodel.cpp docdigestdetailview.cpp addressprovider.cpp addressselectorwidget.cpp addressprovider_akonadi.cpp addressselectordialog.cpp kraftdb.cpp geld.cpp defaultprovider.cpp metaxmlparser.cpp texttemplateinterface.cpp documenttemplate.cpp pdfconverter.cpp format.cpp stringutil.cpp epcqrcode.cpp 3rdparty/qrcodegen.cpp ) kconfig_add_kcfg_files(kraft_SRCS databasesettings.kcfgc kraftsettings.kcfgc ) ki18n_wrap_ui(kraft_SRCS calctemplate.ui dbinit.ui createdb.ui dbselect.ui mysqldetails.ui sqlitedetails.ui identity.ui statuspage.ui upgradedb.ui timepart.ui fixpartui.ui matpartui.ui inserttmplbase.ui materialdialog.ui docheader.ui positionwidget.ui docfooter.ui texteditbase.ui positionwidget.ui doctypeeditbase.ui taxeditbase.ui wageseditbase.ui unitseditbase.ui importtodocbase.ui numbercycleseditbase.ui xrechnung.ui ) set(KRAFT_LINK_LIBS Qt5::Core Qt5::Widgets Qt5::Sql Qt5::Xml KF5::I18n KF5::Contacts KF5::ConfigCore KF5::ConfigGui ${CTEMPLATE_LIBRARIES} pthread Grantlee5::Templates ) if(${AKO_PREFIX}Akonadi_FOUND) list(APPEND KRAFT_LINK_LIBS ${AKO_PREFIX}::AkonadiCore ${AKO_PREFIX}::AkonadiContact ${AKO_PREFIX}::ContactEditor ${AKO_PREFIX}::AkonadiAgentBase ${AKO_PREFIX}::AkonadiWidgets ${AKO_PREFIX}::AkonadiXml ) endif() add_library(kraftlib STATIC ${KRAFT_RC_SRC} ${kraft_SRCS}) target_compile_options(kraftlib PRIVATE -Wall -Wno-suggest-override) add_executable(kraft main.cpp) set_target_properties(kraft PROPERTIES OUTPUT_NAME kraft) target_link_libraries(kraftlib PUBLIC ${KRAFT_LINK_LIBS} ) target_link_libraries(kraft PUBLIC kraftlib ) install(TARGETS kraft ${INSTALL_TARGETS_DEFAULT_ARGS}) ########### install files ############### install(FILES kraftsettings.kcfg databasesettings.kcfg DESTINATION ${KCFG_INSTALL_DIR}) install(FILES kraftui.rc katalogview.rc DESTINATION ${KXMLGUI_INSTALL_DIR}/kraft) kraft-1.1/src/Kraft2.config000066400000000000000000000000371450127457600156040ustar00rootroot00000000000000// ADD PREDEFINED MACROS HERE! kraft-1.1/src/Kraft2.creator000066400000000000000000000000501450127457600157710ustar00rootroot00000000000000[General] [General] [General] [General] kraft-1.1/src/Kraft2.files000066400000000000000000000073561450127457600154540ustar00rootroot00000000000000addressselection.cpp addressselection.h addresstemplateprovider.cpp addresstemplateprovider.h archdoc.cpp archdoc.h archdocposition.cpp archdocposition.h archiveman.cpp archiveman.h attribute.cpp attribute.h brunskatalog.cpp brunskatalog.h brunskataloglistview.cpp brunskataloglistview.h brunskatalogview.cpp brunskatalogview.h brunsrecord.cpp brunsrecord.h brunsviewer.cpp brunsviewer.h brunsviewmain.cpp calcpart.cpp calcpart.h catalogchapteredit.cpp catalogchapteredit.h catalogselection.cpp catalogselection.h catalogtemplate.cpp catalogtemplate.h catalogtemplateprovider.cpp catalogtemplateprovider.h CMakeLists.txt dbids.h defaultprovider.cpp defaultprovider.h docassistant.cpp docassistant.h docdigest.cpp docdigest.h docdigestview.cpp docdigestview.h docfooter.ui docguardedptr.h docheader.ui doclocaledialog.cpp doclocaledialog.h docposition.cpp docposition.h docpostcard.cpp docpostcard.h doctext.cpp doctext.h doctextsview.ui doctype.cpp doctype.h doctypedetailseditbase.ui doctypeedit.cpp doctypeedit.h doctypeeditbase.ui documentman.cpp documentman.h documentsaverbase.cpp documentsaverbase.h documentsaverdb.cpp documentsaverdb.h einheit.cpp einheit.h extendedcombo.cpp extendedcombo.h filterheader.cpp filterheader.h fixcalcdialog.cpp fixcalcdialog.h fixcalcpart.cpp fixcalcpart.h fixpartui.ui floskel.cpp floskel.h floskeltemplate.cpp floskeltemplate.h flostab.ui flostempldialog.cpp flostempldialog.h footertemplateprovider.cpp footertemplateprovider.h geld.cpp geld.h headerselection.cpp headerselection.h headertemplateprovider.cpp headertemplateprovider.h htmlview.cpp htmlview.h imporst.cpp importfilter.cpp importfilter.h importitemdialog.cpp importitemdialog.h importtodocbase.ui insertplantbase.ui insertplantdialog.cpp insertplantdialog.h inserttempldialog.cpp inserttempldialog.h inserttmplbase.ui katalog.cpp katalog.h kataloglistview.cpp kataloglistview.h katalogman.cpp katalogman.h katalogview.cpp katalogview.h kraftdb.cpp kraftdb.h kraftdoc.cpp kraftdoc.h kraftdocedit.cpp kraftdocedit.h kraftdocfooteredit.cpp kraftdocfooteredit.h kraftdocheaderedit.cpp kraftdocheaderedit.h kraftdocpositionsedit.cpp kraftdocpositionsedit.h kraftglobals.h kraftview.cpp kraftview.h kraftview_ro.cpp kraftview_ro.h main.cpp matcalcdialog.cpp matcalcdialog.h materialcalcpart.cpp materialcalcpart.h materialdialog.ui materialkataloglistview.cpp materialkataloglistview.h materialkatalogview.cpp materialkatalogview.h materialsaverbase.cpp materialsaverbase.h materialsaverdb.cpp materialsaverdb.h materialselectdialog.cpp materialselectdialog.h materialtempldialog.cpp materialtempldialog.h matkatalog.cpp matkatalog.h matpartui.ui matpartui.ui.h newdocassistant.cpp newdocassistant.h numbercycle.cpp numbercycle.h numbercycledialog.cpp numbercycledialog.h numbercycleseditbase.ui pics/CMakeLists.txt portal.cpp portal.h portalhtmlview.cpp portalhtmlview.h portalview.cpp portalview.h portinglog.txt positiontagdialog.cpp positiontagdialog.h positionviewwidget.cpp positionviewwidget.h positionwidget.ui prefsdialog.cpp prefsdialog.h reportgenerator.cpp reportgenerator.h stdsatzman.cpp stdsatzman.h stockmaterial.cpp stockmaterial.h stockmaterialman.cpp stockmaterialman.h tagman.cpp tagman.h tagtemplatesdialog.cpp tagtemplatesdialog.h templateprovider.cpp templateprovider.h templatesaverbase.cpp templatesaverbase.h templatesaverdb.cpp templatesaverdb.h templkatalog.cpp templkatalog.h templkataloglistview.cpp templkataloglistview.h templkatalogview.cpp templkatalogview.h templtopositiondialogbase.cpp templtopositiondialogbase.h texteditbase.ui texteditdialog.cpp texteditdialog.h textselection.cpp textselection.h texttemplate.cpp texttemplate.h timecalcpart.cpp timecalcpart.h unitmanager.cpp unitmanager.h version.h zeitcalcdialog.cpp zeitcalcdialog.h zeitcalcpart.cpp zeitcalcpart.h zeitpartui.uikraft-1.1/src/Kraft2.includes000066400000000000000000000000001450127457600161330ustar00rootroot00000000000000kraft-1.1/src/Messages.sh000066400000000000000000000006241450127457600153710ustar00rootroot00000000000000#!bin/sh EXTRACTRC=$KRAFT_HOME/src/extractrc XGETTEXT=xgettext if [ -z "$KRAFT_HOME" ]; then echo "Need to set KRAFT_HOME" exit 1 fi podir=$KRAFT_HOME/po echo "PODir: " $podir pushd $KRAFT_HOME/src $EXTRACTRC `find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` >> rc.cpp $XGETTEXT --kde --language=C++ --from-code=UTF-8 `find . -name \*.cc -o -name \*.cpp -o -name \*.h` -o $podir/kraft.pot kraft-1.1/src/addeditchapterdialog.cpp000066400000000000000000000055251450127457600201240ustar00rootroot00000000000000/*************************************************************************** addeditchapter - add and edit catalog chapters ------------------- begin : Sat Nov 6 2010 copyright : (C) 2010 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include "addeditchapterdialog.h" #include "catalogchapter.h" AddEditChapterDialog::AddEditChapterDialog( QWidget *parent ) :QDialog( parent ) { setObjectName( "CHAPTER_EDIT_DIALOG" ); setModal( true ); setWindowTitle( i18n( "Add/Edit Catalog Chapter" ) ); QVBoxLayout *vbox = new QVBoxLayout; this->setLayout( vbox ); mTopLabel = new QLabel(); mTopLabel->setText( i18n("Create a new Catalog Chapter")); vbox->addWidget( mTopLabel ); vbox->addWidget( new QLabel( i18n("Chapter Name:"))); mNameEdit = new QLineEdit; vbox->addWidget( mNameEdit ); vbox->addWidget( new QLabel( i18n("Chapter Description:"))); mDescEdit = new QLineEdit; vbox->addWidget( mDescEdit ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); vbox->addWidget(buttonBox); } QString AddEditChapterDialog::name() const { return mNameEdit->text(); } QString AddEditChapterDialog::description() const { return mDescEdit->text(); } void AddEditChapterDialog::setParentChapter( const CatalogChapter& chapter ) { mParentChapter = chapter; mTopLabel->setText( i18n("Create new Catalog Chapter below chapter %1", chapter.name() )); } void AddEditChapterDialog::setEditChapter( const CatalogChapter& chapter ) { mChapter = chapter; mTopLabel->setText( i18n("Edit name and description of chapter %1", chapter.name() )); mNameEdit->setText( chapter.name() ); mDescEdit->setText( chapter.description() ); } kraft-1.1/src/addeditchapterdialog.h000066400000000000000000000031511450127457600175620ustar00rootroot00000000000000/*************************************************************************** addeditchapter - add and edit catalog chapters ------------------- begin : Sat Nov 6 2010 copyright : (C) 2010 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef ADDEDITCHAPTERDIALOG_H #define ADDEDITCHAPTERDIALOG_H #include #include #include #include "catalogchapter.h" class AddEditChapterDialog : public QDialog { Q_OBJECT public: AddEditChapterDialog(QWidget *parent = 0); void setEditChapter( const CatalogChapter& ); void setParentChapter( const CatalogChapter& ); QString name() const; QString description() const; private: CatalogChapter mChapter; CatalogChapter mParentChapter; QLineEdit *mNameEdit; QLineEdit *mDescEdit; QLabel *mTopLabel; }; #endif // ADDEDITCHAPTERDIALOG_H kraft-1.1/src/addressprovider.cpp000066400000000000000000000116341450127457600171750ustar00rootroot00000000000000/*************************************************************************** addressprovider.cpp - ------------------- begin : Fri Mar 4 2011 copyright : (C) 2011 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include "addressprovider.h" #include // FIXME this needs to change once there are more address book providers, ie. // on Mac. #include "addressprovider_akonadi.h" /* ==================================================================================== */ AddressProvider::AddressProvider( QObject *parent ) :QObject( parent ), _d( new AddressProviderPrivate(parent) ) { connect(_d, SIGNAL(addresseeFound(QString, KContacts::Addressee)), this, SLOT(slotAddresseeFound(QString, KContacts::Addressee))); connect(_d, SIGNAL(lookupError( QString, QString)), this, SLOT(slotErrorMsg(QString, QString))); connect(_d, SIGNAL(addresseeNotFound(QString)), SLOT(slotAddresseeNotFound(QString))); } bool AddressProvider::backendUp() { return _d->backendUp(); } QString AddressProvider::backendName() const { return _d->backendName(); } void AddressProvider::slotAddresseeFound( const QString& uid, const KContacts::Addressee contact) { // remove a potential error message in case an error happened before if( !( uid.isEmpty() || contact.isEmpty()) ) { _errMessages.remove(uid); } _addressCache[uid] = contact; _addressCache[uid].insertCustom(CUSTOM_ADDRESS_MARKER, "addressbook"); emit lookupResult(uid, _addressCache[uid]); } void AddressProvider::slotAddresseeNotFound( const QString& uid ) { KContacts::Addressee contact; // Empty for not found. _notFoundUids.insert(uid); emit lookupResult(uid, contact); } void AddressProvider::slotResetNotFoundCache() { _notFoundUids.clear(); } void AddressProvider::slotErrorMsg(const QString& uid, const QString& msg) { if( !uid.isEmpty() ) { _errMessages[uid] = msg; } } QString AddressProvider::errorMsg( const QString& uid ) { if( !_d->backendUp() ) { return "Backend down"; } if( _errMessages.contains(uid) ) { return _errMessages[uid]; } return QString(); } KContacts::Addressee AddressProvider::getAddresseeFromCache(const QString& uid) { KContacts::Addressee adr; if( _addressCache.contains(uid)) { adr = _addressCache[uid]; } return adr; } AddressProvider::LookupState AddressProvider::lookupAddressee( const QString& uid ) { // FIXME: Check for the size of the err messages. If it is big, // maybe do not bother the backend more if( !_d->backendUp() ) { return BackendError; } if( _notFoundUids.contains(uid)) { // qDebug() << uid << "was not found before"; return LookupNotFound; } if( _addressCache.contains(uid)) { return LookupFromCache; } if( _d->isSearchOngoing(uid) ) { return LookupOngoing; } if( _d->lookupAddressee(uid) ) { return LookupStarted; } return ItemError; } KContacts::Addressee AddressProvider::getAddressee(const QModelIndex& indx) { return _d->getAddressee(indx); } KContacts::Addressee AddressProvider::getAddressee( int row, const QModelIndex &parent) { return _d->getAddressee(row, parent); } QAbstractItemModel *AddressProvider::model() { return _d->model(); } QString AddressProvider::formattedAddress( const KContacts::Addressee& contact ) const { QString re; KContacts::Address address; address = contact.address( KContacts::Address::Pref ); if( address.isEmpty() ) address = contact.address(KContacts::Address::Work ); if( address.isEmpty() ) address = contact.address(KContacts::Address::Home ); if( address.isEmpty() ) address = contact.address(KContacts::Address::Postal ); if( address.isEmpty() ) { re = contact.realName(); } else { #if KContacts_VERSION >= QT_VERSION_CHECK(5, 92, 0) re = address.formatted( KContacts::AddressFormatStyle::MultiLineDomestic, contact.realName(), contact.organization() ); #else re = address.formattedAddress( contact.realName(), contact.organization() ); #endif } return re; } kraft-1.1/src/addressprovider.h000066400000000000000000000101661450127457600166410ustar00rootroot00000000000000/*************************************************************************** addressprovider.h ------------------- begin : Fri Mar 4 2011 copyright : (C) 2011 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef ADDRESSPROVIDER_H #define ADDRESSPROVIDER_H #include #include #include // use define CUSTOM_ADDRESS_MARKER to mark the origin of addresses with .insertCustom #define CUSTOM_ADDRESS_MARKER "kraft", "identity_source" class AddressProviderPrivate; class AddressProvider : public QObject { Q_OBJECT public: AddressProvider( QObject* parent = 0 ); enum LookupState { LookupOngoing, LookupStarted, LookupFromCache, LookupNotFound, ItemError, BackendError }; bool backendUp(); QString backendName() const; /** * @brief lookupAddressee - look up an addressee by it's uid. * @param uid - A unique string identifying the contact * * This is asynchron an asynchronous method that returns immediately. * Connect to the signal lookupResult() for the result. * * Make sure to always use a non empty uid. */ LookupState lookupAddressee( const QString& uid ); QString formattedAddress( const KContacts::Addressee& ) const; /** * @brief return an address from cache * @param uid - the unique address uid * * Use this method to get the address if the lookupAddressee method * returned LookupFromCache. In this case, the address is already * known and can be fetched synchronously */ KContacts::Addressee getAddresseeFromCache(const QString& uid); /** * @brief model - returns an Qt model for a tree view. * @return a QAbstractItemModel */ QAbstractItemModel *model(); /** * @brief getAddressee - get the contact from an index * @param indx * * Depending on the underlying model in the private implementation * advantage can be taken from this functions. * Used by the addressselectorwidget * @return the found addressee */ KContacts::Addressee getAddressee(const QModelIndex& indx); KContacts::Addressee getAddressee( int row, const QModelIndex &parent = QModelIndex()); /** * @brief errorMsg - returns the error string for retrieval by uid * @param uid - the UID of the lookup job * * If the lookup job failed for whatever reason, this returns an error * message why, if that was available from the private implementation. * @return QString error message */ QString errorMsg( const QString& uid ); public slots: void slotResetNotFoundCache(); protected slots: void slotErrorMsg(const QString& uid, const QString& msg); void slotAddresseeFound( const QString& uid, const KContacts::Addressee contact); void slotAddresseeNotFound( const QString& uid ); signals: /** * @brief lookupResult - deliver lookup result * @param uid - the uid of the lookup, and the contact * * If the contact is empty, it was simply not found. It can be checked * if there was an error using the errorMsg method for the uid. If there * was no error (errorMsg returns empty string) the addressbook just * did not contain the address. */ void lookupResult( const QString&, const KContacts::Addressee& ); private: QHash _addressCache; AddressProviderPrivate *_d; QHash _errMessages; QSet _notFoundUids; }; #endif // ADDRESSPROVIDER_H kraft-1.1/src/addressprovider_akonadi.cpp000066400000000000000000000172101450127457600206570ustar00rootroot00000000000000/*************************************************************************** addressprovider.cpp - ------------------- begin : Fri Mar 4 2011 copyright : (C) 2011 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "addressprovider_akonadi.h" #include #include #ifdef HAVE_AKONADI #include #if AKONADI_VERSION >= QT_VERSION_CHECK(5,20,0) #include #else #define AKONADICONTACT_VERSION AKONADI_VERSION #endif #if AKONADICONTACT_VERSION >= QT_VERSION_CHECK(5, 20, 0) #include #else #include #endif #if AKONADI_VERSION >= QT_VERSION_CHECK(5, 18, 41) #include #include #include #include #include #include #include #else #include #include #include #include #include #include #include #endif using namespace Akonadi; #endif AddressProviderPrivate::AddressProviderPrivate( QObject *parent ) :QObject( parent ), _akonadiUp(false), mSession(0), mMonitor(0), _model(0) { init(); } bool AddressProviderPrivate::init() { _akonadiUp = false; #ifdef HAVE_AKONADI if ( !Akonadi::Control::start( ) ) { qDebug() << "Failed to start Akonadi!"; } else { mSession = new Akonadi::Session( "KraftSession" ); _akonadiUp = true; } #endif return _akonadiUp; } QString AddressProviderPrivate::backendName() const { #ifdef HAVE_AKONADI return QStringLiteral("Akonadi"); #else return QStringLiteral("Akonadi disabled by compile option!"); #endif } bool AddressProviderPrivate::backendUp() { return _akonadiUp; } bool AddressProviderPrivate::isSearchOngoing(const QString& uid) { return mUidSearches.contains(uid); } bool AddressProviderPrivate::lookupAddressee( const QString& uid ) { if( uid.isEmpty() ) { qDebug() << "Invalid: UID to lookup is empty."; return false; } if( mUidSearches.contains( uid ) ) { // search is already running // qDebug () << "Search already underways!";^ return false; } #ifdef HAVE_AKONADI Akonadi::ContactSearchJob *csjob = new Akonadi::ContactSearchJob( this ); csjob->setLimit( 1 ); csjob->setQuery(ContactSearchJob::ContactUid , uid, ContactSearchJob::ExactMatch); csjob->setProperty("UID", uid); connect( csjob, SIGNAL( result( KJob* ) ), this, SLOT( searchResult( KJob* ) ) ); csjob->start(); mUidSearches.insert( uid ); model(); return true; #endif return false; } #ifdef HAVE_AKONADI void AddressProviderPrivate::searchResult( KJob* job ) { if( !job ) return; QString uid; KContacts::Addressee contact; uid = job->property("UID").toString(); if( job->error() ) { // both uid and err message can be empty const QString errMsg = job->errorString(); emit lookupError(uid, errMsg ); // qDebug () << "Address Search job failed: " << job->errorString(); } else { Akonadi::ContactSearchJob *searchJob = qobject_cast( job ); const KContacts::Addressee::List contacts = searchJob->contacts(); KContacts::Addressee::List(); // qDebug () << "Found list of " << contacts.size() << " addresses as search result"; if( contacts.size() > 0 ) { contact = contacts[0]; // qDebug() << "Found uid search job for UID " << uid << " = " << contact.realName(); emit addresseeFound(uid, contact); } else { // qDebug() << "No search result for UID" << uid; emit addresseeNotFound(uid); } } // cleanup if(!uid.isEmpty()) { mUidSearches.remove( uid ); } job->deleteLater(); } #endif QAbstractItemModel* AddressProviderPrivate::model() { if( !_akonadiUp ) { return 0; } #ifdef HAVE_AKONADI Akonadi::ItemFetchScope scope; // fetch all content of the contacts, including images scope.fetchFullPayload( true ); // fetch the EntityDisplayAttribute, which contains custom names and icons scope.fetchAttribute(); if( ! mMonitor ) { mMonitor = new Akonadi::ChangeRecorder; mMonitor->setSession( mSession ); // include fetching the collection tree mMonitor->fetchCollection( true ); // set the fetch scope that shall be used mMonitor->setItemFetchScope( scope ); // monitor all collections below the root collection for changes mMonitor->setCollectionMonitored( Akonadi::Collection::root() ); // list only contacts and contact groups mMonitor->setMimeTypeMonitored( KContacts::Addressee::mimeType(), true ); mMonitor->setMimeTypeMonitored( KContacts::ContactGroup::mimeType(), true ); } if( !_model ) { _model = new Akonadi::ContactsTreeModel( mMonitor ); Akonadi::ContactsTreeModel::Columns columns; columns << Akonadi::ContactsTreeModel::FullName; columns << Akonadi::ContactsTreeModel::HomeAddress; // columns << Akonadi::ContactsTreeModel::FamilyName; // columns << Akonadi::ContactsTreeModel::GivenName; _model->setColumns( columns ); } return _model; #endif return 0; } KContacts::Addressee AddressProviderPrivate::getAddressee(const QModelIndex& indx) { KContacts::Addressee contact; #ifdef HAVE_AKONADI if( indx.isValid() ) { const Akonadi::Item item = indx.data(Akonadi::EntityTreeModel::ItemRole).value(); if (item.hasPayload()) { contact = item.payload(); } } #endif return contact; } KContacts::Addressee AddressProviderPrivate::getAddressee(int row, const QModelIndex &parent) { #ifdef HAVE_AKONADI const QModelIndex index = _model->index(row, 0, parent); return getAddressee(index); #endif return KContacts::Addressee(); } QString AddressProviderPrivate::formattedAddress( const KContacts::Addressee& contact ) const { QString re; KContacts::Address address; address = contact.address( KContacts::Address::Pref ); if( address.isEmpty() ) address = contact.address(KContacts::Address::Work ); if( address.isEmpty() ) address = contact.address(KContacts::Address::Home ); if( address.isEmpty() ) address = contact.address(KContacts::Address::Postal ); if( address.isEmpty() ) { re = contact.realName(); } else { re = address.formattedAddress( contact.realName(), contact.organization() ); } return re; } kraft-1.1/src/addressprovider_akonadi.h000066400000000000000000000063011450127457600203230ustar00rootroot00000000000000/*************************************************************************** addressprovider.h ------------------- begin : Fri Mar 4 2011 copyright : (C) 2011 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef ADDRESSPROVIDER_AKONADI_H #define ADDRESSPROVIDER_AKONADI_H #include #include #include #ifdef HAVE_AKONADI #include #include #if AKONADI_VERSION >= QT_VERSION_CHECK(5,20,0) #include #else #define AKONADICONTACT_VERSION AKONADI_VERSION #endif #if AKONADICONTACT_VERSION >= QT_VERSION_CHECK(5, 20, 0) #include #else #include #endif #if AKONADI_VERSION >= QT_VERSION_CHECK(5, 18, 41) #include #include #else #include #include #endif #endif class QAbstractItemModel; class AddressItemModel; // An akonadi based provider. class AddressProviderPrivate : public QObject { Q_OBJECT public: AddressProviderPrivate( QObject* parent = 0 ); // initialize the backend and return true if that worked. bool init(); // returns the result of the init process later on bool backendUp(); QString backendName() const; bool lookupAddressee( const QString& uid ); QString formattedAddress( const KContacts::Addressee& ) const; QAbstractItemModel *model(); KContacts::Addressee getAddressee(int row, const QModelIndex &parent); KContacts::Addressee getAddressee(const QModelIndex& indx); bool isSearchOngoing(const QString& uid); #ifdef HAVE_AKONADI public slots: void searchResult( KJob* ); #endif signals: // void addresseeFound( const QString&, const KContacts::Addressee& ); void addresseeNotFound( const QString& ); // error message when looking up the address for a UID void lookupError( const QString&, const QString&); // emitted when the search is finished, even if there was no result. void finished( int ); private: QSet mUidSearches; bool _akonadiUp; #ifdef HAVE_AKONADI Akonadi::Session *mSession; Akonadi::ChangeRecorder* mMonitor; // FIXME: Must static somehow Akonadi::ContactsTreeModel *_model; #else void *mSession; void *mMonitor; void *_model; #endif }; #endif // ADDRESSPROVIDER_AKONADI_H kraft-1.1/src/addressselectordialog.cpp000066400000000000000000000052751450127457600203470ustar00rootroot00000000000000/*************************************************************************** addressselectordialog.cpp - select addressee from address book. ------------------- begin : Sept. 2016 copyright : (C) 2016 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include "kraftsettings.h" #include "addressselectorwidget.h" #include "addressselectordialog.h" AddressSelectorDialog::AddressSelectorDialog( QWidget *parent ) :QDialog(parent) { setModal( true ); const QByteArray geo = QByteArray::fromBase64( KraftSettings::self()->addressSelectDialogSize().toLatin1() ); restoreGeometry(geo); _addressSelectorWidget = new AddressSelectorWidget(this, false); connect(_addressSelectorWidget, SIGNAL(addressSelected(KContacts::Addressee)), SLOT(slotAddresseeSelected(KContacts::Addressee))); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, this); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(_addressSelectorWidget); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(buttonBox); } void AddressSelectorDialog::slotAddresseeSelected( const KContacts::Addressee& addressee ) { _addressee = addressee; _addressee.insertCustom(CUSTOM_ADDRESS_MARKER, "addressbook"); } KContacts::Addressee AddressSelectorDialog::addressee() { return _addressee; } void AddressSelectorDialog::done(int r) { const QByteArray geo = saveGeometry().toBase64(); KraftSettings::self()->setAddressSelectDialogSize(geo); _addressSelectorWidget->saveState(); QDialog::done(r); } kraft-1.1/src/addressselectordialog.h000066400000000000000000000030601450127457600200020ustar00rootroot00000000000000/*************************************************************************** addressselectordialog.h - select addressee from address book. ------------------- begin : Sept. 2012 copyright : (C) 2012 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef ADDRESSSELECTORDIALOG_H #define ADDRESSSELECTORDIALOG_H #include #include class AddressSelectorWidget; using namespace KContacts; class AddressSelectorDialog : public QDialog { Q_OBJECT public: AddressSelectorDialog( QWidget *parent = 0 ); KContacts::Addressee addressee(); void done(int r); private slots: void slotAddresseeSelected(const KContacts::Addressee&); private: AddressSelectorWidget *_addressSelectorWidget; Addressee _addressee; }; #endif // ADDRESSSELECTORDIALOG_H kraft-1.1/src/addressselectorwidget.cpp000066400000000000000000000310331450127457600203620ustar00rootroot00000000000000/*************************************************************************** AddressSelectorWidget - Address Selection Widget based on Akonadi ------------------- begin : Jul 2011 copyright : (C) 2011 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "kraftsettings.h" #include "addressselectorwidget.h" #include "addressprovider.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_AKONADI #include #if AKONADI_VERSION >= QT_VERSION_CHECK(5, 18, 41) #include #include #else #include #include #endif #endif /* ==================================================================== */ AddressSortProxyModel::AddressSortProxyModel(AddressProvider *provider, QObject *parent) : QSortFilterProxyModel(parent), _provider(provider) { // setFilterRole(ActivityItemDelegate::ActionTextRole); setFilterKeyColumn(0); } static bool addressMatchesFilter(const KContacts::Address &address, const QString &filterString) { if (address.street().contains(filterString, Qt::CaseInsensitive)) { return true; } if (address.locality().contains(filterString, Qt::CaseInsensitive)) { return true; } if (address.region().contains(filterString, Qt::CaseInsensitive)) { return true; } if (address.postalCode().contains(filterString, Qt::CaseInsensitive)) { return true; } if (address.country().contains(filterString, Qt::CaseInsensitive)) { return true; } if (address.label().contains(filterString, Qt::CaseInsensitive)) { return true; } if (address.postOfficeBox().contains(filterString, Qt::CaseInsensitive)) { return true; } return false; } static bool contactMatchesFilter(const KContacts::Addressee &contact, const QString &filterString) { if (contact.assembledName().contains(filterString, Qt::CaseInsensitive)) { return true; } if (contact.formattedName().contains(filterString, Qt::CaseInsensitive)) { return true; } if (contact.nickName().contains(filterString, Qt::CaseInsensitive)) { return true; } if (contact.birthday().toString().contains(filterString, Qt::CaseInsensitive)) { return true; } const KContacts::Address::List addresses = contact.addresses(); int count = addresses.count(); for (int i = 0; i < count; ++i) { if (addressMatchesFilter(addresses.at(i), filterString)) { return true; } } const KContacts::PhoneNumber::List phoneNumbers = contact.phoneNumbers(); count = phoneNumbers.count(); for (int i = 0; i < count; ++i) { if (phoneNumbers.at(i).number().contains(filterString, Qt::CaseInsensitive)) { return true; } } const QStringList emails = contact.emails(); count = emails.count(); for (int i = 0; i < count; ++i) { if (emails.at(i).contains(filterString, Qt::CaseInsensitive)) { return true; } } const QStringList categories = contact.categories(); count = categories.count(); for (int i = 0; i < count; ++i) { if (categories.at(i).contains(filterString, Qt::CaseInsensitive)) { return true; } } if (contact.mailer().contains(filterString, Qt::CaseInsensitive)) { return true; } if (contact.title().contains(filterString, Qt::CaseInsensitive)) { return true; } if (contact.role().contains(filterString, Qt::CaseInsensitive)) { return true; } if (contact.organization().contains(filterString, Qt::CaseInsensitive)) { return true; } if (contact.department().contains(filterString, Qt::CaseInsensitive)) { return true; } if (contact.note().contains(filterString, Qt::CaseInsensitive)) { return true; } if (contact.url().url().url().contains(filterString, Qt::CaseInsensitive)) { return true; } const QStringList customs = contact.customs(); count = customs.count(); for (int i = 0; i < count; ++i) { if (customs.at(i).contains(filterString, Qt::CaseInsensitive)) { return true; } } return false; } bool contactGroupMatchesFilter(const KContacts::ContactGroup &group, const QString &filterString) { if (group.name().contains(filterString, Qt::CaseInsensitive)) { return true; } const uint count = group.dataCount(); for (uint i = 0; i < count; ++i) { if (group.data(i).name().contains(filterString, Qt::CaseInsensitive)) { return true; } if (group.data(i).email().contains(filterString, Qt::CaseInsensitive)) { return true; } } return false; } bool AddressSortProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const { KContacts::Addressee contact = _provider->getAddressee(row, parent); if( contact.isEmpty() ) { return true; } else { const QString p = filterRegExp().pattern(); return contactMatchesFilter(contact, p ); } return true; } QVariant AddressSortProxyModel::headerData(int section, Qt::Orientation orientation, int role) const { if ( orientation == Qt::Horizontal && role == Qt::DisplayRole) { if( section == 0 ) { return i18n("Name"); } else if ( section == 1 ) { return i18n("Address"); } } return QVariant(); } /* ------------------------------------------------------------------------------ */ KraftContactViewer::KraftContactViewer(QWidget *parent) :QWidget(parent) #ifdef HAVE_AKONADI , _contactViewer(0) #endif { QVBoxLayout *lay = new QVBoxLayout; lay->setMargin(0); setLayout(lay); #ifdef HAVE_AKONADI #if AKONADICONTACT_VERSION >= QT_VERSION_CHECK(5, 24, 0) _contactViewer = new ContactEditor::ContactViewer; #else _contactViewer = new Akonadi::ContactViewer; #endif _contactViewer->setShowQRCode(false); lay->addWidget(_contactViewer); #endif } void KraftContactViewer::setContact( const KContacts::Addressee& contact) { #ifdef HAVE_AKONADI _contactViewer->setRawContact(contact); #else Q_UNUSED(contact); #endif } /* ------------------------------------------------------------------------------ */ AddressSelectorWidget::AddressSelectorWidget(QWidget *parent, bool /* showText */) : QSplitter(parent), _provider(0) { setupUi(); restoreState(); } AddressSelectorWidget::~AddressSelectorWidget() { } void AddressSelectorWidget::setupUi() { _provider = new AddressProvider(this); setChildrenCollapsible(false); // Left page of the splitter QWidget *leftW = new QWidget; QVBoxLayout *leftLay = new QVBoxLayout; leftW->setLayout(leftLay); this->addWidget(leftW); QHBoxLayout *searchLay = new QHBoxLayout; leftLay->addLayout(searchLay); QLabel *searchLabel = new QLabel(i18n("&Search:")); searchLay->addWidget( searchLabel ); QLineEdit *edit = new QLineEdit; searchLabel->setBuddy(edit); edit->setClearButtonEnabled(true); searchLay->addWidget( edit ); connect(edit, SIGNAL(textChanged(QString)), SLOT(slotFilterTextChanged(QString))); #ifdef HAVE_AKONADI _addressTreeView = new Akonadi::EntityTreeView( this ); #else _addressTreeView = new QTreeView; #endif _addressTreeView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); leftLay->addWidget(_addressTreeView); mProxyModel = new AddressSortProxyModel(_provider, this); mProxyModel->setSourceModel(_provider->model()); _addressTreeView->setModel(mProxyModel); connect(_addressTreeView, SIGNAL(activated(QModelIndex)), this, SLOT(slotAddresseeSelected(QModelIndex))); mProxyModel->sort(0); // the right side QWidget *rightW = new QWidget; QVBoxLayout *rightLay = new QVBoxLayout; rightW->setLayout(rightLay); this->addWidget(rightW); _contactViewer = new KraftContactViewer; _contactViewer->setMinimumWidth(200); rightLay->addWidget(_contactViewer); // Buttons to create and edit QHBoxLayout *hboxBot = new QHBoxLayout; hboxBot->addStretch(4); rightLay->addLayout( hboxBot ); mButEditContact = new QPushButton(i18n("Edit Contact...")); mButEditContact->setToolTip( i18n("Edit the currently selected contact" )); mButEditContact->setEnabled( false ); hboxBot->addWidget( mButEditContact ); QPushButton *butCreateContact = new QPushButton(i18n("New Contact...")); butCreateContact->setToolTip( i18n("Create a new Contact" ) ); hboxBot->addWidget( butCreateContact ); connect(butCreateContact,SIGNAL(clicked()),SLOT(slotCreateNewContact())); connect(mButEditContact, SIGNAL(clicked()),SLOT(slotEditContact())); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); } void AddressSelectorWidget::slotFilterTextChanged( const QString& filter) { // qDebug() << "Filter: " << filter; mProxyModel->setFilterRegExp(QRegExp(filter, Qt::CaseInsensitive, QRegExp::RegExp)); // mProxyModel.setFilterFixedString(filter); } void AddressSelectorWidget::restoreState() { const QList sizes = KraftSettings::self()->addressPickerSplitterSize(); setSizes(sizes); const QByteArray state = QByteArray::fromBase64( KraftSettings::self()->addressPickerTreeviewState().toLatin1() ); _addressTreeView->header()->restoreState(state); } void AddressSelectorWidget::saveState() { const QList s = sizes(); KraftSettings::self()->setAddressPickerSplitterSize(s); const QByteArray state = _addressTreeView->header()->saveState().toBase64(); KraftSettings::self()->setAddressPickerTreeviewState(state); } bool AddressSelectorWidget::backendUp() const { bool re = false; if( _provider ) { re = _provider->backendUp(); } return re; } void AddressSelectorWidget::slotCreateNewContact() { #ifdef HAVE_AKONADI #if AKONADICONTACT_VERSION >= QT_VERSION_CHECK(5, 24, 0) _addressEditor = new ContactEditor::ContactEditorDialog(ContactEditor::ContactEditorDialog::EditMode, this ); #else _addressEditor = new Akonadi::ContactEditorDialog(Akonadi::ContactEditorDialog::CreateMode, this ); #endif _addressEditor->show(); #endif } void AddressSelectorWidget::slotAddresseeSelected(QModelIndex index) { if ( index.isValid() ) { QModelIndex sourceIdx = mProxyModel->mapToSource(index); KContacts::Addressee contact = _provider->getAddressee( sourceIdx ); qDebug() << "----------- " << contact.formattedName() << contact.uid(); _contactViewer->setContact(contact); emit addressSelected(contact); mButEditContact->setEnabled( true ); } else { // qDebug () << "No address was selected!"; mButEditContact->setEnabled( false ); } } void AddressSelectorWidget::slotEditContact() { #ifdef HAVE_AKONADI if( _addressTreeView->selectionModel()->hasSelection() ) { QModelIndex index = _addressTreeView->selectionModel()->currentIndex(); if ( index.isValid() ) { const Akonadi::Item item = index.data( Akonadi::EntityTreeModel::ItemRole ).value(); if ( item.isValid() && item.hasPayload() ) { #if AKONADICONTACT_VERSION >= QT_VERSION_CHECK(5, 24, 0) _addressEditor = new ContactEditor::ContactEditorDialog(ContactEditor::ContactEditorDialog::EditMode, this ); #else _addressEditor = new Akonadi::ContactEditorDialog(Akonadi::ContactEditorDialog::CreateMode, this ); #endif _addressEditor->setContact( item ); _addressEditor->show(); } } } #endif } kraft-1.1/src/addressselectorwidget.h000066400000000000000000000076331450127457600200400ustar00rootroot00000000000000/*************************************************************************** addressselectorwidget - Address Selection Widget ------------------- begin : Jul 2011 copyright : (C) 2011- by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef ADDRESSSELECTORWIDGET_H #define ADDRESSSELECTORWIDGET_H #include #include #include #ifdef HAVE_AKONADI #include #if AKONADI_VERSION >= QT_VERSION_CHECK(5,20,0) #include #else #define AKONADICONTACT_VERSION AKONADI_VERSION #endif #if AKONADICONTACT_VERSION >= QT_VERSION_CHECK(5, 24, 0) #include #include #elif AKONADICONTACT_VERSION >= QT_VERSION_CHECK(5, 20, 0) #include #include #else #include #include #endif #endif #include #include "addressprovider.h" using namespace KContacts; class QLabel; class QTreeView; class QuickSearchWidget; class QItemSelectionModel; class QuickSearchWidget; class QPushButton; /* =============================================================== */ class KraftContactViewer : public QWidget { Q_OBJECT public: explicit KraftContactViewer(QWidget *parent = 0); void setContact( const KContacts::Addressee& contact); private: #ifdef HAVE_AKONADI #if AKONADICONTACT_VERSION >= QT_VERSION_CHECK(5, 24, 0) ContactEditor::ContactViewer *_contactViewer; #else Akonadi::ContactViewer *_contactViewer; #endif #endif }; class AddressSortProxyModel : public QSortFilterProxyModel { Q_OBJECT public: AddressSortProxyModel(AddressProvider *provider, QObject *parent = 0); QVariant headerData(int section, Qt::Orientation orientation, int role) const; protected: bool filterAcceptsRow(int row, const QModelIndex &parent) const; // bool lessThan(const QModelIndex &left, const QModelIndex &right) const Q_DECL_OVERRIDE; public: QString mFilter; AddressProvider *_provider; }; /* =============================================================== */ class AddressSelectorWidget : public QSplitter { Q_OBJECT public: explicit AddressSelectorWidget(QWidget *parent = 0, bool showText = true ); ~AddressSelectorWidget(); bool backendUp() const; signals: void addressSelected(KContacts::Addressee); public slots: void saveState(); protected slots: void slotCreateNewContact(); void slotEditContact(); void restoreState(); void slotFilterTextChanged( const QString& filter); private slots: void slotAddresseeSelected(QModelIndex index); private: void setupUi(); QPushButton *mButEditContact; AddressProvider *_provider; AddressSortProxyModel *mProxyModel; QTreeView *_addressTreeView; KraftContactViewer *_contactViewer; #ifdef HAVE_AKONADI #if AKONADICONTACT_VERSION >= QT_VERSION_CHECK(5, 24, 0) ContactEditor::ContactEditorDialog *_addressEditor; #else Akonadi::ContactEditorDialog *_addressEditor; #endif #endif }; #endif // AKONADIADDRESSSELECTOR_H kraft-1.1/src/addresstemplateprovider.cpp000066400000000000000000000050621450127457600207270ustar00rootroot00000000000000/*************************************************************************** addresstemplateprovider - template provider class for addresses ------------------- begin : Jun 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include "addresstemplateprovider.h" #include "texteditdialog.h" #include "doctext.h" #include "defaultprovider.h" AddressTemplateProvider::AddressTemplateProvider( QWidget *parent ) :TemplateProvider( parent ), mParent( parent ) { } void AddressTemplateProvider::slotNewTemplate() { // qDebug () << "SlotNewTemplate for addresses called!"; KRun::runCommand( QString::fromLatin1( "kaddressbook --new-contact" ), QString::fromLatin1("kaddressbook" ), "address", mParent, "" ); } void AddressTemplateProvider::slotEditTemplate() { // qDebug () << "SlotEditTemplate called!"; KRun::runCommand( QString::fromLatin1( "kaddressbook --uid %1" ).arg( mCurrentAddress.uid() ), QString::fromLatin1("kaddressbook" ), "address", mParent, "" ); } void AddressTemplateProvider::slotDeleteTemplate() { } void AddressTemplateProvider::slotSetCurrentAddress( const Addressee& adr ) { // qDebug () << "Current Address was set to " << adr.realName(); mCurrentAddress = adr; } void AddressTemplateProvider::slotTemplateToDocument() { if( mCurrentAddress.isEmpty() ) { // qDebug () << "Current address is empty, that should not happen"; return; } // qDebug () << "Moving address of " << mCurrentAddress.realName() << " to document"; emit addressToDocument( mCurrentAddress ); } void AddressTemplateProvider::slotInsertTemplateToDocument() { // It does not really make sense to insert an address text while not replacing it completely. } kraft-1.1/src/addresstemplateprovider.h000066400000000000000000000033531450127457600203750ustar00rootroot00000000000000/*************************************************************************** addresstemplateprovider - template provider class for address data ------------------- begin : Jun 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef ADDRESSTEMPLATEPROVIDER_H #define ADDRESSTEMPLATEPROVIDER_H #include #include "templateprovider.h" #include "doctext.h" #include using namespace KContacts; class AddressTemplateProvider : public TemplateProvider { Q_OBJECT public: AddressTemplateProvider( QWidget* ); signals: void newAddress( Addressee ); void addressToDocument( const Addressee& ); public slots: void slotNewTemplate() override; void slotEditTemplate() override; void slotDeleteTemplate() override; void slotTemplateToDocument() override; void slotInsertTemplateToDocument() override; void slotSetCurrentAddress( const Addressee& ); private: Addressee mCurrentAddress; QWidget *mParent; }; #endif kraft-1.1/src/alldocsview.cpp000066400000000000000000000346501450127457600163140ustar00rootroot00000000000000/*************************************************************************** alldocsview.cpp ------------------- begin : Wed Mar 15 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "models/documentmodel.h" #include "models/documentproxymodels.h" #include "filterheader.h" #include "alldocsview.h" #include "documentman.h" #include "docguardedptr.h" #include "kraftdoc.h" #include "kraftdb.h" #include "defaultprovider.h" #include "docdigestdetailview.h" #include "kraftsettings.h" AllDocsView::AllDocsView( QWidget *parent ) : QWidget( parent ), mTableModel(0), mDateModel(0) { QVBoxLayout *box = new QVBoxLayout; setLayout( box ); box->setMargin( 0 ); box->setSpacing( 0 ); _searchLine = new QLineEdit(this); _searchLine->setClearButtonEnabled(true); _searchLine->setMinimumWidth(200); connect( _searchLine, SIGNAL(textChanged(QString)), this, SLOT(slotSearchTextChanged(QString)) ); QComboBox *filterCombo = new QComboBox; filterCombo->addItem(i18n("All documents")); filterCombo->addItem(i18n("Documents of last week")); filterCombo->addItem(i18n("Documents of last month")); // filterCombo->addItem("Document Type"); connect( filterCombo, SIGNAL(activated(int)), this, SLOT(slotAmountFilterChanged(int))); QHBoxLayout *hbox = new QHBoxLayout; QLabel *l1 = new QLabel(i18n("&Show: ")); l1->setBuddy(filterCombo); hbox->addWidget(l1); hbox->addWidget(filterCombo); hbox->addStretch( 2 ); QLabel *lab = new QLabel; lab->setText( i18n("&Search: ") ); lab->setBuddy( _searchLine); hbox->addWidget( lab ); hbox->addWidget( _searchLine); box->addLayout( hbox ); QFrame *f = new QFrame; f->setLineWidth( 2 ); f->setMidLineWidth( 3 ); f->setFrameStyle( QFrame::HLine | QFrame::Raised ); f->setFixedHeight( 10 ); box->addWidget( f ); box->addWidget(initializeTreeWidget()); } AllDocsView::~AllDocsView() { const QByteArray state = _tableView->horizontalHeader()->saveState().toBase64(); KraftSettings::self()->setDigestListColumnsAll( state ); const QByteArray state1 = _dateView->header()->saveState().toBase64(); KraftSettings::self()->setDigestListColumnsTime(state1); KraftSettings::self()->save(); } void AllDocsView::slotAmountFilterChanged(int entryNo) { int num = -1; if( entryNo == 1 ) { num = 7; } else if( entryNo == 2 ) { num = 31; } mTableModel->setMaxRows(num); mDateModel->setMaxRows(num); } void AllDocsView::slotSearchTextChanged(const QString& newStr ) { mTableModel->setFilterRegExp(newStr); mDateModel->setFilterRegExp(newStr); } QWidget* AllDocsView::initializeTreeWidget() { //Note: Currently building the views is done in slotBuildView() that is called from the portal // because otherwise we'd access the database before it is initialized _tableView = new QTableView; _dateView = new QTreeView; //Initialise mAllMenu = new QMenu( _tableView ); mAllMenu->setTitle( i18n("Document Actions")); //Add treewidgets to the toolbox: All docs view QVBoxLayout *vb1 = new QVBoxLayout; vb1->setMargin(0); _stack = new QStackedWidget(this); _stack->addWidget(_tableView); _stack->addWidget(_dateView); vb1->addWidget( _stack ); mAllViewDetails = new DocDigestDetailView; connect( mAllViewDetails, &DocDigestDetailView::showLastPrint, this, &AllDocsView::slotOpenLastPrinted); connect( mAllViewDetails, &DocDigestDetailView::exportXRechnung , this, &AllDocsView::slotExportXRechnung); vb1->addWidget( mAllViewDetails ); QWidget *w = new QWidget; w->setLayout(vb1); // return w; } void AllDocsView::setView( ViewType type ) { // change the document listing widget QModelIndex current; if( type == FlatList) { _stack->setCurrentIndex(0); current = _tableView->currentIndex(); } else { _stack->setCurrentIndex(1); current = _dateView->currentIndex(); } // clear the details view mAllViewDetails->slotClearView(); if( current.isValid() > 0 ) { slotCurrentChanged(current, QModelIndex()); } else { // workaround, not cool. mCurrentlySelected = QModelIndex(); } } void AllDocsView::slotBuildView() { const QByteArray headerStateTable = QByteArray::fromBase64( KraftSettings::self()->digestListColumnsAll().toLatin1() ); const QByteArray headerStateDate = QByteArray::fromBase64( KraftSettings::self()->digestListColumnsTime().toLatin1() ); mDateModel = new DocumentFilterModel(-1, this); mDateModel->setEnableTreeview(true); mTableModel = new DocumentFilterModel(-1, this); mTableModel->setEnableTreeview(false); _tableView->setModel(mTableModel); _dateView->setModel(mDateModel); _tableView->sortByColumn(DocumentModel::Document_CreationDateRaw, Qt::DescendingOrder); _tableView->verticalHeader()->hide(); _tableView->setSortingEnabled(true); _tableView->horizontalHeader()->setSectionsMovable( true ); _tableView->horizontalHeader()->setSortIndicatorShown( true ); _tableView->horizontalHeader()->restoreState( headerStateTable ); _tableView->setSelectionBehavior( QAbstractItemView::SelectRows ); _tableView->setShowGrid( false ); _tableView->hideColumn( DocumentModel::Document_Id ); _tableView->hideColumn( DocumentModel::Document_ClientId ); _tableView->hideColumn( DocumentModel::Document_ClientAddress ); _tableView->showColumn( DocumentModel::Document_ClientName ); _tableView->showColumn( DocumentModel::Document_CreationDateRaw); _tableView->hideColumn( DocumentModel::Document_CreationDate); _tableView->hideColumn( DocumentModel::Document_Id_Raw); _tableView->hideColumn( DocumentModel::Treestruct_Type); _tableView->hideColumn( DocumentModel::Treestruct_Month); _tableView->hideColumn( DocumentModel::Treestruct_Year); _dateView->header()->restoreState( headerStateDate ); _dateView->hideColumn( DocumentModel::Document_ClientId ); _dateView->hideColumn( DocumentModel::Document_ClientAddress ); _dateView->showColumn( DocumentModel::Document_ClientName ); _dateView->showColumn( DocumentModel::Document_CreationDateRaw); _dateView->hideColumn( DocumentModel::Document_CreationDate); _dateView->hideColumn( DocumentModel::Document_Id_Raw); _dateView->hideColumn( DocumentModel::Treestruct_Type); _dateView->hideColumn( DocumentModel::Treestruct_Month); _dateView->hideColumn( DocumentModel::Treestruct_Year); _dateView->setSelectionBehavior( QAbstractItemView::SelectRows ); //Initialize common style options connect( _tableView->selectionModel(), SIGNAL( currentRowChanged(QModelIndex,QModelIndex) ), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex))); connect( _dateView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex))); connect( _tableView, SIGNAL( doubleClicked(QModelIndex) ), this, SLOT( slotDocOpenRequest(QModelIndex) ) ); connect( _dateView, SIGNAL( doubleClicked(QModelIndex) ), this, SLOT( slotDocOpenRequest(QModelIndex) ) ); _tableView->setAlternatingRowColors( true ); _dateView->setAlternatingRowColors(false); _tableView->setSelectionMode( QAbstractItemView::SingleSelection ); _tableView->setEditTriggers( QAbstractItemView::NoEditTriggers ); _dateView->setEditTriggers( QAbstractItemView::NoEditTriggers ); _dateView->setExpandsOnDoubleClick( false ); // expand the current year and month QModelIndex startIdx = mDateModel->index(0,DocBaseModel::Treestruct_Year, QModelIndex()); QModelIndexList yearIndexes = mDateModel->match(startIdx, Qt::DisplayRole, QVariant(QDate::currentDate().year()) ); if( yearIndexes.size() > 0 ) { QModelIndex yearIndx = mDateModel->index(yearIndexes.first().row(), 0, yearIndexes.first().parent()); _dateView->setExpanded(yearIndx,true); QModelIndex startIdxM = mDateModel->index(0, DocBaseModel::Treestruct_Month, yearIndx); QModelIndexList monthIndexes = mDateModel->match(startIdxM, Qt::DisplayRole, QVariant(QDate::currentDate().month()) ); if( monthIndexes.size() > 0 ) { QModelIndex mIdx = monthIndexes.first(); QModelIndex rIdx = mDateModel->index(mIdx.row(), 0, mIdx.parent()); _dateView->setExpanded(rIdx, true); } } connect(KraftDB::self(), &KraftDB::docDatabaseChanged, this, &AllDocsView::slotUpdateView); } void AllDocsView::slotUpdateView() { QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) ); static_cast(mDateModel->sourceModel())->resetData(); static_cast(mTableModel->sourceModel())->resetData(); mCurrentlySelected = QModelIndex(); QApplication::restoreOverrideCursor(); } void AllDocsView::contextMenuEvent( QContextMenuEvent * event ) { mAllMenu->popup( event->globalPos() ); } void AllDocsView::slotExportXRechnung() { // qDebug () << "slotOpenLastPrinted hit! "; emit exportXRechnungArchivedDocument( mLatestArchivedDigest ); } void AllDocsView::slotOpenLastPrinted( ) { // qDebug () << "slotOpenLastPrinted hit! "; emit openArchivedDocument( mLatestArchivedDigest ); } ArchDocDigest AllDocsView::currentLatestArchivedDoc() const { return mLatestArchivedDigest; } void AllDocsView::slotDocOpenRequest( QModelIndex index ) { Q_UNUSED(index) const QString id = currentDocumentId(); emit openDocument( id ); } int AllDocsView::currentDocumentRow() const { return mCurrentlySelected.row(); } QString AllDocsView::currentDocumentId( ) const { bool isDoc = true; DocBaseModel *model; if( _stack->currentIndex() == 0 ) { model = static_cast( mTableModel->sourceModel() ); } else { model = static_cast( mDateModel->sourceModel() ); isDoc = model->isDocument(mCurrentlySelected); } QString id; if( isDoc ) { QModelIndex idIndx = model->index(mCurrentlySelected.row(), DocumentModel::Document_Id_Raw, mCurrentlySelected.parent()); id = idIndx.data( Qt::DisplayRole ).toString(); } return id; } void AllDocsView::slotCurrentChanged( QModelIndex index, QModelIndex previous ) { Q_UNUSED(previous); if(index.isValid()) { DocBaseModel *model; bool isDoc = true; bool isDateModel= false; if( _stack->currentIndex() == 0 ) { mCurrentlySelected = mTableModel->mapToSource(index); model = static_cast( mTableModel->sourceModel() ); } else { isDateModel = true; mCurrentlySelected = mDateModel->mapToSource(index); model = static_cast( mDateModel->sourceModel() ); isDoc = model->isDocument(mCurrentlySelected); } /* get the corresponding document id */ if( isDoc ) { DocDigest digest; QModelIndex idIndx = model->index(mCurrentlySelected.row(), DocumentModel::Document_Ident, mCurrentlySelected.parent()); const QString id = idIndx.data( Qt::DisplayRole ).toString(); digest = model->digest( mCurrentlySelected ); emit docSelected(digest); mAllViewDetails->slotShowDocDetails( digest ); if( digest.archDocDigestList().size() > 0 ) { mLatestArchivedDigest = digest.archDocDigestList()[0]; } else { mLatestArchivedDigest = ArchDocDigest(); } } else { const QModelIndex idIndx = model->index(mCurrentlySelected.row(), DocumentModel::Treestruct_Type, mCurrentlySelected.parent()); int type = idIndx.data( Qt::DisplayRole ).toInt(); if( isDateModel) { const QModelIndex yIndx = model->index(mCurrentlySelected.row(), DocumentModel::Treestruct_Year, mCurrentlySelected.parent()); int year = yIndx.data( Qt::DisplayRole ).toInt(); if( type == AbstractIndx::MonthType ) { const QModelIndex mIndx = model->index(mCurrentlySelected.row(), DocumentModel::Treestruct_Month, mCurrentlySelected.parent()); int month = mIndx.data( Qt::DisplayRole ).toInt(); mAllViewDetails->slotShowMonthDetails(year, month); } else if( type == AbstractIndx::YearType ) { mAllViewDetails->slotShowYearDetails(year); } } } } else { // qDebug () << "Got invalid index, clearing digest view."; emit docSelected( DocDigest() ); mAllViewDetails->slotClearView(); } //// qDebug () << "Supposed row: " << sourceIndex.row() << " Supposed ID: " << DocumentModel::self()->data(sourceIndex, Qt::DisplayRole); } QVector AllDocsView::contextMenus() { QVector menus; menus.append( mAllMenu); return menus; } kraft-1.1/src/alldocsview.h000066400000000000000000000056751450127457600157660ustar00rootroot00000000000000/*************************************************************************** alldocsview.h - digest view of all docs with filter ------------------- begin : Sat Mar 11 2017 copyright : (C) 2017 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef ALLDOCSVIEW_H #define ALLDOCSVIEW_H #include #include #include #include #include #include #include "models/datemodel.h" #include "docdigest.h" #include "docguardedptr.h" #include "models/documentproxymodels.h" class QPushButton; class dbID; class ArchDocDigest; class QContextMenuEvent; class QToolBox; class DocDigestDetailView; class AllDocsView : public QWidget { Q_OBJECT public: typedef enum {FlatList, TreeView} ViewType; AllDocsView( QWidget *parent = 0 ); ~AllDocsView(); int currentDocumentRow() const; QString currentDocumentId( ) const; ArchDocDigest currentLatestArchivedDoc() const; QVector contextMenus(); public slots: void slotBuildView(); void slotUpdateView(); void setView(ViewType type); protected: void contextMenuEvent( QContextMenuEvent* ); QWidget *initializeTreeWidget(); protected slots: void slotDocOpenRequest( QModelIndex ); void slotCurrentChanged( QModelIndex, QModelIndex ); void slotOpenLastPrinted(); void slotExportXRechnung(); void slotSearchTextChanged(const QString& newStr ); void slotAmountFilterChanged(int entryNo); signals: void createDocument(); void openDocument( const QString& ); void viewDocument( const QString& ); void copyDocument( const QString& ); void docSelected( const DocDigest& ); void openArchivedDocument( const ArchDocDigest& ); void exportXRechnungArchivedDocument(const ArchDocDigest&); private: QTableView *_tableView; QTreeView *_dateView; QStackedWidget *_stack; DocDigestDetailView *mAllViewDetails; QModelIndex mCurrentlySelected; DocumentFilterModel *mTableModel; DocumentFilterModel *mDateModel; QMenu *mAllMenu; QPushButton *mNewDocButton; ArchDocDigest mLatestArchivedDigest; QLineEdit *_searchLine; }; #endif kraft-1.1/src/archdoc.cpp000066400000000000000000000210401450127457600153700ustar00rootroot00000000000000/*************************************************************************** ArchDoc.cpp - an archived document. ------------------- begin : Mit Dez 31 19:24:05 CET 2003 copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include // application specific includes #include "archiveman.h" #include "archdoc.h" #include "documentman.h" #include "kraftdb.h" #include "defaultprovider.h" #include "kraftsettings.h" #include "format.h" namespace { QString multilineHtml( const QString& str ) { QString re {str.toHtmlEscaped()}; re.replace( '\n', "
            "); return re; } } // end namespace ArchDoc::ArchDoc() : mAttributes( QLatin1String("ArchDoc")) { } ArchDoc::ArchDoc( const dbID& id ) : mAttributes( QLatin1String("ArchDoc")) { /* load archive from database */ loadFromDb( id ); } QString ArchDoc::docIdentifier() const { QString re = docTypeStr(); return i18n("%1 for %2 (Id %3)", re, ident() ); } QString ArchDoc::dateStr() const { return Format::toDateString(mDate, KraftSettings::self()->dateFormat()); } QString ArchDoc::dateStrISO() const { return mDate.toString("yyyy-MM-dd"); } QString ArchDoc::preText() const { return mPreText; } QString ArchDoc::preTextHtml() const { return multilineHtml(mPreText); } QString ArchDoc::postText() const { return mPostText; } QString ArchDoc::postTextHtml() const { return multilineHtml(mPostText); } Geld ArchDoc::nettoSum() const { const Geld g = positions().sumPrice(); return g; } Geld ArchDoc::bruttoSum() const { Geld g = nettoSum(); const Geld ts = taxSum(); g += ts; return g; } Geld ArchDoc::taxSum() const { const Geld g = positions().taxSum(); return g; } Geld ArchDoc::fullTaxSum() const { return positions().fullTaxSum(); } Geld ArchDoc::reducedTaxSum() const { return positions().reducedTaxSum(); } QString ArchDoc::fullTaxPercentStr() const { return Format::localeDoubleToString(mTax, *DefaultProvider::self()->locale()); } QString ArchDoc::reducedTaxPercentStr() const { return Format::localeDoubleToString(mReducedTax, *DefaultProvider::self()->locale()); } QString ArchDoc::taxPercentStr() const { DocPositionBase::TaxType tt = mPositions.listTaxation(); if (tt == DocPositionBase::TaxType::TaxFull) { return fullTaxPercentStr(); } else if (tt == DocPositionBase::TaxType::TaxReduced) { return reducedTaxPercentStr(); } return QString(); } QString ArchDoc::taxPercentNum() const { DocPositionBase::TaxType tt = mPositions.listTaxation(); if (tt == DocPositionBase::TaxType::TaxFull) { return fullTaxPercentNum(); } else if (tt == DocPositionBase::TaxType::TaxReduced) { return reducedTaxPercentNum(); } return QString(); } QString ArchDoc::fullTaxPercentNum() const { double t = tax(); return QString::number(t, 'f', 2); } QString ArchDoc::reducedTaxPercentNum() const { double t = reducedTax(); return QString::number(t, 'f', 2); } double ArchDoc::tax() const { return mTax; } double ArchDoc::reducedTax() const { return mReducedTax; } void ArchDoc::loadFromDb( dbID id ) { mArchDocID = id; QSqlQuery q; q.prepare("SELECT archDocID, ident, docType, clientAddress, clientUid, " // pos 0..4 "salut, goodbye, printDate, date, pretext, posttext, country, language, " // pos 5..12 "projectLabel, predecessor, tax, reducedTax, state from archdoc WHERE archDocID=:id" ); // pos 13..17 q.bindValue(":id", id.toInt()); q.exec(); // qDebug () << "Loading document id " << id.toString(); if( q.next()) { QString docID; QString country; QString lang; docID = q.value( 0 ).toString(); mIdent = q.value( 1 ).toString(); mDocTypeStr = q.value( 2 ).toString(); mAddress = q.value( 3 ).toString(); mClientUid = q.value( 4 ).toString(); mSalut = q.value( 5 ).toString(); mGoodbye = q.value( 6 ).toString(); QVariant v = q.value( 7 ); mPrintDate = v.toDateTime(); mDate = q.value( 8 ).toDate(); mPreText = KraftDB::self()->mysqlEuroDecode( q.value( 9 ).toString() ); mPostText = KraftDB::self()->mysqlEuroDecode( q.value( 10 ).toString() ); country = q.value( 11 ).toString(); lang = q.value( 12 ).toString(); mProjectLabel = q.value( 13 ).toString(); mPredecessor = q.value( 14 ).toString(); mTax = q.value( 15 ).toDouble(); mReducedTax = q.value( 16 ).toDouble(); mState = q.value( 17 ).toInt(); loadItems( docID ); mAttributes.load(id); } else { // qDebug () << "ERR: Could not load archived doc with id " << id.toString(); } } void ArchDoc::loadItems( const QString& archDocId ) { mPositions.clear(); if ( archDocId.isEmpty() /* || ! archDocId.isNum() */ ) { // qDebug () << "ArchDocId is not crappy: " << archDocId; return; } QSqlQuery q; q.prepare("SELECT archPosID, archDocID, ordNumber, kind, postype, text, amount, " // pos 0..6 "unit, price, overallPrice, taxType FROM archdocpos WHERE archDocID=:id ORDER BY ordNumber"); // pos 7..10 q.bindValue(":id", archDocId); if( !q.exec() ) { qDebug() << "Error: " << q.lastError().nativeErrorCode(); } mPositions.setTaxes(mTax, mReducedTax); while( q.next() ) { ArchDocPosition pos; pos.mPosNo = q.value( 2 ).toString(); pos.mKind = q.value( 3 ).toString(); pos.mText = q.value( 5 ).toString(); pos.mAmount = q.value( 6 ).toDouble(); pos.mUnit = q.value( 7 ).toString(); pos.mUnitPrice = Geld( q.value( 8 ).toDouble() ); pos.mOverallPrice = q.value( 9 ).toDouble(); int tt = q.value( 10 ).toInt(); if ( tt == 1 ) pos.mTaxType = DocPositionBase::TaxNone; else if ( tt == 2 ) pos.mTaxType = DocPositionBase::TaxReduced; else if ( tt == 3 ) pos.mTaxType = DocPositionBase::TaxFull; mPositions.append( pos ); } } QList ArchDoc::itemslist() const { return mPositions; } QDateTime ArchDoc::sentOutDate() { QDateTime re; if ( mAttributes.hasAttribute( SentOutDateC ) ) { re = mAttributes["sentOutDate"].value().toDateTime(); } return re; } void ArchDoc::setSentOutDate( const QDateTime& dt ) { QString attName(SentOutDateC); if( dt.isValid() ) { Attribute att(attName); att.setPersistant(true); att.setValue(dt); mAttributes[attName] = att; } else { mAttributes.markDelete(attName); } mAttributes.save(mArchDocID); } ArchDocDigest ArchDoc::toDigest() const { return ArchDocDigest(mPrintDate, mState, mIdent, mDocTypeStr, mArchDocID); } /* ###################################################################### */ ArchDocDigest::ArchDocDigest() { } ArchDocDigest::ArchDocDigest(QDateTime dt, int s, const QString& ident, const QString & docType, dbID id ) : mPrintDate( dt ), mState( s ), mArchDocId( id ), mIdent( ident ), mDocTypeStr(docType) { } ArchDocDigest::~ArchDocDigest() { } QString ArchDocDigest::pdfArchiveFileName() const { const QString outputDir = ArchiveMan::self()->pdfBaseDir(); const QString filename = ArchiveMan::self()->archiveFileName(archDocIdent(), archDocId().toString(), "pdf" ); const QString file = QString( "%1/%2" ).arg( outputDir ).arg( filename ); return file; } bool ArchDocDigest::isInvoice() const { // This is just a work around and should be fixed with an attribute for the doctype // at some point. return (mDocTypeStr == QStringLiteral("Rechnung")); } /* ###################################################################### */ kraft-1.1/src/archdoc.h000066400000000000000000000172361450127457600150510ustar00rootroot00000000000000/*************************************************************************** archdoc.h - ------------------- begin : Sep 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef ARCHDOC_H #define ARCHDOC_H // include files for QT #include #include #include #include #include "archdocposition.h" #include "geld.h" #include "dbids.h" class QLocale; class AttributeMap; class ArchDocDigest { public: /** Constructor for the fileclass of the application */ ArchDocDigest(); ArchDocDigest( QDateTime, int, const QString&, const QString&, dbID ); /** Destructor for the fileclass of the application */ virtual ~ArchDocDigest(); QDateTime printDate() const { return mPrintDate; } int archDocState() const { return mState; } dbID archDocId() const { return mArchDocId; } QString archDocIdent() const { return mIdent; } QString docTypeStr() const { return mDocTypeStr; } QString pdfArchiveFileName() const; // FIXME: This is a workaround for the XRechnung - so far only the german // doctype "Rechnung" enables the XRechnung support. bool isInvoice() const; protected: QDateTime mPrintDate; int mState; dbID mArchDocId; QString mIdent; QString mDocTypeStr; }; class ArchDoc: public QObject, public ArchDocDigest { Q_OBJECT Q_PROPERTY(QString docType READ docTypeStr) Q_PROPERTY(QString address READ address) Q_PROPERTY(QString clientUid READ clientUid) Q_PROPERTY(QString ident READ ident) Q_PROPERTY(QString salut READ salut) Q_PROPERTY(QString goodbye READ goodbye) Q_PROPERTY(QString preText READ preText) Q_PROPERTY(QString preTextHtml READ preTextHtml) Q_PROPERTY(QString postText READ postText) Q_PROPERTY(QString postTextHtml READ postTextHtml) Q_PROPERTY(QString projectLabel READ projectLabel) Q_PROPERTY(QString predecessor READ predecessor) Q_PROPERTY(QString docIDStr READ archDocIdStr) Q_PROPERTY(QString docIdentifier READ docIdentifier) Q_PROPERTY(QString dateStr READ dateStr) Q_PROPERTY(QString dateStrISO READ dateStrISO) Q_PROPERTY(QString nettoSumStr READ nettoSumStr) Q_PROPERTY(QString nettoSumNum READ nettoSumNum) Q_PROPERTY(QString bruttoSumStr READ bruttoSumStr) Q_PROPERTY(QString bruttoSumNum READ bruttoSumNum) Q_PROPERTY(QString taxSumStr READ taxSumStr) Q_PROPERTY(QString taxSumNum READ taxSumNum) Q_PROPERTY(QString fullTaxSumStr READ fullTaxSumStr) Q_PROPERTY(QString fullTaxSumNum READ fullTaxSumNum) Q_PROPERTY(QString reducedTaxSumStr READ reducedTaxSumStr) Q_PROPERTY(QString reducedTaxSumNum READ reducedTaxSumNum) Q_PROPERTY(QString dueDateStrISO READ dueDate) Q_PROPERTY(QString buyerReference READ buyerRef) Q_PROPERTY(QString fullTaxPercentNum READ fullTaxPercentNum) Q_PROPERTY(QString fullTaxPercentStr READ fullTaxPercentStr) Q_PROPERTY(QString reducedTaxPercentNum READ reducedTaxPercentNum) Q_PROPERTY(QString reducedTaxPercentStr READ reducedTaxPercentStr) Q_PROPERTY(QString taxPercentStr READ taxPercentStr) Q_PROPERTY(QString taxPercentNum READ taxPercentNum) Q_PROPERTY(QString taxMarkerFull READ taxMarkerFull) Q_PROPERTY(QString taxMarkerReduced READ taxMarkerReduced) Q_PROPERTY(QList items READ itemslist) Q_PROPERTY(bool hasIndividualTaxation READ hasIndividualTaxation) Q_PROPERTY(bool isInvoice READ isInvoice) public: const QString SentOutDateC {"SentOutDate"}; /** Constructor for the fileclass of the application */ ArchDoc(); ArchDoc( const dbID& ); /** Destructor for the fileclass of the application */ virtual ~ArchDoc() {}; ArchDocPositionList positions() const { return mPositions; } QList itemslist() const; QDate date() const { return mDate; } QString dateStr() const; QString dateStrISO() const; QString address() const { return mAddress; } QString clientUid() const { return mClientUid; } QString ident() const { return mIdent; } QString salut() const { return mSalut; } QString goodbye() const { return mGoodbye; } QString preText() const; QString preTextHtml() const; QString postText() const; QString postTextHtml() const; QString projectLabel() const { return mProjectLabel; } QString predecessor() const { return mPredecessor; } QString archDocIdStr() const { return archDocId().toString(); } QString docIdentifier() const; Geld nettoSum() const; QString nettoSumStr() const { return nettoSum().toLocaleString(); } QString nettoSumNum() const { return nettoSum().toNumberString(); } Geld bruttoSum() const; QString bruttoSumStr() const { return bruttoSum().toLocaleString(); } QString bruttoSumNum() const { return bruttoSum().toNumberString(); } Geld taxSum() const; QString taxSumStr() const { return taxSum().toLocaleString(); } QString taxSumNum() const { return taxSum().toNumberString(); } Geld fullTaxSum() const; QString fullTaxSumStr() const { return fullTaxSum().toLocaleString(); } QString fullTaxSumNum() const { return fullTaxSum().toNumberString(); } Geld reducedTaxSum() const; QString reducedTaxSumStr() const { return reducedTaxSum().toLocaleString(); } QString reducedTaxSumNum() const { return reducedTaxSum().toNumberString(); } QString fullTaxPercentNum() const; QString fullTaxPercentStr() const; QString reducedTaxPercentNum() const; QString reducedTaxPercentStr() const; QString taxPercentStr() const; QString taxPercentNum() const; QString dueDate() const { return _dueDate.toString("yyyy-MM-dd"); } QString buyerRef() const { return _buyerRef; } void setDueDate(const QDate& d) { _dueDate = d; } void setBuyerRef(const QString& br) { _buyerRef = br; } static QString taxMarkerNoTax() { return QStringLiteral("1"); } static QString taxMarkerReduced() { return QStringLiteral("2"); } static QString taxMarkerFull() { return QStringLiteral(""); } bool hasIndividualTaxation() const { return mPositions.hasIndividualTaxes(); } double tax() const; double reducedTax() const; ArchDocDigest toDigest() const; // when the document was sent to the customer. QDateTime sentOutDate(); void setSentOutDate( const QDateTime& dt ); void loadFromDb( dbID ); protected: void loadItems( const QString& ); dbID mArchDocID; QString mAddress; QString mClientUid; QString mPreText; QString mPostText; QString mSalut; QString mGoodbye; QString mIdent; QString mProjectLabel; QString mPredecessor; QString _buyerRef; QDate _dueDate; double mTax; double mReducedTax; QDate mDate; ArchDocPositionList mPositions; AttributeMap mAttributes; }; #endif // ARCHDOC_H kraft-1.1/src/archdocposition.cpp000066400000000000000000000121531450127457600171620ustar00rootroot00000000000000/*************************************************************************** archdocposition.cpp - a position in an archived document ------------------- begin : Sep. 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include // application specific includes #include "einheit.h" #include "geld.h" #include "archdocposition.h" #include "archdoc.h" #include "unitmanager.h" /** @author Klaas Freitag */ ArchDocPosition::ArchDocPosition() : mAmount( 0 ) { } Geld ArchDocPosition::nettoPrice() const { return mOverallPrice; } Geld ArchDocPosition::fullTax( double fullTax ) const { Geld tax; if ( mTaxType == DocPositionBase::TaxFull ) { tax = mOverallPrice * fullTax; } return tax / 100.0; } Geld ArchDocPosition::reducedTax( double reducedTax ) const { Geld tax; if ( mTaxType == DocPositionBase::TaxReduced ) { tax = mOverallPrice * reducedTax; } return tax / 100.0; } Geld ArchDocPosition::tax( double fullTax, double reducedTax ) const { Geld tax; if ( mTaxType == DocPositionBase::TaxFull ) { tax = mOverallPrice * fullTax; } else if ( mTaxType == DocPositionBase::TaxReduced ) { tax = mOverallPrice * reducedTax; } return tax / 100.0; } QString ArchDocPosition::taxMarkerHelper() const { QString re; if ( mTaxType == DocPositionBase::TaxReduced ) { re = ArchDoc::taxMarkerReduced(); } else if ( mTaxType == DocPositionBase::TaxNone) { re = ArchDoc::taxMarkerNoTax(); } else if ( mTaxType == DocPositionBase::TaxFull) { re = ArchDoc::taxMarkerFull(); } return re; } QString ArchDocPosition::htmlText(const QString& paraStyle) const { QString re; QString style( paraStyle ); if ( style.isEmpty() ) style = QStringLiteral("text"); // Keep empty parts allows multiple newlines here const QStringList li = mText.toHtmlEscaped().split( "\n", QString::KeepEmptyParts ); re = li.join("
            "); return re; } QString ArchDocPosition::unitEC20() const { const QString ece20 = UnitManager::self()->getECE20(mUnit); return ece20; } // ================================================================== ArchDocPositionList::ArchDocPositionList() : QList() { } Geld ArchDocPositionList::sumPrice() const { Geld g; const_iterator it; for ( it = begin(); it != end(); ++it ) { g += ( *it ).nettoPrice(); } return g; } Geld ArchDocPositionList::taxSum() const { Geld allTaxSum = fullTaxSum(); allTaxSum += reducedTaxSum(); return allTaxSum; } Geld ArchDocPositionList::fullTaxSum() const { Geld g; const_iterator it; for ( it = begin(); it != end(); ++it ) { if( (*it).taxType() == DocPositionBase::TaxFull) { g += (*it).nettoPrice(); } } const Geld ftSum(g.percent(_fullTax).toLong()); return ftSum; } Geld ArchDocPositionList::reducedTaxSum() const { Geld g; const_iterator it; for ( it = begin(); it != end(); ++it ) { if( (*it).taxType() == DocPositionBase::TaxReduced) { g += (*it).nettoPrice(); } } const Geld rtSum(g.percent(_reducedTax).toLong()); return rtSum; } DocPositionBase::TaxType ArchDocPositionList::listTaxation() const { int fullTax = 0; int noTax = 0; int redTax = 0; DocPositionBase::TaxType ret = DocPositionBase::TaxType::TaxNone; const_iterator it; for ( it = begin(); it != end(); ++it ) { if( (*it).taxType() == DocPositionBase::TaxFull) { fullTax++; } else if( (*it).taxType() == DocPositionBase::TaxReduced ) { redTax++; } else if( (*it).taxType() == DocPositionBase::TaxNone ) { noTax++; } } int cnt = count(); if (noTax == cnt) { ret = DocPositionBase::TaxType::TaxNone; } else if (redTax == cnt) { ret = DocPositionBase::TaxType::TaxReduced; } else if (fullTax == cnt) { ret = DocPositionBase::TaxType::TaxFull; } else ret = DocPositionBase::TaxType::TaxIndividual; return ret; } bool ArchDocPositionList::hasIndividualTaxes() const { bool re = listTaxation() == DocPositionBase::TaxType::TaxIndividual; return re; } void ArchDocPositionList::setTaxes(double fullTax, double reducedTax) { _fullTax = fullTax; _reducedTax = reducedTax; } kraft-1.1/src/archdocposition.h000066400000000000000000000121201450127457600166210ustar00rootroot00000000000000/*************************************************************************** archdocposition.h - a position in an archived document ------------------- begin : Sep 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef ARCHDOCPOSITION_H #define ARCHDOCPOSITION_H // include files for Qt #include #include #include // include files for KDE // application specific includes #include "einheit.h" #include "geld.h" #include "dbids.h" #include "docposition.h" #include "defaultprovider.h" class ArchDoc; /** @author Klaas Freitag */ class ArchDocPosition { friend class ArchDoc; public: ArchDocPosition(); ~ArchDocPosition(){}; QString posNumber() const { return mPosNo; } QString text() const { return mText; } QString htmlText(const QString ¶Style = QString()) const; QString unit() const { return mUnit; } QString unitEC20() const; Geld unitPrice() const { return mUnitPrice; } Geld nettoPrice() const; double amount() const { return mAmount; } DocPositionBase::TaxType taxType() const { return mTaxType; } Geld tax( double fullTax, double reducedTax ) const; Geld fullTax( double fullTax ) const; Geld reducedTax( double reducedTax ) const; QString kind() const { return mKind; } QString taxMarkerHelper() const; private: QString mText; QString mPosNo; QString mUnit; QString mKind; Geld mUnitPrice; Geld mOverallPrice; double mAmount; DocPositionBase::TaxType mTaxType; // No calculation yet }; class ArchDocPositionList : public QList { public: ArchDocPositionList(); Geld sumPrice() const; Geld taxSum() const; Geld fullTaxSum() const; Geld reducedTaxSum() const; DocPositionBase::TaxType listTaxation() const; bool hasIndividualTaxes() const; void setTaxes(double fullTax, double reducedTax); private: double _fullTax; double _reducedTax; }; Q_DECLARE_METATYPE(ArchDocPosition) Q_DECLARE_METATYPE(ArchDocPositionList) // Read-only introspection of Person object. GRANTLEE_BEGIN_LOOKUP(ArchDocPosition) if ( property == "itemNumber" ) return object.posNumber(); else if ( property == "text" ) return object.text(); else if ( property == "htmlText" ) return object.htmlText(); else if ( property == "kind" ) return object.kind(); else if ( property == "unit" ) return object.unit(); else if ( property == "unitCode" ) return object.unitEC20(); else if ( property == "unitPrice" ) { return object.unitPrice().toLocaleString(); } else if ( property == "unitPriceNum") { return QString::number(object.unitPrice().toDouble(), 'f', 2); } else if ( property == "nettoPrice" ) { return object.nettoPrice().toLocaleString(); } else if ( property == "nettoPriceNum" ) { return QString::number(object.nettoPrice().toDouble(), 'f', 2); } else if ( property == "amount" ) { QLocale *loc = DefaultProvider::self()->locale(); return loc->toString(object.amount()); } else if ( property == "amountNum") { return QString::number(object.amount(), 'f', 2) ; } else if ( property == "taxType" ) { if (object.taxType() == DocPositionBase::TaxType::TaxFull) { return QStringLiteral("fullTax"); } else if (object.taxType() == DocPositionBase::TaxType::TaxReduced) { return QStringLiteral("reducedTax"); } else if (object.taxType() == DocPositionBase::TaxType::TaxNone) { return QStringLiteral("noTax"); } return QStringLiteral("Invalid"); } else if ( property == "itemType" ) { return object.kind(); } else if ( property == "taxMarker") { return object.taxMarkerHelper(); } else { return QStringLiteral("undefined"); } GRANTLEE_END_LOOKUP GRANTLEE_BEGIN_LOOKUP(ArchDocPositionList) if (property == "sumPrice") return object.sumPrice().toLocaleString(); else if (property == "taxSum") return object.taxSum().toLocaleString(); else if (property == "fullTaxSum") return object.fullTaxSum().toLocaleString(); else if (property == "reducedTaxSum") return object.reducedTaxSum().toLocaleString(); else if (property == "reducedTaxSum") return object.reducedTaxSum().toLocaleString(); else if (property == "hasIndividualTaxes") return object.hasIndividualTaxes(); else return QStringLiteral("Undefined"); GRANTLEE_END_LOOKUP #endif kraft-1.1/src/archiveman.cpp000066400000000000000000000313761450127457600161170ustar00rootroot00000000000000/*************************************************************************** archiveman.cpp - Archive Manager ------------------- begin : July 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include "archiveman.h" #include "kraftdoc.h" #include "kraftdb.h" #include "unitmanager.h" #include "dbids.h" #include "documentman.h" #include "defaultprovider.h" #include "format.h" #include "version.h" Q_GLOBAL_STATIC(ArchiveMan, mSelf) ArchiveMan *ArchiveMan::self() { return mSelf; } ArchiveMan::ArchiveMan() { } ArchiveMan::~ArchiveMan() { } dbID ArchiveMan::archiveDocument( KraftDoc *doc ) { if( ! doc ) return dbID(); dbID archId = archiveDocumentDb( doc ); if ( DefaultProvider::self()->writeXmlArchive() ) { archiveDocumentXml( doc, archId.toString()); } return archId; } QString ArchiveMan::documentID( dbID archID ) const { QString re; QSqlQuery q; q.prepare("SELECT ident FROM archdoc WHERE archDocID=:id"); q.bindValue(":id", archID.toInt()); q.exec(); if ( q.next() ) { re = q.value( 0 ).toString(); } return re; } QDomElement ArchiveMan::xmlTextElement( QDomDocument doc, const QString& name, const QString& value ) { QDomElement elem = doc.createElement( name ); QDomText t = doc.createTextNode( value ); elem.appendChild( t ); return elem; } QDomElement ArchiveMan::positionsDomElement( DocPositionList *positions, QDomDocument& doc ) { QDomElement topElem = doc.createElement( "positions" ); QDomElement posElem; int num = 1; DocPositionListIterator it(*positions); while( it.hasNext() ) { DocPosition *dpb = static_cast( it.next() ); if( dpb->type() == DocPositionBase::Position ) { DocPosition *dp = static_cast(dpb); posElem = doc.createElement( "position" ); posElem.setAttribute( "number", num++ ); topElem.appendChild( posElem ); posElem.appendChild( xmlTextElement( doc, "text", dp->text() ) ); double am = dp->amount(); QString h = QString::number(am, 'f', 2 ); posElem.appendChild( xmlTextElement( doc, "amount", h )); Einheit e = dp->unit(); posElem.appendChild( xmlTextElement( doc, "unit", e.einheit( am ) ) ); Geld g = dp->unitPrice(); posElem.appendChild( xmlTextElement( doc, "unitprice", QString::number(g.toDouble(), 'f', 2 ))); Geld sum(g * am); posElem.appendChild( xmlTextElement( doc, "sumprice", QString::number(sum.toDouble(), 'f', 2 ) ) ); } } return topElem; } QDomDocument ArchiveMan::archiveDocumentXml( KraftDoc *doc, const QString& archId ) { QDomDocument xmldoc( "kraftdocument" ); QDomElement root = xmldoc.createElement( "kraftdocument" ); root.setAttribute(QStringLiteral("kraft_version"), Kraft::Version::number()); xmldoc.appendChild( root ); QDomElement cust = xmldoc.createElement( "client" ); root.appendChild( cust ); cust.appendChild( xmlTextElement( xmldoc, "address", doc->address() ) ); cust.appendChild( xmlTextElement( xmldoc, "clientId", doc->addressUid() ) ); QDomElement docElem = xmldoc.createElement( "docframe" ); root.appendChild( docElem ); docElem.appendChild( xmlTextElement( xmldoc, "docType", doc->docType() ) ); docElem.appendChild( xmlTextElement( xmldoc, "docDesc", doc->whiteboard() ) ); docElem.appendChild( xmlTextElement( xmldoc, "ident", doc->ident() ) ); docElem.appendChild( xmlTextElement( xmldoc, "predecessor", doc->predecessor() ) ); docElem.appendChild( xmlTextElement( xmldoc, "preText", doc->preText() ) ); docElem.appendChild( xmlTextElement( xmldoc, "postText", doc->postText() ) ); docElem.appendChild( xmlTextElement( xmldoc, "projectLabel", doc->projectLabel() ) ); docElem.appendChild( xmlTextElement( xmldoc, "salut", doc->salut() ) ); docElem.appendChild( xmlTextElement( xmldoc, "goodbye", doc->goodbye() ) ); docElem.appendChild( xmlTextElement( xmldoc, "date", Format::toDateString(doc->date(), Format::DateFormatIso))); DocPositionList dpList = doc->positions(); root.appendChild( positionsDomElement(&dpList, xmldoc) ); QString xml = xmldoc.toString(); // qDebug() << "Resulting XML: " << xml; const QString outputDir = xmlBaseDir(); const QString filename = archiveFileName( doc->ident(), archId, "xml" ); const QString xmlFile = QString( "%1/%2" ).arg( outputDir ).arg( filename ); // qDebug () << "Storing XML to " << xmlFile; QFile file( xmlFile ); if ( file.open( QIODevice::WriteOnly ) ) { QTextStream stream( &file ); stream << xml << "\n"; file.close(); } else { // qDebug () << "Saving failed"; } return xmldoc ; } dbID ArchiveMan::archiveDocumentDb( KraftDoc *doc ) { /* mysql> describe archdoc; +---------------+--------------+------+-----+-------------------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------------+--------------+------+-----+-------------------+----------------+ | archDocID | int(11) | NO | PRI | NULL | auto_increment | | ident | varchar(32) | YES | MUL | NULL | | | docType | varchar(255) | YES | | NULL | | | clientAddress | text | YES | | NULL | | | clientUid | varchar(32) | YES | | NULL | | | salut | varchar(255) | YES | | NULL | | | goodbye | varchar(128) | YES | | NULL | | | printDate | timestamp | NO | | CURRENT_TIMESTAMP | | | date | date | YES | | NULL | | | pretext | text | YES | | NULL | | | posttext | text | YES | | NULL | | | country | varchar(32) | YES | | NULL | | | language | varchar(32) | YES | | NULL | | | projectLabel | varchar(255) | YES | | NULL | | | state | int(11) | YES | | NULL | | +---------------+--------------+------+-----+-------------------+----------------+ */ if( ! doc ) return dbID(); QSqlTableModel model; model.setTable("archdoc"); QSqlRecord record = model.record(); if( doc->isNew() ) { // qDebug () << "Strange: Document in archiving is new!"; } record.setValue( "ident", doc->ident() ); record.setValue( "docType", doc->docType() ); record.setValue( "docDescription", KraftDB::self()->mysqlEuroEncode( doc->whiteboard() ) ); record.setValue( "clientAddress", doc->address() ); record.setValue( "clientUid", doc->addressUid() ); record.setValue( "salut", doc->salut() ); record.setValue( "goodbye", doc->goodbye() ); record.setValue( "printDate", KraftDB::self()->currentTimeStamp() ); record.setValue( "date", doc->date() ); record.setValue( "pretext", KraftDB::self()->mysqlEuroEncode(doc->preText() ) ); record.setValue( "posttext", KraftDB::self()->mysqlEuroEncode(doc->postText() ) ); record.setValue( "projectLabel", KraftDB::self()->mysqlEuroEncode(doc->projectLabel() ) ); record.setValue( "predecessor", doc->predecessor() ); QLocale *loc = DefaultProvider::self()->locale(); record.setValue( "country", loc->name() ); record.setValue( "language", QLocale::languageToString(DefaultProvider::self()->locale()->language())); record.setValue( "tax", DocumentMan::self()->tax( doc->date() ) ); record.setValue( "reducedTax", DocumentMan::self()->reducedTax( doc->date() ) ); if(!model.insertRecord(-1, record)) { // qDebug () << model.lastError(); } dbID id = KraftDB::self()->getLastInsertID(); archivePos( id.toInt(), doc ); return id; } int ArchiveMan::archivePos( int archDocId, KraftDoc *doc ) { /* mysql> describe archdocpos; +-----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+--------------+------+-----+---------+----------------+ | archPosID | int(11) | NO | PRI | NULL | auto_increment | | archDocID | int(11) | NO | MUL | | | | ordNumber | int(11) | NO | | | | | text | text | YES | | NULL | | | amount | decimal(6,2) | YES | | NULL | | | unit | varchar(64) | YES | | NULL | | | price | decimal(6,2) | YES | | NULL | | | vat | decimal(3,1) | YES | | 0.0 | | +-----------+--------------+------+-----+---------+----------------+ */ if( ! doc ) return -1; QSqlTableModel model; model.setTable("archdocpos"); QSqlRecord record = model.record(); int cnt = 0; DocPositionList posList = doc->positions(); DocPositionListIterator it( posList ); // qDebug () << "Archiving pos for " << archDocId; while ( it.hasNext() ) { DocPosition *dp = static_cast( it.next() ); record.setValue( "archDocID", archDocId ); record.setValue( "ordNumber", 1+cnt /* dp->position() */ ); record.setValue( "kind", dp->attribute( DocPosition::Kind ) ); record.setValue( "text", dp->text() ); // expandItemText( dp ) ); record.setValue( "amount", dp->amount() ); record.setValue( "unit", dp->unit().einheit( dp->amount() ) ); record.setValue( "price", dp->unitPrice().toDouble() ); record.setValue( "overallPrice", dp->overallPrice().toDouble() ); record.setValue( "taxType", dp->taxTypeNumeric() ); if(!model.insertRecord(-1, record)) { // qDebug () << model.lastError(); } dbID id = KraftDB::self()->getLastInsertID(); // qDebug() << "Inserted for id " << id.toString(); cnt++; // save the attributes of the positions in the attributes // table but with a new host type which reflects the arch state AttributeMap attribs = dp->attributes(); attribs.setHost( "ArchPosition" ); attribs.save( id ); } return cnt; } void ArchiveMan::ensureDirIsExisting( const QString& dir ) const { if( ! QFile::exists(dir)) { qDebug() << "pdfBaseDir does not exist! Trying to create" << dir; QDir d; if( d.mkpath(dir) ) { qDebug() << "Successfully created" << dir; } else { qDebug() << "Failed to create" << dir; } } } QString ArchiveMan::xmlBaseDir() const { QString outputDir = DefaultProvider::self()->xmlArchivePath(); if ( outputDir.isEmpty() ) { // stay bug compatible: Before issue #80, this was the pdfOutputDir outputDir = DefaultProvider::self()->pdfOutputDir(); } if (outputDir.isEmpty()) { outputDir = QStandardPaths::writableLocation( QStandardPaths::AppDataLocation ); } if ( ! outputDir.endsWith('/') ) outputDir += QChar('/'); ensureDirIsExisting(outputDir); return outputDir; } QString ArchiveMan::pdfBaseDir() const { QString outputDir = DefaultProvider::self()->pdfOutputDir(); if ( outputDir.isEmpty() ) { outputDir = QStandardPaths::writableLocation( QStandardPaths::AppDataLocation ); } if ( ! outputDir.endsWith('/') ) outputDir += QChar('/'); ensureDirIsExisting(outputDir); return outputDir; } QString ArchiveMan::archiveFileName( const QString& docId, const QString& archId, const QString& ext ) const { QString re = QString( "%1_%2.%3" ).arg( docId ).arg( archId ).arg( ext ); re.replace(QLatin1Char('/'), QLatin1Char('_')); return re; } kraft-1.1/src/archiveman.h000066400000000000000000000042011450127457600155470ustar00rootroot00000000000000/*************************************************************************** archiveman.h - Archive Manager ------------------- begin : July 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef ARCHIVEMAN_H #define ARCHIVEMAN_H #include #include "dbids.h" class KraftDoc; class dbID; class QDomDocument; class DocPositionList; class ArchiveMan { friend class KraftDB; public: virtual ~ArchiveMan(); static ArchiveMan *self(); /** * query the document identifier id for a given database archive id */ QString documentID( dbID archID ) const; QString xmlBaseDir() const; QString pdfBaseDir() const; QString archiveFileName( const QString&, const QString&, const QString& ) const; ArchiveMan(); protected: /* do not use the archive function directly, but always via KraftDB, to let the DB * class update the counters of documents. */ dbID archiveDocument( KraftDoc* ); virtual QDomDocument archiveDocumentXml( KraftDoc*, const QString& ); virtual dbID archiveDocumentDb( KraftDoc* ); private: QDomElement xmlTextElement( QDomDocument, const QString&, const QString& ); QDomElement positionsDomElement( DocPositionList *positions, QDomDocument& doc ); int archivePos( int, KraftDoc* ); void ensureDirIsExisting( const QString& dir ) const; }; #endif kraft-1.1/src/attribute.cpp000066400000000000000000000276071450127457600160070ustar00rootroot00000000000000/*************************************************************************** attribute.cpp - generic attribute object ------------------- begin : Aug. 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include "attribute.h" #include "kraftdb.h" #include "dbids.h" Attribute::Attribute() :mPersist( true ), mListValue( false ), mDelete( false ) { } Attribute::Attribute( const QString& name ) :mName( name ), mPersist( true ), mListValue( false ), mDelete( false ) { } void Attribute::setRawValue( const QVariant& var ) { mValue = var; } void Attribute::setValue( const QVariant& var ) { mValue = var; } QVariant Attribute::value() const { return mValue; } QString Attribute::name() const { return mName; } bool Attribute::persistant() { return mPersist; } void Attribute::setPersistant( bool p ) { mPersist = p; } void Attribute::setListValue( bool p ) { mListValue = p; } bool Attribute::listValue() const { return mListValue; } QString Attribute::toString() const { QString re; re = "+ Attribute name: " + mName + '\n'; if ( mListValue ) { re += "+ Attribute Value (List): " + mValue.toStringList().join( ", " )+ '\n'; } else { re += "+ Attribute Value (String): " + mValue.toString() + '\n'; } re += "+ List: " + ( mListValue ? QString( "yes" ) : QString( "no" ) ) + '\n'; return re; } /* * Attribute Map ============================================================ */ AttributeMap::AttributeMap( const QString& host) :QMap(), mHost( host ) { } void AttributeMap::setHost( const QString& host ) { mHost = host; } bool AttributeMap::hasAttribute( const QString& name ) const { ConstIterator it = find( name ); if ( it != end() ) { // it is there, check the delete flag. if ( ! ( *it ).mDelete ) return true; } return false; } /* * this method saves the attribute together with the host string that * defines the type of object that this attribute is associated to (like * position or document) and the hosts database id. */ void AttributeMap::save( dbID id ) { checkHost(); if (size() == 0) return; QSqlQuery attribQuery; attribQuery.prepare( "SELECT id, valueIsList FROM attributes WHERE hostObject=:host AND hostId=:hostId AND name=:name" ); attribQuery.bindValue( ":host", mHost ); attribQuery.bindValue( ":hostId", id.toString() ); Iterator it; for ( it = begin(); it != end(); ++it ) { Attribute att = it.value(); // qDebug () << ">> oo- saving attribute with name " << it.key() << " for " << id.toString() << " att-name: " << att.name(); attribQuery.bindValue( ":name", att.name() ); attribQuery.exec(); QString attribId; if ( attribQuery.next() ) { // the attrib exists. Check the values attribId = attribQuery.value(0).toString(); // the id if ( att.value().isNull() || att.mDelete ) { // the value is empty. the existing entry needs to be dropped dbDeleteAttribute( attribId ); return; } } else { // the attrib does not yet exist. Create if att value is not null. if ( att.value().isNull() ) { // qDebug () << "oo- skip writing of attribute, value is empty"; } else { // qDebug () << "oo- writing of attribute name " << att.name(); QSqlQuery insQuery; insQuery.prepare( "INSERT INTO attributes (hostObject, hostId, name, valueIsList) " "VALUES (:host, :hostId, :name, :valueIsList)" ); insQuery.bindValue( ":host", mHost ); insQuery.bindValue( ":hostId", id.toString() ); insQuery.bindValue( ":name", att.name() ); insQuery.bindValue( ":valueIsList", att.listValue() ); insQuery.exec(); dbID attId = KraftDB::self()->getLastInsertID(); attribId = attId.toString(); } } // store the id to be able to drop not longer existent values // qDebug () << "adding attribute id " << attribId << " for attribute " << att.name(); // now there is a valid entry in the attribute table. Check the values. QSqlQuery valueQuery( "SELECT id, value FROM attributeValues WHERE attributeId=" + attribId ); typedef QMap ValueMap; ValueMap valueMap; while ( valueQuery.next() ) { QString idStr = valueQuery.value( 0 ).toString(); // id QString valStr = valueQuery.value( 1 ).toString(); // value valueMap[valStr] = idStr; } // create a stringlist with the current values of the attribute if ( att.listValue() ) { QStringList newValues; newValues = att.mValue.toStringList(); // qDebug () << "new values are: " << newValues.join( ", " ); if ( newValues.empty() ) { // delete the entire attribute. dbDeleteValue( attribId ); // deletes all values dbDeleteAttribute( attribId ); valueMap.clear(); } else { // we really have new values QSqlQuery insValue; insValue.prepare( "INSERT INTO attributeValues (attributeId, value) VALUES (:attribId, :val)" ); insValue.bindValue( ":attribId", attribId ); // loop over all existing new values of the attribute. for ( QStringList::Iterator valIt = newValues.begin(); valIt != newValues.end(); ++valIt ) { QString curValue = *valIt; if ( valueMap.contains( curValue ) ) { // the valueMap is already saved. remove it from the valueMap string // qDebug () << "Value " << curValue << " is already present with id " << valueMap[curValue]; valueMap.remove( curValue ); } else { // the value is not yet there, insert it. insValue.bindValue( ":val", curValue ); insValue.exec(); } } } } else { // only a single entry for the attribte, update if needed. QString newValue = att.mValue.toString(); // access the attribute object directly to get the numeric // qDebug () << "NEW value String: " << newValue; // value in case the attribute is bound to a relation table if ( newValue.isEmpty() ) { // delete the entire attribute dbDeleteValue( attribId ); // deletes all values dbDeleteAttribute( attribId ); valueMap.clear(); } else { if ( valueMap.empty() ) { // there is no entry yet that could be updated. QSqlQuery insertQuery; insertQuery.prepare( "INSERT INTO attributeValues (attributeId, value ) VALUES (:id, :val)" ); insertQuery.bindValue( ":id", attribId ); insertQuery.bindValue( ":val", newValue ); insertQuery.exec(); // qDebug () << "insert new attrib value for non list: " << newValue; } else { QString oldValue = valueMap.begin().key(); QString id = valueMap.begin().value(); if ( newValue != oldValue ) { // qDebug () << "Updating " << id << " from " << oldValue << " to " << newValue; QSqlQuery updateQuery; updateQuery.prepare( "UPDATE attributeValues SET value=:val WHERE id=:id" ); updateQuery.bindValue( ":val", newValue ); updateQuery.bindValue( ":id", id ); // qDebug () << "do the update!"; updateQuery.exec(); } valueMap.remove( oldValue ); } } } // remove all still existing entries in the valueMap because they point to values which are // in the db but were deleted from the attribute if ( ! valueMap.isEmpty() ) { ValueMap::Iterator mapIt; for ( mapIt = valueMap.begin(); mapIt != valueMap.end(); ++mapIt ) { QString valId = mapIt.value(); dbDeleteValue( attribId, valId ); } } } } bool AttributeMap::containsUndeleted(const QString &name) const { if ( name.isEmpty() || ! contains( name ) ) return false; ConstIterator it = find( name ); if ( it != end() ) { if (!(*it).mDelete) return true; // qDebug () << "Marking attrib " << name << " to delete!"; } return false; } void AttributeMap::markDelete( const QString& name ) { if ( name.isEmpty() || ! contains( name ) )return; Iterator it = find( name ); if ( it != end() ) { ( *it ).mDelete = true; // qDebug () << "Marking attrib " << name << " to delete!"; } } /* remove all Attributes from the database for the given host id * this method clears the entire map and should only be called if * the whole host is to delete anyway. */ void AttributeMap::dbDeleteAll( dbID id ) { // qDebug () << "This is the id for to delete: " << id.toString(); if ( !id.isOk() ) return; QSqlQuery listQuery; listQuery.prepare( "SELECT id FROM attributes WHERE hostObject=:hostObject AND hostId=:hostId" ); listQuery.bindValue( ":hostObject", mHost ); listQuery.bindValue( ":hostId", id.toString() ); listQuery.exec(); // qDebug () << "4-XXXXXXXXXXX " << listQuery.lastError().text(); while ( listQuery.next() ) { dbDeleteAttribute( listQuery.value( 0 ).toString() ); } clear(); } void AttributeMap::dbDeleteAttribute( const QString& attribId ) { if ( attribId.isEmpty() ) return; QSqlQuery delQuery; // qDebug () << "Deleting attribute id " << attribId; delQuery.prepare( "DELETE FROM attributes WHERE id=:id" ); delQuery.bindValue( ":id", attribId ); delQuery.exec(); // qDebug () << "5-XXXXXXXXXXX " << delQuery.lastError().text(); dbDeleteValue( attribId ); // delete all values } void AttributeMap::dbDeleteValue( const QString& attribId, const QString& id ) { QSqlQuery delQuery; if ( id.isEmpty() && ! attribId.isEmpty() ) { delQuery.prepare( "DELETE FROM attributeValues WHERE attributeId=" + attribId ); } else if ( !id.isEmpty() ) { delQuery.prepare( "DELETE FROM attributeValues WHERE id="+id ); } delQuery.exec(); // qDebug () << "6-XXXXXXXXXXX " << delQuery.lastError().text(); } void AttributeMap::load( dbID id ) { QSqlQuery q1; q1.prepare("SELECT id, name, valueIsList FROM attributes WHERE hostObject=:hostObject AND hostId=:hostId"); q1.bindValue(":hostObject", mHost); q1.bindValue(":hostId", id.toInt()); q1.exec(); checkHost(); while ( q1.next() ) { QString h = q1.value( 1 ).toString(); bool isList = q1.value( 2 ).toBool(); Attribute attr( h ); attr.setListValue( isList ); QSqlQuery q2; q2.prepare("SELECT value FROM attributeValues WHERE attributeId=:id"); q2.bindValue(":id", q1.value(0).toInt()); q2.exec(); QStringList values; QString str; while ( q2.next() ) { if ( isList ) { values << q2.value( 0 ).toString(); } else { str = q2.value( 0 ).toString(); // qDebug() << " attribute string " << h <<": " << str; } } // qDebug() << " attribute list " << h <<": " << values; if ( isList ) { attr.setRawValue( QVariant( values ) ); } else { attr.setRawValue( QVariant( str ) ); } attr.setPersistant( true ); insert( h, attr ); } } void AttributeMap::checkHost() { if ( mHost.isEmpty() ) { // qDebug () << "Host for attributes unset, assuming unknown"; mHost = "unknown"; } } kraft-1.1/src/attribute.h000066400000000000000000000050321450127457600154400ustar00rootroot00000000000000/*************************************************************************** attribute.h - generic attribute object ------------------- begin : Aug. 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef ATTRIBUTE_H #define ATTRIBUTE_H // include files for Qt #include // include files for KDE // application specific includes #include "kraftcat_export.h" /** @author Klaas Freitag */ class QString; class dbID; class KRAFTCAT_EXPORT Attribute { friend class AttributeMap; public: Attribute(); Attribute( const QString& name ); void setValue( const QVariant& var ); QVariant value() const; QString name() const; bool persistant(); bool listValue() const; void setListValue( bool ); void setPersistant( bool ); // TODO: Remove this unneeded method QString toString() const; bool isMarkedDeleted() const { return mDelete; } private: void setRawValue( const QVariant& var ); // sets the value without checking for relations QString mName; QVariant mValue; bool mPersist; bool mListValue; bool mDelete; // Delete the attribute on save. Written and read by the attributemap }; /* * Attribute Map */ class KRAFTCAT_EXPORT AttributeMap: public QMap { public: AttributeMap( const QString& ); bool hasAttribute( const QString& ) const; void setHost( const QString& ); void load( dbID ); void save( dbID ); void markDelete( const QString& ); void dbDeleteAll( dbID ); bool containsUndeleted(const QString &name) const; protected: void dbDeleteAttribute( const QString& ); void dbDeleteValue( const QString&, const QString& = QString() ); private: void checkHost(); QString mHost; }; #endif kraft-1.1/src/calcdialogbase.cpp000066400000000000000000000035201450127457600167050ustar00rootroot00000000000000/*************************************************************************** CalcDialogBase - base class for calculation detail dialogs ------------------- begin : 2017-01-31 copyright : (C) 2017 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include #include #include "calcdialogbase.h" CalcDialogBase::CalcDialogBase(QWidget *parent) : QDialog( parent ) { _centralWidget = new QWidget(this); setModal( true ); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(_centralWidget); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(buttonBox); } /* END */ kraft-1.1/src/calcdialogbase.h000066400000000000000000000024161450127457600163550ustar00rootroot00000000000000/*************************************************************************** CalcDialogBase - base class for calculation detail dialogs ------------------- begin : 2017-01-31 copyright : (C) 2017 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _CALCDIALOGBASE_H #define _CALCDIALOGBASE_H #include #include /** * */ class CalcDialogBase: public QDialog { Q_OBJECT public: CalcDialogBase(QWidget *parent); protected: QWidget *_centralWidget; }; #endif /* END */ kraft-1.1/src/calcpart.cpp000066400000000000000000000102351450127457600155620ustar00rootroot00000000000000/*************************************************************************** calcpart.cpp - ------------------- begin : Mit Dez 31 2003 copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include "calcpart.h" #include "fixcalcpart.h" #include "materialcalcpart.h" #include "timecalcpart.h" CalcPart::CalcPart( ): m_prozentPlus(0), m_dbId(-1), m_templId(-1), m_dirty(false), m_toDelete(false) { } CalcPart::CalcPart( int prozent ): m_prozentPlus( prozent ), m_dbId(-1), m_templId(-1), m_dirty(false), m_toDelete(false) { } CalcPart::CalcPart(const QString& name, int prozent ) : m_prozentPlus( prozent ), m_name( name ), m_dbId(-1), m_templId(-1), m_dirty(false), m_toDelete(false) { } CalcPart::~CalcPart() { } /** Read property of int m_prozentPlus. */ const double& CalcPart::getProzentPlus() { return m_prozentPlus; } /** Write property of int m_prozentPlus. */ void CalcPart::setProzentPlus( const double& _newVal) { if( _newVal != m_prozentPlus ) { m_prozentPlus = _newVal; setDirty(true); } } void CalcPart::setName( const QString& newName ) { if( newName != m_name ) { m_name = newName; setDirty(true); } } /** Wird immer reimplementiert */ Geld CalcPart::basisKosten() { Geld g; return g; } QString CalcPart::getType() const { return i18n("Base"); } void CalcPart::setToDelete(bool val) { m_toDelete = val; } bool CalcPart::isToDelete() { return m_toDelete; } /* * =========================================================================== */ CalcPartList::CalcPartList() :QList() { } Geld CalcPartList::calcPrice() { return costPerCalcPart( ALL_KALKPARTS ); } Geld CalcPartList::costPerCalcPart( const QString& calcPart ) { CalcPart *cp; Geld g; /* suche nach einer speziellen Kalkulationsart */ QListIterator i( *this ); while( i.hasNext()) { cp = i.next(); if( ( calcPart == ALL_KALKPARTS || calcPart == cp->getType() ) && ! cp->isToDelete() ) { g += cp->basisKosten(); } } return g; } /* * Attention: returning non deep copy here ! */ CalcPartList CalcPartList::getCalcPartsList( const QString& calcPart ) { CalcPartList parts; if( calcPart == ALL_KALKPARTS ) return *this; else { CalcPart *cp; /* suche nach einer speziellen Kalkulationsart */ QListIterator i( *this ); while( i.hasNext()) { cp = i.next(); if( calcPart == cp->getType() && ! cp->isToDelete() ) { parts.append(cp); } } } return( parts ); } /* * Attention: returning non deep copy here ! */ CalcPartList CalcPartList::decoupledCalcPartsList() { CalcPartList parts; CalcPart *newcp = 0; CalcPart *cp; QListIterator i( *this ); while( i.hasNext()) { cp = i.next(); if ( cp->getType() == KALKPART_FIX ) { newcp = new FixCalcPart( ); *newcp = *( static_cast( cp ) ); } else if ( cp->getType ()== KALKPART_TIME ) { newcp = new TimeCalcPart( ); *newcp = *( static_cast( cp ) ); } else if ( cp->getType() == KALKPART_MATERIAL ) { newcp = new MaterialCalcPart( ); *newcp = *( static_cast( cp ) ); } if ( newcp ) newcp->setDbID( -1 ); parts.append( newcp ); } return( parts ); } kraft-1.1/src/calcpart.h000066400000000000000000000050111450127457600152230ustar00rootroot00000000000000/*************************************************************************** calcpart.h - ------------------- begin : Mit Dez 31 2003 copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef CALCPART_H #define CALCPART_H #include #include #include "dbids.h" #include "kraftglobals.h" /**This file contains a part of a calculation. *@author Klaas Freitag */ class CalcPart { public: CalcPart(); CalcPart( int prozent ); CalcPart( const QString& name, int prozent = 0 ); virtual ~CalcPart(); /** Write property of int m_prozentPlus. */ virtual void setProzentPlus( const double& _newVal); /** Read property of int m_prozentPlus. */ virtual const double& getProzentPlus(); /** base costs for one unit */ virtual Geld basisKosten(); void setName( const QString& name ); QString getName() const { return m_name; } virtual QString getType() const; virtual bool isDirty() { return m_dirty; } virtual void setDirty( bool b ) { m_dirty = b; } virtual dbID getDbID() { return m_dbId; } virtual void setDbID( dbID id ) { m_dbId = id; } virtual dbID getTemplID() { return m_templId; } virtual void setTemplID( dbID id ) { m_templId = id; } virtual void setToDelete(bool ); virtual bool isToDelete(); private: double m_prozentPlus; QString m_name; dbID m_dbId; dbID m_templId; bool m_dirty; bool m_toDelete; }; class CalcPartList : public QList { public: CalcPartList(); Geld calcPrice(); Geld costPerCalcPart( const QString& ); CalcPartList getCalcPartsList( const QString& ); CalcPartList decoupledCalcPartsList(); }; typedef QListIterator CalcPartListIterator; #endif kraft-1.1/src/calctemplate.ui000066400000000000000000000625441450127457600162740ustar00rootroot00000000000000 d_calcTempl 0 0 657 801 Edit Template true 1 Template Text: Qt::Horizontal QSizePolicy::Expanding 118 20 &Store in Chapter false cbChapter false 0 160 false &Unit false m_unit Qt::Horizontal 40 20 &Count Time for Overalltime Qt::Horizontal 40 20 0 0 VAT false full half Time Calculation text true Time measureable effort for this template: false false false 4 true Label Duration Hourly Rate Glob. Rate Adds a new time calculation part to the template new... Edits the current time calculation part edit... Deletes the current time calculation part delete Qt::Vertical QSizePolicy::Expanding 20 191 Fix Costs text true Fix costs for this template per one unit: false false false 4 true Amount Label Single Price Overall Price adds a new fix calculation part new... edits the current fix calculation part edit... deletes the current fix calculation part delete Qt::Vertical QSizePolicy::Expanding 20 170 Material text true Needed materials for one unit of this template: false false false 4 true Label Amount Unit Price adds a new material calculation part new... edits the current material part edit... deletes the current material calculation part delete Qt::Vertical QSizePolicy::Expanding 20 160 Overall Price per Unit &Manual Price Calculated Price 99999.000000000000000 0.000000000000000 0 99999 Qt::Horizontal 40 20 textLabel2 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false Fix Costs Part: false textLabel2 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false Material Part: false textLabel2 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 0 0 Profit: false spBenefit QAbstractSpinBox::UpDownArrows % -1000 1000 Time Calculation Part: false Qt::Vertical 20 40 QFrame::HLine QFrame::Raised 75 true Calculated Price: Qt::PlainText false 75 true 88.888,88 € Qt::PlainText Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter tabWidget cbChapter m_text m_unit m_addTime cbMwst m_rbManual m_rbCalculation m_timeParts m_butAddTime m_butEditTime m_butRemoveTime m_fixParts m_butAddFix m_butEditFix m_butRemoveFix m_matParts m_butAddMat m_butEditMat m_butRemoveMat kraft-1.1/src/catalogchapter.cpp000066400000000000000000000074211450127457600167550ustar00rootroot00000000000000/*************************************************************************** catalogchapter.h - a simle catalog chapter object ------------------- begin : Thu Nov 4 2010 copyright : (C) 2010 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include "catalogchapter.h" #include "kraftdb.h" CatalogChapter::CatalogChapter() : mSortKey(0) { } CatalogChapter::CatalogChapter( int id, int csId, const QString& name, int parent, const QString& desc ) :mName( name ), mId( dbID(id) ), mCatalogSetId( dbID(csId) ), mDescription( desc ), mParentId( parent ), mSortKey(0) { } QString CatalogChapter::name() const { return mName; } void CatalogChapter::setName( const QString& name ) { mName = name; } QString CatalogChapter::description() const { return mDescription; } void CatalogChapter::setDescription( const QString& d ) { mDescription = d; } dbID CatalogChapter::id() const { return mId; } dbID CatalogChapter::catalogSetId() const { return mCatalogSetId; } void CatalogChapter::setCatalogSetId( const dbID& id ) { mCatalogSetId = id; } dbID CatalogChapter::parentId() const { return mParentId; } void CatalogChapter::setParentId( const dbID &id ) { mParentId = id; } int CatalogChapter::sortKey() const { return mSortKey; } void CatalogChapter::setSortKey( int key ) { mSortKey = key; } void CatalogChapter::save() { // qDebug () << "Inserting new chapter " << name() << mCatalogSetId.toString(); QSqlQuery q; q.prepare("INSERT INTO CatalogChapters (catalogSetID, chapter, description, sortKey, parentChapter)" "VALUES(:catalogSetID, :chapter, :desc, :sortKey, :parentChapter)"); q.bindValue( ":catalogSetID", mCatalogSetId.toString() ); q.bindValue( ":chapter", this->name() ); q.bindValue( ":desc", this->description() ); q.bindValue( ":sortKey", this->sortKey() ); q.bindValue( ":parentChapter", this->parentId().toInt() ); q.exec(); mId = KraftDB::self()->getLastInsertID(); } bool CatalogChapter::removeFromDB() { // qDebug () << "Removing chapter " << name() << " with id " << mId.toInt(); QSqlQuery q; q.prepare("DELETE FROM CatalogChapters WHERE chapterID=:chapId"); q.bindValue( ":chapId", mId.toInt() ); return q.exec(); } void CatalogChapter::saveNameAndDesc() { QSqlQuery q; q.prepare("UPDATE CatalogChapters SET chapter = :newchapter, description = :desc WHERE chapterID = :id"); q.bindValue(":id", mId.toInt() ); q.bindValue(":desc", this->description() ); q.bindValue(":newchapter", this->name() ); q.exec(); } void CatalogChapter::reparent( const dbID& pId ) { dbID parentId( pId ); setParentId( pId ); QSqlQuery q; q.prepare("UPDATE CatalogChapters SET parentChapter= :p WHERE chapterID = :id"); q.bindValue(":id", mId.toInt() ); q.bindValue(":p", parentId.toInt() ); q.exec(); // qDebug () << "Reparenting chapter " << mId.toInt() << ", reuslt: " << q.lastError().text(); } kraft-1.1/src/catalogchapter.h000066400000000000000000000035371450127457600164260ustar00rootroot00000000000000/*************************************************************************** catalogchapter.h - a simle catalog chapter object ------------------- begin : Thu Nov 4 2010 copyright : (C) 2010 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef CATALOGCHAPTER_H #define CATALOGCHAPTER_H #include #include "kraftcat_export.h" #include class KRAFTCAT_EXPORT CatalogChapter { public: CatalogChapter(); CatalogChapter( int, int, const QString&, int, const QString& = QString() ); QString name() const; void setName( const QString& ); QString description() const; void setDescription( const QString& ); dbID id() const; dbID parentId() const; void setParentId( const dbID& ); dbID catalogSetId() const; void setCatalogSetId( const dbID& ); bool removeFromDB(); int sortKey() const; void setSortKey( int ); void save( ); void saveNameAndDesc(); void reparent( const dbID& ); private: QString mName; dbID mId; dbID mCatalogSetId; QString mDescription; dbID mParentId; int mSortKey; }; #endif // CATALOGCHAPTER_H kraft-1.1/src/catalogselection.cpp000066400000000000000000000141271450127457600173150ustar00rootroot00000000000000/*************************************************************************** katalogselection - widget to select catalog entries from ------------------- begin : 2006-08-30 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "catalogselection.h" #include "catalogtemplate.h" #include "katalogman.h" #include "templkatalog.h" #include "templkataloglistview.h" #include "materialkataloglistview.h" #include "matkatalog.h" #include "docposition.h" #include "filterheader.h" #include #include #include #include #include #include #include #include #include #include #include #include CatalogSelection::CatalogSelection( QWidget *parent ) :QWidget( parent ), mCatalogSelector(nullptr), mWidgets(nullptr) { QVBoxLayout *layout = new QVBoxLayout; layout->setMargin(0); QHBoxLayout *hb = new QHBoxLayout; layout->addLayout(hb); QLabel *l = new QLabel( i18n( "Selected &Catalog: " ) ); hb->addWidget(l); mCatalogSelector = new QComboBox; hb->addWidget(mCatalogSelector); connect( mCatalogSelector, SIGNAL( activated( const QString& ) ), this, SLOT( slotSelectCatalog( const QString& ) ) ); l->setBuddy( mCatalogSelector ); hb->addStretch(); mListSearchLine = new FilterHeader; hb->addWidget(mListSearchLine); mWidgets = new QStackedWidget; mWidgets->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); layout->addWidget(mWidgets); this->setLayout(layout); setupCatalogList(); } void CatalogSelection::setupCatalogList() { QStringList katalogNames = KatalogMan::self()->allKatalogNames(); mCatalogSelector->insertItems(-1, katalogNames ); slotSelectCatalog( katalogNames[0] ); } void CatalogSelection::slotCatalogDoubleClicked( QModelIndex ) { emit actionAppendPosition(); } CatalogTemplateList CatalogSelection::currentSelectedPositions() { CatalogTemplateList re; const QString currentCat = mCatalogSelector->currentText(); if( mWidgetMap.contains( currentCat ) ) { KatalogListView *lv = mWidgetMap[currentCat]; re = lv->selectedTemplates(); } return re; } Katalog* CatalogSelection::currentSelectedKat() { const QString currentCat = mCatalogSelector->currentText(); Katalog *kat = KatalogMan::self()->getKatalog( currentCat ); if ( ! kat ) { qCritical() << "Could not find catalog " << currentCat; } return kat; } QString CatalogSelection::currentSelectedKatChapter() { QString chap; const QString currentCat = mCatalogSelector->currentText(); if( mWidgetMap.contains( currentCat ) ) { KatalogListView *lv = mWidgetMap[currentCat]; chap = lv->selectedCatalogChapter(); } return chap; } void CatalogSelection::slotSelectCatalog( const QString& katName ) { Katalog *kat = KatalogMan::self()->getKatalog( katName ); if ( !kat ) { const QString type = KatalogMan::self()->catalogTypeString( katName ); // qDebug () << "Catalog type for cat " << katName << " is " << type; if ( type == QStringLiteral("TemplCatalog") ) { kat = new TemplKatalog( katName ); } else if ( type == QStringLiteral("MaterialCatalog") ) { kat = new MatKatalog( katName ); } if ( kat ) { KatalogMan::self()->registerKatalog( kat ); } else { qCritical() << "Could not find a valid catalog type for catalog named " << katName; } } if ( kat ) { KatalogListView *katListView = nullptr; if ( ! mWidgetMap.contains( katName ) ) { if ( kat->type() == TemplateCatalog ) { TemplKatalogListView *tmpllistview = new TemplKatalogListView( this ); katListView = tmpllistview; tmpllistview->setShowCalcParts( false ); // qDebug () << "Creating a selection list for catalog " << katName; } else if ( kat->type() == MaterialCatalog ) { MaterialKatalogListView *matListView = new MaterialKatalogListView( this ); katListView = matListView; } if ( katListView ) { katListView->setSelectFromMode(); // mode to only select from mWidgets->addWidget(katListView); mWidgetMap.insert( katName, katListView ); katListView->contextMenu()->addAction( i18n("Append to Document"), this, &CatalogSelection::actionAppendPosition); katListView->addCatalogDisplay( katName ); connect(katListView, &KatalogListView::doubleClicked, this, &CatalogSelection::slotCatalogDoubleClicked); connect(katListView, &KatalogListView::currentItemChanged, this, &CatalogSelection::selectionChanged); KatalogMan::self()->registerKatalogListView( katName, katListView ); } } else { katListView = mWidgetMap[katName]; } // Select the widget if ( katListView ) { mWidgets->setCurrentWidget(katListView); mListSearchLine->setListView(katListView); emit selectionChanged(katListView->currentItem(), nullptr); } } } kraft-1.1/src/catalogselection.h000066400000000000000000000046301450127457600167600ustar00rootroot00000000000000/*************************************************************************** katalogselection - widget to select catalog entries from ------------------- begin : 2006-08-30 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef CATALOGSELECTION_H #define CATALOGSELECTION_H #include #include "kataloglistview.h" class QComboBox; class QStackedWidget; class QActionCollection; class QAction; class DocPosition; class FilterHeader; class CalcPartList; class Katalog; class CatalogSelection : public QWidget { Q_OBJECT public: CatalogSelection( QWidget *parent=0 ); ~CatalogSelection() { }; Katalog* currentSelectedKat(); QString currentSelectedKatChapter(); CatalogTemplateList currentSelectedPositions(); protected: void setupCatalogList(); signals: /* * a template was selected to be inserted into the document. This * transports a ptr to the katalog and the item in it. Since the * template type is dependent on the katalog type it is not known * what type of template is coming. It is up to the receiver to * decide (and cast) to the correct template on the katalog type. * * FIXME: Better approach: all catalog items inherit from a base * type. */ void selectionChanged(QTreeWidgetItem * current,QTreeWidgetItem * previous); void actionAppendPosition(); protected slots: void slotSelectCatalog( const QString& ); // void slotAppendToDoc( QListViewItem *item = 0 ); void slotCatalogDoubleClicked( QModelIndex ); private: QComboBox *mCatalogSelector; QStackedWidget *mWidgets; QMap mWidgetMap; FilterHeader *mListSearchLine; }; #endif kraft-1.1/src/catalogtemplate.cpp000066400000000000000000000072721450127457600171460ustar00rootroot00000000000000/*************************************************************************** catalogtemplate - template base class for catalog data ------------------- begin : Oct 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include "catalogtemplate.h" #include "unitmanager.h" CatalogTemplate::CatalogTemplate() : m_calcType( Calculation ), mUseCounter(0), mEntered( QDateTime::currentDateTime() ), mLastModified( QDateTime::currentDateTime() ), mUnitId(0) { } CatalogTemplate::~CatalogTemplate() { } CatalogTemplate::CalculationType CatalogTemplate::calcKind() { return m_calcType; } void CatalogTemplate::setCalculationType( CalculationType t ) { m_calcType = t; } QString CatalogTemplate::calcKindString() const { if( m_calcType == ManualPrice ) return i18n("Manual Price"); else if( m_calcType == Calculation ) return i18n("Calculated"); else if( m_calcType == AutoCalc ) return i18n("AutoCalc"); else return i18n( "Err: Unknown type %d", m_calcType); } void CatalogTemplate::setEnterDate( const QDateTime& d ) { mEntered = d; } QDateTime CatalogTemplate::enterDate() { return mEntered; } void CatalogTemplate::setModifyDate( const QDateTime& d ) { mLastModified = d; } QDateTime CatalogTemplate::modifyDate() { return mLastModified; } void CatalogTemplate::setLastUsedDate( const QDateTime &d ) { mLastUsed = d; } QDateTime CatalogTemplate::lastUsedDate() { return mLastUsed; } void CatalogTemplate::setUseCounter( int cnt ) { mUseCounter = cnt; } int CatalogTemplate::useCounter() { return mUseCounter; } QString CatalogTemplate::getText() const { return mText; } void CatalogTemplate::setText( const QString& str ) { mText = str; } void CatalogTemplate::setUnitId(int id) { mUnitId = id; } Einheit CatalogTemplate::unit() const { return UnitManager::self()->getUnit(mUnitId); } void CatalogTemplate::setChapterId( const dbID& id, bool persist ) { // qDebug () << "set chapterId to " << id.toString(); mChapterId = id; if( persist ) { saveChapterId(); } } void CatalogTemplate::saveChapterId() { // qDebug () << "WRN: Chapter ID saving for template not implemented!"; } dbID CatalogTemplate::chapterId() { return mChapterId; } // ================================================================================ CatalogTemplateList::CatalogTemplateList() :QList() { } CatalogTemplateList::~CatalogTemplateList() { } int CatalogTemplateList::compareItems( CatalogTemplate *ct1, CatalogTemplate *ct2 ) { // CatalogTemplate* ct1 = static_cast( i1 ); // CatalogTemplate* ct2 = static_cast( i2 ); // qDebug () << "********************************* In Sort!"; if ( !( ct1 && ct2 ) ) return 0; int sortKey1 = ct1->sortKey(); int sortKey2 = ct2->sortKey(); if ( sortKey1 == sortKey2 ) return 0; if ( sortKey1 < sortKey2 ) return -1; return 1; } kraft-1.1/src/catalogtemplate.h000066400000000000000000000054151450127457600166100ustar00rootroot00000000000000/*************************************************************************** catalogtemplate - template base class for catalog data ------------------- begin : Oct 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef CATALOGTEMPLATE_H #define CATALOGTEMPLATE_H /** * base class that is the base for all templates in kraft catalogs. */ #include #include "kraftcat_export.h" #include "dbids.h" class QWidget; class CatalogSelection; class Katalog; class Geld; class Einheit; class KRAFTCAT_EXPORT CatalogTemplate { public: typedef enum { Unknown, ManualPrice, Calculation, AutoCalc } CalculationType; CatalogTemplate(); virtual ~CatalogTemplate(); virtual bool save() = 0; virtual Geld unitPrice() = 0; CalculationType calcKind(); void setCalculationType( CalculationType t ); QString calcKindString() const ; int sortKey() { return mSortKey; } void setSortKey( int k ) { mSortKey = k; } void setEnterDate( const QDateTime& ); QDateTime enterDate(); void setModifyDate( const QDateTime& ); QDateTime modifyDate(); void setLastUsedDate( const QDateTime& ); QDateTime lastUsedDate(); void setUseCounter( int ); int useCounter(); QString getText() const; void setText( const QString& ); void setChapterId( const dbID&, bool ); dbID chapterId(); Einheit unit() const; void setUnitId(int id); protected: virtual void saveChapterId(); CalculationType m_calcType; int mSortKey; int mUseCounter; dbID mChapterId; // the chapter (==parent) of the item QDateTime mEntered; QDateTime mLastModified; QDateTime mLastUsed; QString mText; private: int mUnitId; }; class KRAFTCAT_EXPORT CatalogTemplateList : public QList { public: CatalogTemplateList(); virtual ~CatalogTemplateList(); protected: // int compareItems( QPtrCollection::Item, QPtrCollection::Item ); virtual int compareItems( CatalogTemplate*, CatalogTemplate* ); }; typedef QListIterator CatalogTemplateListIterator; #endif kraft-1.1/src/catalogtemplateprovider.cpp000066400000000000000000000053201450127457600207110ustar00rootroot00000000000000/*************************************************************************** catalogtemplateprovider - template provider class for catalog data ------------------- begin : 2007-05-23 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include "catalogtemplateprovider.h" #include "texteditdialog.h" #include "doctext.h" #include "defaultprovider.h" #include "katalog.h" #include "catalogselection.h" CatalogTemplateProvider::CatalogTemplateProvider( QWidget *parent ) :TemplateProvider( parent ), mCatalogSelection(nullptr) { } Katalog *CatalogTemplateProvider::currentCatalog() { Katalog *kat {nullptr}; if (mCatalogSelection) { kat = mCatalogSelection->currentSelectedKat(); } return kat; } void CatalogTemplateProvider::setCatalogSelection( CatalogSelection *cs ) { mCatalogSelection = cs; connect( mCatalogSelection, SIGNAL( actionAppendPosition() ), this, SLOT( slotTemplateToDocument() ) ); } void CatalogTemplateProvider::slotNewTemplate() { qDebug () << "SlotNewTemplate for Catalog called!"; if ( mCatalogSelection ) { Katalog *catalog = mCatalogSelection->currentSelectedKat(); CatalogTemplateList list; const QString currKat = mCatalogSelection->currentSelectedKatChapter(); emit templatesToDocument(catalog, list, currKat); } } void CatalogTemplateProvider::slotEditTemplate() { // qDebug () << "SlotEditTemplate for Catalog called!"; // mCatalogSelection->currentSelectedPositions } void CatalogTemplateProvider::slotDeleteTemplate() { } void CatalogTemplateProvider::slotTemplateToDocument() { // qDebug () << "Moving catalog entry to document"; if ( mCatalogSelection ) { Katalog *catalog = mCatalogSelection->currentSelectedKat(); emit templatesToDocument(catalog, mCatalogSelection->currentSelectedPositions(), QString()); } } void CatalogTemplateProvider::slotInsertTemplateToDocument() { } kraft-1.1/src/catalogtemplateprovider.h000066400000000000000000000034541450127457600203640ustar00rootroot00000000000000/*************************************************************************** catalogtemplateprovider - template provider classes for catalog data ------------------- begin : 2007-05-24 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef CATALOGTEMPLATEPROVIDER_H #define CATALOGTEMPLATEPROVIDER_H #include "templateprovider.h" #include "doctext.h" #include "catalogtemplate.h" #include "katalog.h" class QWidget; class CatalogSelection; class CatalogTemplateProvider : public TemplateProvider { Q_OBJECT public: CatalogTemplateProvider( QWidget* ); void setCatalogSelection( CatalogSelection * ); Katalog *currentCatalog(); signals: void templatesToDocument( Katalog*, CatalogTemplateList, const QString& ); void catalogSelected(Katalog*); public slots: void slotNewTemplate() override; void slotEditTemplate() override; void slotDeleteTemplate() override; void slotTemplateToDocument() override; void slotInsertTemplateToDocument() override; private: CatalogSelection *mCatalogSelection; }; #endif kraft-1.1/src/createdb.ui000066400000000000000000000074641450127457600154070ustar00rootroot00000000000000 createDbForm 0 0 395 232 Database creation and initial schema setup: true 0 0 / 129 30 0 X Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Filling the database with initial values: true 0 0 / 129 30 0 X Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Status: QFrame::NoFrame Database setup status... true Qt::Vertical 20 149 kraft-1.1/src/databasesettings.kcfg000066400000000000000000000030141450127457600174430ustar00rootroot00000000000000 localhost -1 root kraft-1.1/src/databasesettings.kcfgc000066400000000000000000000001241450127457600176050ustar00rootroot00000000000000File=databasesettings.kcfg ClassName=DatabaseSettings Singleton=true Mutators=true kraft-1.1/src/dbids.h000066400000000000000000000043001450127457600145170ustar00rootroot00000000000000/*************************************************************************** dbids.h - database id class ------------------- begin : ? copyright : (C) 2006- by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DBIDS_H #define DBIDS_H #include #include #include #include /** * utility class that provides a simple database id object. * It's useful to work with dicts which do not work on base * types like int */ class dbID { public: dbID(int id):m_id(id){} dbID():m_id(-1){} int intID() const { return m_id; } bool operator==( const int& _u ) const { return m_id == _u; } bool operator==( const long& _u ) const { return m_id == _u; } bool operator==( const dbID& _u ) const { return m_id == _u.m_id; } bool operator!=( const dbID& _u ) const { return m_id != _u.m_id; } dbID& operator=( const QString& _u ) { bool ok; int id = _u.toInt( &ok ); if( ok ) { m_id = id; } return *this; } bool operator<( dbID _id ) { if( m_id < _id.toInt() ) return true; return false; } dbID& operator=( const int _u ) { m_id = _u; return *this; } bool isOk() const { return m_id > -1; } int toInt() { return m_id; } QString toString() const { return QString::number(m_id); } private: int m_id; }; typedef QList DBIdList; #endif kraft-1.1/src/dbinit.ui000066400000000000000000000052011450127457600150720ustar00rootroot00000000000000 dbInitWidget 0 0 556 244 Database Update: true Overall Progress: 0 TextLabel Detail Progress: 0 TextLabel Status: TextLabel kraft-1.1/src/dbselect.ui000066400000000000000000000036361450127457600154200ustar00rootroot00000000000000 dbSelectForm 0 0 419 255 <html><head/><body><p>Kraft uses a database backend to store values. By default it uses a file based database with easy setup targeted to single user mode.</p><p><br/></p></body></html> true SQLite 3 - file based database (default) true buttonGroup MySQL Serverbased Database for advanced Setups buttonGroup Qt::Vertical 20 94 kraft-1.1/src/defaultprovider.cpp000066400000000000000000000222211450127457600171660ustar00rootroot00000000000000/*************************************************************************** defaultprovider.cpp - Default Providing Class ------------------- begin : November 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include "defaultprovider.h" #include "kraftdb.h" #include "doctext.h" #include "kraftsettings.h" #include "doctype.h" #include "kraftdoc.h" #include "dbids.h" #include Q_GLOBAL_STATIC(DefaultProvider, mSelf) DefaultProvider *DefaultProvider::self() { return mSelf; } DefaultProvider::DefaultProvider() { } QIcon DefaultProvider::icon(const QString& name) { const QString fullIconName = QString(":kraft/custom-icons/%1.svg").arg(name); const QIcon icon { fullIconName }; return icon; } QString DefaultProvider::docType() { QString type = KraftSettings::self()->doctype(); if ( type.isEmpty() ) { QStringList allTypes = DocType::allLocalised(); if( ! allTypes.isEmpty() ) { type = DocType::allLocalised()[0]; } else { type = i18n( "Unknown" ); } } return type; } DocTextList DefaultProvider::documentTexts( const QString& docType, KraftDoc::Part tt ) { DocTextList re; QString typeStr = DocText::textTypeToString( tt ); QString sql = QString( "SELECT texts.docTextID, texts.name, texts.text, texts.description, " "texts.textType, types.name as docTypeName FROM DocTexts texts, " "DocTypes types WHERE texts.docTypeId=types.docTypeID AND " "types.name=\'%1\' AND textType = \'%2\'").arg( docType ).arg( typeStr ); // qDebug() << "Reading texts from DB with: " << sql; QSqlQuery query( sql ); if ( query.isActive() ) { while ( query.next() ) { DocText dt; dt.setDbId( query.value( 0 ) /* docTextID */ .toInt() ); dt.setName( query.value( 1 ) /* name */ .toString() ); dt.setText( KraftDB::self()->mysqlEuroDecode( query.value( 2 ) /* text */ .toString() ) ); dt.setDescription( query.value( 3 ) /* description */ .toString() ); dt.setTextType( DocText::stringToTextType( query.value( 4 ) /* textType */ .toString() ) ); dt.setDocType( query.value( 5 ) /* docType */ .toString() ); re.append( dt ); } } return re; } QString DefaultProvider::defaultText( const QString& docType, KraftDoc::Part p, DocGuardedPtr ) { QString re; DocTextList list = documentTexts( docType, p ); DocTextList::iterator it; for ( it = list.begin(); it != list.end(); ++it ) { if( (*it).isStandardText() ) { re = ( *it ).text(); break; } } return re; } dbID DefaultProvider::saveDocumentText( const DocText& t ) { dbID retVal; QSqlTableModel model; model.setTable( "DocTexts" ); if ( t.dbId().isOk() ) { // qDebug () << "Doing update!"; model.setFilter( "docTextID=" + t.dbId().toString() ); model.select(); if( model.rowCount() > 0 ) { QSqlRecord record = model.record(0); record.setValue( "docTextID", t.dbId().toString() ); record.setValue( "name", t.name() ); record.setValue( "description", t.description() ); record.setValue( "text", KraftDB::self()->mysqlEuroEncode( t.text() ) ); record.setValue( "docType", t.docType() ); record.setValue( "docTypeId", DocType::docTypeId( t.docType() ).toString() ); record.setValue( "textType", t.textTypeString() ); model.setRecord(0, record); model.submitAll(); } } else { // qDebug () << "Doing insert!"; QSqlRecord record = model.record(); record.setValue( "name", t.name() ); record.setValue( "description", t.description() ); record.setValue( "text", KraftDB::self()->mysqlEuroEncode( t.text() ) ); record.setValue( "docType", t.docType() ); record.setValue( "docTypeId", DocType::docTypeId( t.docType() ).toString() ); record.setValue( "textType", t.textTypeString() ); model.insertRecord(-1, record); model.submitAll(); } retVal = KraftDB::self()->getLastInsertID(); return retVal; } QLocale* DefaultProvider::locale() { return &_locale; } void DefaultProvider::deleteDocumentText( const DocText& dt ) { if ( dt.dbId().isOk() ) { QSqlQuery q; q.prepare("DELETE FROM DocTexts WHERE docTextID=" + dt.dbId().toString() ) ; q.exec(); } else { // qDebug () << "Delete document text not ok: " << dt.text(); } } QString DefaultProvider::currencySymbol() const { return self()->locale()->currencySymbol(); } QString DefaultProvider::iconvTool() const { return locateBinary( "iconv" ); } QString DefaultProvider::getStyleSheet( const QString& styleName ) const { QString style; if( styleName.isEmpty() ) return style; const QString findFile = QString("styles/%1.style").arg(styleName); const QString tmplFile = locateFile(findFile); QFile data( tmplFile ); if (data.open( QFile::ReadOnly )) { QTextStream readIn( &data ); style = readIn.readAll(); data.close(); } return style; } // this method first checks if KRAFT_HOME is set. If it is it tries to read the files from there. // If KRAFT_HOME is not set, it uses QStandardPath::locate from the AppDataLocation to find // files. // // For AppImage, this method should actually look relative to the application directory. // QString DefaultProvider::locateFile(const QString& findFile) const { QString re; const QString kraftHome = QString::fromUtf8(qgetenv( "KRAFT_HOME" )); if (!kraftHome.isEmpty()){ // KRAFT_HOME is set QString fifi {kraftHome}; if (!fifi.endsWith('/') && !findFile.startsWith('/')) fifi.append('/'); fifi.append(findFile); if (QFile::exists(fifi)) { re = fifi; } } if (re.isEmpty()) { // it was not found in the system location or in KRAFT_HOME // If so, check relative to the binary for AppImage. QString fifi = QString("%1/../share/kraft/%2").arg(QCoreApplication::applicationDirPath()).arg(findFile); if (QFile::exists(fifi)) { QFileInfo fi(fifi); re = fi.absoluteFilePath(); } } // check the system paths if (re.isEmpty()) { // prepend the kraft path segment and look in the system resources QString fifi {findFile}; re = QStandardPaths::locate( QStandardPaths::AppDataLocation, fifi); } if (re.isEmpty()) { qDebug() << "locateFile could not find file " << findFile; } return re; } QStringList DefaultProvider::locatePythonTool(const QString& toolName) const { QString fullPath; // first use the standard locateFile to consider KRAFT_HOME and relative... fullPath = locateFile("tools/" + toolName); // if that is empty, go for the system executables if (fullPath.isEmpty()) { fullPath = QStandardPaths::findExecutable(toolName); } QFileInfo fi(fullPath); if (!fi.exists()) { fullPath.clear(); } // -- check for python. // Default is python3 // If Kraft is running from an AppImage, we rather use the python from conda which is // installed in a relative path. QString python {"python3"}; const QString pypath = QCoreApplication::applicationDirPath() + QStringLiteral("/../conda/bin/python"); QFileInfo fip(pypath); if (fip.exists() && fip.isExecutable()) { python = fip.canonicalFilePath(); } QStringList rep {python, fullPath}; qDebug() << "Returning tool path" << rep; return rep; } QString DefaultProvider::locateBinary(const QString& name) const { // check the current app path and check if the binary is in there. (AppImage) const QString path = QCoreApplication::applicationDirPath(); const QString localPrg = QString("%1/%2").arg(path).arg(name); QFileInfo fi{localPrg}; if (fi.exists() && fi.isExecutable()) { qDebug() << "Returning tool path" << fi.absoluteFilePath() << "for" << name; return fi.absoluteFilePath(); } const QString bin = QStandardPaths::findExecutable( name ); return bin; } bool DefaultProvider::writeXmlArchive() { return KraftSettings::self()->doXmlArchive(); } QString DefaultProvider::xmlArchivePath() { return KraftSettings::self()->xmlArchivePath(); } QString DefaultProvider::pdfOutputDir() { return KraftSettings::self()->pdfOutputDir(); } DefaultProvider::~DefaultProvider() { } kraft-1.1/src/defaultprovider.h000066400000000000000000000043171450127457600166410ustar00rootroot00000000000000/*************************************************************************** defaultprovider.h - Defaults for this and that ------------------- begin : November 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DEFAULTPROVIDER_H #define DEFAULTPROVIDER_H #include #include "kraftcat_export.h" #include "kraftdoc.h" #include "doctext.h" class QSqlRecord; class QStringList; class dbID; /** * encapsulates all relevant for default values for documents such as * texts etc. */ class KRAFTCAT_EXPORT DefaultProvider { public: ~DefaultProvider(); static DefaultProvider *self(); QIcon icon(const QString& name); QString defaultText( const QString&, KraftDoc::Part, DocGuardedPtr = 0 ); dbID saveDocumentText( const DocText& ); void deleteDocumentText( const DocText& ); QString docType(); // the default document type for new docs DocTextList documentTexts( const QString&, KraftDoc::Part ); QString currencySymbol() const; QLocale* locale(); QString iconvTool() const; QStringList locatePythonTool(const QString& toolName) const; QString locateBinary(const QString& name) const; QString locateFile(const QString& findFile) const; QString getStyleSheet( const QString& ) const; DefaultProvider(); bool writeXmlArchive(); QString pdfOutputDir(); QString xmlArchivePath(); private: // static DefaultProvider *mSelf; QLocale _locale; const QString EuroTag; }; #endif kraft-1.1/src/docassistant.cpp000066400000000000000000000365611450127457600165020ustar00rootroot00000000000000/*************************************************************************** docassistant.cpp - Assistant widget ------------------- begin : April 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include "docassistant.h" #include "docpostcard.h" #include "catalogselection.h" #include "textselection.h" #include "kraftsettings.h" #include "kataloglistview.h" #include "doctext.h" #include "defaultprovider.h" #include "headertemplateprovider.h" #include "footertemplateprovider.h" #include "catalogtemplateprovider.h" #include "addresstemplateprovider.h" DocAssistant::DocAssistant( QWidget *parent ): QSplitter( parent ), mFullPreview( true ), mActivePage( KraftDoc::Header ) { setOrientation( Qt::Vertical ); QWidget *topWidget = new QWidget; QVBoxLayout *topVBox = new QVBoxLayout; topVBox->setMargin(0); topWidget->setLayout( topVBox ); QHBoxLayout *buttonLayout = new QHBoxLayout; topVBox->addLayout( buttonLayout ); QPushButton *pb = new QPushButton( i18n( "Show &Templates" ) ); buttonLayout->addWidget( pb ); connect( pb, SIGNAL( toggled( bool ) ), this, SLOT( slotToggleShowTemplates( bool ) ) ); pb->setCheckable( true ); pb->setToolTip( i18n( "Show mask to create or select templates to be used in the document" ) ); buttonLayout->addStretch(); topVBox->addLayout(buttonLayout); mPostCard = new DocPostCard; mPostCard->slotSetMode( DocPostCard::Full, KraftDoc::Header ); // setResizeMode( vb /* mPostCard->view() */, KeepSize ); topVBox->addWidget(mPostCard); addWidget(topWidget); mTemplatePane = new QWidget; QVBoxLayout *bottomVBox = new QVBoxLayout; bottomVBox->setMargin(0); mTemplatePane->setLayout( bottomVBox ); addWidget( mTemplatePane ); setStretchFactor(0, 0); setStretchFactor(1, 0); mWidgetStack = new QStackedWidget; bottomVBox->addWidget( mWidgetStack ); mWidgetStack->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); /* Selections are the gui reprenentations of the template providing catalogs * like header- and footer texts and catalogs. */ mCatalogSelection = new CatalogSelection; mWidgetStack->addWidget( mCatalogSelection ); connect( mCatalogSelection, SIGNAL( selectionChanged(QTreeWidgetItem*,QTreeWidgetItem*) ), this, SLOT( slotCatalogSelectionChanged(QTreeWidgetItem*,QTreeWidgetItem*) ) ); mHeaderSelector = new TextSelection( 0, KraftDoc::Header ); mWidgetStack->addWidget( mHeaderSelector ); connect( mHeaderSelector, SIGNAL(validTemplateSelected() ), this, SLOT( slotTemplateSelectionChanged() ) ); connect( mHeaderSelector, SIGNAL(editCurrentTemplate()), this, SLOT(slotEditTemplate())); mFooterSelection = new TextSelection( 0, KraftDoc::Footer ); mWidgetStack->addWidget( mFooterSelection ); connect( mFooterSelection, SIGNAL(validTemplateSelected()), this, SLOT(slotTemplateSelectionChanged())); connect( mFooterSelection, SIGNAL(editCurrentTemplate()), this, SLOT(slotEditTemplate())); connect( mFooterSelection, SIGNAL( actionCurrentTextToDoc() ), this, SLOT( slotAddToDocument() ) ); connect( mPostCard, SIGNAL( selectPage( int ) ), this, SLOT( slotSelectDocPart( int ) ) ); QHBoxLayout *butHBox2 = new QHBoxLayout; bottomVBox->addLayout( butHBox2 ); QIcon icons = DefaultProvider::self()->icon( "arrow-narrow-left" ); mPbAdd = new QPushButton( icons, QString() ); mPbAdd->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ); connect( mPbAdd, SIGNAL( clicked() ), this, SLOT( slotAddToDocument() ) ); butHBox2->addWidget( mPbAdd ); mPbAdd->setToolTip( i18n( "Add a template to the document" ) ); icons = DefaultProvider::self()->icon( "arrow-bar-to-left" ); mPbInsert = new QPushButton( icons, QString() ); mPbInsert->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ); connect( mPbInsert, SIGNAL( clicked() ), this, SLOT( slotInsertIntoDocument() ) ); butHBox2->addWidget( mPbInsert); mPbInsert->setToolTip( i18n( "Insert the template to the document" ) ); butHBox2->insertSpacing(2, 40); icons = DefaultProvider::self()->icon( "plus" ); mPbNew = new QPushButton( icons, QString() ); // KDE 4 icon name: document-new mPbNew->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ); connect( mPbNew, SIGNAL( clicked() ), this, SLOT( slotNewTemplate() ) ); mPbNew->setToolTip( i18n( "Create a new template" ) ); butHBox2->addWidget( mPbNew ); icons = DefaultProvider::self()->icon( "edit" ); mPbEdit = new QPushButton( icons, QString() ); // KDE 4 icon name: document-properties mPbEdit->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ); connect( mPbEdit, SIGNAL( clicked() ), this, SLOT( slotEditTemplate() ) ); mPbEdit->setToolTip( i18n( "Edit the current template" ) ); butHBox2->addWidget( mPbEdit ); icons = DefaultProvider::self()->icon( "x" ); mPbDel = new QPushButton( icons, QString() ); // KDE 4 icon name: edit-delete mPbDel->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ); connect( mPbDel, SIGNAL( clicked() ), this, SLOT( slotDeleteTemplate() ) ); mPbDel->setToolTip( i18n( "Delete the current template" ) ); butHBox2->addWidget( mPbDel ); butHBox2->addStretch(); mPbAdd->setEnabled( false ); mPbNew->setEnabled( false ); mPbEdit->setEnabled( false ); mPbDel->setEnabled( false ); mPbInsert->setEnabled(false); /* Template Provider initialisations */ mHeaderTemplateProvider = new HeaderTemplateProvider( parent ); /* get a new header text from the default provider */ connect( mHeaderTemplateProvider, SIGNAL( newHeaderText( const DocText& ) ), this, SLOT( slotNewHeaderDocText( const DocText& ) ) ); connect( mHeaderTemplateProvider, SIGNAL( updateHeaderText( const DocText& ) ), this, SLOT( slotUpdateHeaderDocText( const DocText& ) ) ); connect( mHeaderTemplateProvider, &HeaderTemplateProvider::headerTextToDocument, this, &DocAssistant::headerTextTemplate); connect( mHeaderTemplateProvider, SIGNAL( headerTextToDocument( const DocText& ) ), this, SLOT( slotHeaderTextToDocument( const DocText& ) ) ); connect( mHeaderTemplateProvider, SIGNAL( deleteHeaderText( const DocText& ) ), this, SLOT( slotHeaderTextDeleted( const DocText& ) ) ); mHeaderTemplateProvider->setSelection( mHeaderSelector ); mFooterTemplateProvider = new FooterTemplateProvider( parent ); /* get a new Footer text from the default provider */ connect( mFooterTemplateProvider, SIGNAL( newFooterText( const DocText& ) ), this, SLOT( slotNewFooterDocText( const DocText& ) ) ); connect( mFooterTemplateProvider, SIGNAL( updateFooterText( const DocText& ) ), this, SLOT( slotUpdateFooterDocText( const DocText& ) ) ); connect( mFooterTemplateProvider, &FooterTemplateProvider::footerTextToDocument, this, &DocAssistant::footerTextTemplate); connect( mFooterTemplateProvider, SIGNAL( deleteFooterText( const DocText& ) ), this, SLOT( slotFooterTextDeleted( const DocText& ) ) ); mFooterTemplateProvider->setSelection( mFooterSelection ); /* Catalog Template Provider */ mCatalogTemplateProvider = new CatalogTemplateProvider( parent ); mCatalogTemplateProvider->setCatalogSelection( mCatalogSelection ); connect(mCatalogTemplateProvider, &CatalogTemplateProvider::templatesToDocument, this, &DocAssistant::templatesToDocument); mCurrTemplateProvider = mHeaderTemplateProvider; const QList sizes = KraftSettings::self()->assistantSplitterSetting(); if( sizes.count() > 0 ) { setSizes( sizes ); } mTemplatePane->hide(); } void DocAssistant::slotInsertIntoDocument() { // qDebug () << "SlotInsertIntoDocument called!"; if ( mCurrTemplateProvider ) { mCurrTemplateProvider->slotInsertTemplateToDocument(); } } void DocAssistant::slotAddToDocument() { // qDebug () << "SlotAddToDocument called!"; if ( mCurrTemplateProvider ) { mCurrTemplateProvider->slotTemplateToDocument(); } } void DocAssistant::slotTemplateSelectionChanged( ) { if (!mCurrTemplateProvider) { mPbNew->setEnabled(false); mPbEdit->setEnabled(false); mPbDel->setEnabled(false); mPbInsert->setEnabled(false); return; } if( mActivePage == KraftDoc::Positions ) { // no editing on the catalogs bool enableNew {false}; auto kat = static_cast(mCurrTemplateProvider)->currentCatalog(); if (kat->type() == KatalogType::TemplateCatalog) { enableNew = true; } mPbNew->setEnabled(enableNew); mPbEdit->setEnabled( false ); mPbDel->setEnabled( false ); mPbInsert->setEnabled(false); } else { bool mv {false}; if( mActivePage == KraftDoc::Header ) { mv = mHeaderSelector->validSelection(); } else if( mActivePage == KraftDoc::Footer ) { mv = mFooterSelection->validSelection(); } mPbAdd->setEnabled( mv ); mPbNew->setEnabled( true ); mPbEdit->setEnabled( mv ); mPbDel->setEnabled( mv ); mPbInsert->setEnabled(mv); } } void DocAssistant::slotCatalogSelectionChanged(QTreeWidgetItem *current ,QTreeWidgetItem *) { // enable the move-to-document button. // qDebug () << "catalog position selection changed!"; if ( current ) { mPbAdd->setEnabled( true ); } else { mPbAdd->setEnabled( false ); } mPbInsert->setEnabled(false); slotTemplateSelectionChanged(); } void DocAssistant::slotNewTemplate() { /* always set the doc type in case the provider benefits from that */ mCurrTemplateProvider->slotSetDocType( mDocType ); mCurrTemplateProvider->slotNewTemplate(); } /* a new header doc text was created and should go to the document */ void DocAssistant::slotNewHeaderDocText( const DocText& dt ) { /* show in list of texts in the GUI */ mHeaderSelector->addNewDocText( dt ); } /* called with a changed text that needs to be updated in the view */ void DocAssistant::slotUpdateHeaderDocText( const DocText& dt ) { mHeaderSelector->updateDocText( dt ); } /* a new header doc text was created and should go to the document */ void DocAssistant::slotNewFooterDocText( const DocText& dt ) { /* show in list of texts in the GUI */ mFooterSelection->addNewDocText( dt ); } /* called with a changed text that needs to be updated in the view */ void DocAssistant::slotUpdateFooterDocText( const DocText& dt ) { mFooterSelection->updateDocText( dt ); } /* Slot that initiates an edit */ void DocAssistant::slotEditTemplate() { // qDebug () << "Editing a template using the currentTemplProvider"; if ( mCurrTemplateProvider ) { mCurrTemplateProvider->slotSetDocType( mDocType ); mCurrTemplateProvider->slotEditTemplate(); } } /* slot that initialises a delete, called from the delete button */ void DocAssistant::slotDeleteTemplate() { QMessageBox msgBox; msgBox.setText(i18n( "Do you really want to delete the template permanently?\n" "It can not be recovered.")); msgBox.setStandardButtons(QMessageBox::Yes| QMessageBox::No); msgBox.setDefaultButton(QMessageBox::Yes); int ret = msgBox.exec(); if ( ret == QMessageBox::No ) { return; } if ( mCurrTemplateProvider ) { mCurrTemplateProvider->slotDeleteTemplate(); } } void DocAssistant::slotHeaderTextDeleted( const DocText& /* dt */) { mHeaderSelector->deleteCurrentText(); slotTemplateSelectionChanged( ); // disable the edit buttons etc. } void DocAssistant::slotFooterTextDeleted( const DocText& /* dt */) { mFooterSelection->deleteCurrentText(); slotTemplateSelectionChanged( ); // disable the edit buttons etc. } /* slot that opens the template details in case on == true */ void DocAssistant::slotToggleShowTemplates( bool on ) { if ( on ) { // setFullPreview is set in the subslots called from here, that // makes mFullPreview truly reflecting the state of the toggle button if ( mActivePage == KraftDoc::Header ) { slotShowHeaderTemplates(); } else if ( mActivePage == KraftDoc::Positions ) { slotShowCatalog(); } else if ( mActivePage == KraftDoc::Footer ) { slotShowFooterTemplates(); } } else { // hide the details setFullPreview( true, mActivePage ); } emit toggleShowTemplates( on ); } DocPostCard *DocAssistant::postCard() { return mPostCard; } CatalogSelection* DocAssistant::catalogSelection() { return mCatalogSelection; } /* sets the Part of the doc, eg. Header, Footer */ void DocAssistant::slotSelectDocPart( int p ) { mActivePage = p; if( mActivePage == KraftDoc::Header ) { mCurrTemplateProvider = mHeaderTemplateProvider; } else if( mActivePage == KraftDoc::Positions ) { mCurrTemplateProvider = mCatalogTemplateProvider; } else if( mActivePage == KraftDoc::Footer ) { mCurrTemplateProvider = mFooterTemplateProvider; } else { // qDebug () << "Alert: Unknown document part id: " << p; } emit selectPage( p ); slotToggleShowTemplates( !mFullPreview ); slotTemplateSelectionChanged( ); // hide the add, edit- and del buttons } /* Doc Type like offer, invoice etc. */ void DocAssistant::slotSetDocType( const QString& type ) { mDocType = type; mHeaderSelector->slotSelectDocType( type ); mFooterSelection->slotSelectDocType( type ); } void DocAssistant::slotShowCatalog( ) { setFullPreview( false, KraftDoc::Positions ); mWidgetStack->setCurrentWidget( mCatalogSelection ); } void DocAssistant::slotShowHeaderTemplates() { setFullPreview( false, KraftDoc::Header ); mWidgetStack->setCurrentWidget( mHeaderSelector ); } void DocAssistant::slotShowFooterTemplates() { setFullPreview( false, KraftDoc::Footer ); mWidgetStack->setCurrentWidget( mFooterSelection ); } void DocAssistant::setFullPreview( bool setFull, int id ) { if ( setFull ) { /* remember the sizes used before */ saveSplitterSizes(); mTemplatePane->hide(); mPostCard->slotSetMode( DocPostCard::Full, id ); mFullPreview = true; } else { mTemplatePane->show(); mPostCard->slotSetMode( DocPostCard::Mini, id ); if ( KraftSettings::self()->assistantSplitterSetting().size() == 2 ) { QList sizes = KraftSettings::self()->assistantSplitterSetting(); if( sizes.contains(0)) { sizes[0] = 50; sizes[1] = 50; } setSizes( sizes ); } mFullPreview = false; } } void DocAssistant::saveSplitterSizes() { if( mTemplatePane->isVisible() ) { const QList s = sizes(); KraftSettings::self()->setAssistantSplitterSetting( s ); } } kraft-1.1/src/docassistant.h000066400000000000000000000070771450127457600161470ustar00rootroot00000000000000/*************************************************************************** docassistant.h - Assistant widget ------------------- begin : April 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DOCASSISTANT_H #define DOCASSISTANT_H #include #include #include #include #include #include "kraftdoc.h" #include "catalogtemplate.h" #include "docpostcard.h" #include "catalogselection.h" class TextSelection; class QWidget; class QPushButton; class Katalog; class TemplateProvider; class HeaderTemplateProvider; class CatalogTemplateProvider; class FooterTemplateProvider; class AddressTemplateProvider; class DocText; class QSplitter; using namespace KContacts; class DocAssistant : public QSplitter { Q_OBJECT public: DocAssistant( QWidget* ); DocPostCard *postCard(); CatalogSelection *catalogSelection(); void saveSplitterSizes(); public slots: void slotShowCatalog(); void slotShowHeaderTemplates(); void slotShowFooterTemplates(); void setFullPreview( bool, int ); void slotSelectDocPart( int ); void slotToggleShowTemplates( bool ); void slotAddToDocument(); void slotInsertIntoDocument(); void slotNewTemplate(); void slotEditTemplate(); void slotDeleteTemplate(); void slotSetDocType( const QString& ); protected slots: void slotTemplateSelectionChanged(); void slotFooterTextDeleted( const DocText& ); void slotHeaderTextDeleted( const DocText& ); void slotNewHeaderDocText( const DocText& ); void slotUpdateHeaderDocText( const DocText& ); void slotCatalogSelectionChanged( QTreeWidgetItem*,QTreeWidgetItem* ); void slotNewFooterDocText( const DocText& ); void slotUpdateFooterDocText( const DocText& ); signals: void selectPage( int ); void templatesToDocument( Katalog*, CatalogTemplateList, const QString&); void toggleShowTemplates( bool ); void addressTemplate( const Addressee& ); void headerTextTemplate( const DocText&, bool replace ); void footerTextTemplate( const DocText&, bool replace ); private: DocPostCard *mPostCard; CatalogSelection *mCatalogSelection; QStackedWidget *mWidgetStack; TextSelection *mFooterSelection; TextSelection *mHeaderSelector; bool mFullPreview; int mActivePage; QPushButton *mPbAdd; QPushButton *mPbInsert; QPushButton *mPbNew; QPushButton *mPbEdit; QPushButton *mPbDel; QWidget *mTemplatePane; QString mDocType; // QSplitter *mMainSplit; TemplateProvider *mCurrTemplateProvider; HeaderTemplateProvider *mHeaderTemplateProvider; AddressTemplateProvider *mAddressTemplateProvider; CatalogTemplateProvider *mCatalogTemplateProvider; FooterTemplateProvider *mFooterTemplateProvider; }; #endif kraft-1.1/src/docdigest.cpp000066400000000000000000000061311450127457600157360ustar00rootroot00000000000000/*************************************************************************** docdigest.cpp ------------------- begin : Wed Mar 15 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include "docdigest.h" #include "defaultprovider.h" #include "format.h" #include "kraftsettings.h" DocDigest::DocDigest( dbID id, const QString& type, const QString& clientID ) :mID(id), mType( type ), mClientId( clientID ), mLocale( "kraft" ) { } DocDigest::DocDigest() :mLocale( "kraft" ) { } QString DocDigest::date() const { return Format::toDateString(mDate, KraftSettings::self()->dateFormat()); } QDate DocDigest::rawDate() const { return mDate; } QString DocDigest::lastModified() const { const QString re = QString( "%1 %2").arg( Format::toDateString(mLastModified.date(), KraftSettings::self()->dateFormat())) .arg(mLastModified.time().toString("hh:mm")); return re; } ArchDocDigestList DocDigest::archDocDigestList() const { const QString id(ident()); qDebug() << "Querying archdocs for document ident " << id; QSqlQuery query; query.prepare("SELECT archDocID, ident, docType, printDate, state FROM archdoc WHERE" " ident=:id ORDER BY printDate DESC" ); query.bindValue(":id", id); query.exec(); ArchDocDigestList archDocs; while(query.next()) { int archDocID = query.value(0).toInt(); const QString dbIdent = query.value(1).toString(); const QString docType = query.value(2).toString(); QDateTime printDateTime = query.value(3).toDateTime(); int state = query.value(4).toInt(); archDocs.append( ArchDocDigest( printDateTime, state, dbIdent, docType, dbID(archDocID) ) ); } return archDocs; } KContacts::Addressee DocDigest::addressee() const { return mContact; } void DocDigest::setAddressee( const KContacts::Addressee& contact ) { mContact = contact; } /* *************************************************************************** */ DocDigestsTimeline::DocDigestsTimeline() :mMonth( 0 ), mYear( 0 ) { } DocDigestsTimeline::DocDigestsTimeline( int m, int y ) :mMonth( m ), mYear( y ) { } void DocDigestsTimeline::setDigestList( const DocDigestList& list ) { mDigests = list; } kraft-1.1/src/docdigest.h000066400000000000000000000064611450127457600154110ustar00rootroot00000000000000/*************************************************************************** docdigest.h - ------------------- begin : Wed Mar 15 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DOCDIGEST_H #define DOCDIGEST_H #include #include #include #include "dbids.h" #include "archdoc.h" class QString; class QDate; typedef QList ArchDocDigestList; class DocDigest { public: DocDigest( dbID id, const QString& type, const QString& clientID ); DocDigest(); QString clientId() const { return mClientId; } void setClientId( const QString& id ) { mClientId = id; } QString clientAddress() const { return mClientAddress; } void setClientAddress( const QString& address ) { mClientAddress = address; } KContacts::Addressee addressee() const; void setAddressee( const KContacts::Addressee& ); QString type() const { return mType; } void setType( const QString& t ) { mType = t; } QString date() const; void setDate( const QDate& date ) { mDate = date; } QDate rawDate() const; QString lastModified() const; void setLastModified( const QDateTime& date ) { mLastModified = date; } QString id() const { return mID.toString(); } void setId( dbID id ) { mID = id; } QString ident() const { return mIdent; } void setIdent( const QString& ident ) { mIdent = ident; } QString whiteboard() const { return mWhiteboard; } void setWhiteboard( const QString& white ) { mWhiteboard = white; } void setProjectLabel( const QString& prjLabel ) { mProjectLabel = prjLabel; } QString projectLabel() const { return mProjectLabel; } ArchDocDigestList archDocDigestList() const; protected: dbID mID; QString mType; QString mClientId; QString mIdent; QString mWhiteboard; QString mProjectLabel; QString mClientAddress ; QDateTime mLastModified; QDate mDate; QLocale mLocale; private: KContacts::Addressee mContact; }; typedef QList DocDigestList; typedef QList DocDigestListIterator; class DocDigestsTimeline { public: DocDigestsTimeline(); DocDigestsTimeline( int, int ); int month() { return mMonth; } void setMonth( int m ) { mMonth = m; } int year() { return mYear; } void setYear( int y ) { mYear = y; } DocDigestList digests() { return mDigests; } void setDigestList( const DocDigestList& ); void clearDigestList() { mDigests.clear (); } private: int mMonth, mYear; DocDigestList mDigests; }; typedef QList DocDigestsTimelineList; #endif kraft-1.1/src/docdigestdetailview.cpp000066400000000000000000000441711450127457600200220ustar00rootroot00000000000000/*************************************************************************** docdigestdetailview.cpp - Details of a doc digest ------------------- begin : februry 2011 copyright : (C) 2011 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include "docdigest.h" #include "docdigestdetailview.h" #include "defaultprovider.h" #include "htmlview.h" #include "texttemplate.h" #include "archdoc.h" #include "format.h" DocDigestHtmlView::DocDigestHtmlView( QWidget *parent ) : HtmlView( parent ) { connect(this, SIGNAL(openUrl(QUrl)), this, SLOT(slotLinkClicked(QUrl))); } void DocDigestHtmlView::slotLinkClicked(const QUrl& url) { const QUrlQuery q(url); // Url is like "http://localhost/show_last_print?id=5" const QString idStr = q.queryItemValue(QLatin1String("id")); const QString path = url.path(); bool ok; if( path.endsWith("show_last_print")) { emit( showLastPrint( dbID(idStr.toInt(&ok)))); } else if (path.endsWith("export_xrechnung")) { emit( exportXRechnung(dbID(idStr.toInt(&ok)))); } } // ######################################################################################################### DocDigestDetailView::DocDigestDetailView(QWidget *parent) : QFrame(parent) { setFrameStyle(QFrame::StyledPanel+QFrame::Raised); QHBoxLayout *hbox = new QHBoxLayout; hbox->setSpacing(0); const int detailMinWidth = 260; setFixedHeight(200); // --- The left details box _leftDetails = new QLabel; hbox->addWidget(_leftDetails); _leftDetails->setTextFormat(Qt::RichText); _leftDetails->setMinimumWidth(detailMinWidth); _leftDetails->setFrameStyle(0); _leftDetails->setTextInteractionFlags(Qt::TextSelectableByMouse); // --- The middle HTML based view hbox->setMargin(0); setLayout( hbox ); mHtmlCanvas = new DocDigestHtmlView( this ); mHtmlCanvas->setFrameStyle(0); mHtmlCanvas->setStylesheetFile("docdigestview.css"); connect( mHtmlCanvas, SIGNAL(showLastPrint( const dbID& )), this, SIGNAL( showLastPrint( const dbID& ) ) ); connect( mHtmlCanvas, SIGNAL(exportXRechnung( const dbID& )), this, SIGNAL( exportXRechnung( const dbID& ) ) ); hbox->addWidget( mHtmlCanvas); const QString bgColor = mHtmlCanvas->palette().base().color().name(); const QString style = QString("QLabel { " "background-color: %1; " "background-image: url(:/kraft/kraft_customer.png); background-repeat: repeat-none;" "background-position: top left; " "padding: 10px; " "}").arg(bgColor); _leftDetails->setStyleSheet(style); _leftDetails->setWordWrap(true); // --- The right details Box const QString styleR = QString("QLabel { " "background-color: %1;" "background-image: url(:/kraft/postit.png); background-repeat: repeat-none;" "background-position: top center;" "padding: 0px; " "padding-left: 10px; " "}").arg(bgColor); _rightDetails = new QLabel; _rightDetails->setTextFormat(Qt::RichText); _rightDetails->setStyleSheet(styleR); _rightDetails->setMinimumWidth(detailMinWidth); _rightDetails->setWordWrap(true); _rightDetails->setTextInteractionFlags(Qt::TextSelectableByMouse); hbox->addWidget(_rightDetails); } void DocDigestDetailView::slotClearView() { const QString details; mHtmlCanvas->displayContent( details ); } QString DocDigestDetailView::widgetStylesheet( Location loc, Detail det ) { const QString bgColor = mHtmlCanvas->palette().base().color().name(); QString style = QString("QLabel { background-color: %1; ").arg(bgColor); QString image; QString bgPos; if( loc == Left ) { if( det == Year ) { image = "Calendar_page.png"; bgPos = "center top"; style += QLatin1String("padding-top: 95px; "); } else if( det == Month ) { image = "Calendar_page.png"; bgPos = "center top"; style += QLatin1String("padding-top: 75px; "); } else { // Document image = "kraft_customer.png"; bgPos = "top left"; style += QLatin1String( "padding-top: 50px; padding-left:15px;"); } } else if(loc == Middle ) { if( det == Year ) { } else if( det == Month ) { } else { // Document } } else if(loc == Right ) { if( det == Year ) { } else if( det == Month ) { } else { // Document image = "postit.png"; bgPos = "top center"; style += QLatin1String("padding: 0px; padding-left: 30px; "); } } else { // undef. } if( !image.isEmpty() ) { style += QString("background-image: url(:/kraft/%1); background-repeat: repeat-none;" "background-position: %2;").arg(image).arg(bgPos); } style += QLatin1String("}"); return style; } #define DOCDIGEST_TAG void DocDigestDetailView::documentListing( TextTemplate *tmpl, int year, int month ) { QString minDate; QString maxDate; if( month > -1 ) { QDate theDate(year, month, 1); // not a year minDate = theDate.toString("yyyy-MM-dd"); int lastDay = theDate.daysInMonth(); theDate.setDate(year, month, lastDay); maxDate = theDate.toString("yyyy-MM-dd"); } else { // is is a year minDate = QString::number(year)+"-01-01"; maxDate = QString::number(year)+"-12-31"; } // read data in the given timeframe from database QSqlQuery q; const QString query = QString("SELECT archDocID, ident, MAX(printDate) FROM archdoc WHERE " "date BETWEEN date('%1') AND date('%2') " "GROUP BY ident").arg(minDate, maxDate); // qDebug() << "***" << query; QMap > docMatrix; q.prepare(query); q.exec(); while( q.next() ) { dbID archDocId(q.value(0).toInt()); const ArchDoc doc(archDocId); const QString docType = doc.docTypeStr(); Geld g; int n = 0; if( docMatrix.contains(docType)) { g = docMatrix[docType].second; n = docMatrix[docType].first; } Geld g1 = doc.nettoSum(); g += g1; docMatrix[docType].first = n+1; docMatrix[docType].second = g; } // now create the template tmpl->setValue("I18N_AMOUNT", i18n("Amount")); tmpl->setValue("I18N_TYPE", i18n("Type")); tmpl->setValue("I18N_SUM", i18n("Sum")); QStringList doctypes = docMatrix.keys(); doctypes.sort(); foreach( const QString dtype, doctypes ) { qDebug() << "creating doc list for "<createDictionary( "DOCUMENTS" ); tmpl->setValue("DOCUMENTS", "DOCTYPE", dtype); const QString am = QString::number(docMatrix[dtype].first); tmpl->setValue("DOCUMENTS", "AMOUNT", am); const QString sm = docMatrix[dtype].second.toLocaleString(); tmpl->setValue("DOCUMENTS", "SUM", sm); } } void DocDigestDetailView::slotShowMonthDetails( int year, int month ) { if( _monthTemplFileName.isEmpty() ) { _monthTemplFileName = DefaultProvider::self()->locateFile( "views/monthdigest.thtml" ); } TextTemplate tmpl; tmpl.setTemplateFileName(_monthTemplFileName); if( !tmpl.isOk() ) { return; } const QString monthStr = DefaultProvider::self()->locale()->monthName(month); const QString yearStr = QString::number(year); tmpl.setValue( DOCDIGEST_TAG("HEADLINE"), i18n("Results in %1 %2", monthStr, yearStr) ); tmpl.setValue( DOCDIGEST_TAG("YEAR_LABEL"), i18n("Year")); tmpl.setValue( DOCDIGEST_TAG("YEAR_NUMBER"), yearStr); tmpl.setValue( DOCDIGEST_TAG("MONTH_LABEL"), i18n("Month")); tmpl.setValue( DOCDIGEST_TAG("MONTH_NAME"), monthStr); // Document listing documentListing(&tmpl, year, month); // left and right information blocks _leftDetails->setStyleSheet(widgetStylesheet(Left, Month)); _leftDetails->setText( "

            "+monthStr + "
            " + yearStr + "

            "); _leftDetails->setAlignment(Qt::AlignHCenter); _rightDetails->setStyleSheet(widgetStylesheet(Right, Month)); _rightDetails->clear(); const QString details = tmpl.expand(); mHtmlCanvas->displayContent(details); } void DocDigestDetailView::slotShowYearDetails( int year ) { if( _yearTemplFileName.isEmpty() ) { _yearTemplFileName = DefaultProvider::self()->locateFile( "views/yeardigest.thtml" ); } TextTemplate tmpl; tmpl.setTemplateFileName(_yearTemplFileName); if( !tmpl.isOk() ) { return; } const QString yearStr = QString::number(year); tmpl.setValue( DOCDIGEST_TAG("YEAR_LABEL"), i18n("Year")); tmpl.setValue( DOCDIGEST_TAG("YEAR_NUMBER"), yearStr); tmpl.setValue( DOCDIGEST_TAG("HEADLINE"), i18n("Results in Year %1", yearStr) ); documentListing(&tmpl, year, -1); const QString details = tmpl.expand(); _leftDetails->setStyleSheet(widgetStylesheet(Left, Year)); _leftDetails->setText("

            "+ yearStr +"

            "); _leftDetails->setAlignment(Qt::AlignHCenter); _rightDetails->setStyleSheet(widgetStylesheet(Right, Year)); _rightDetails->clear(); mHtmlCanvas->displayContent( details ); } void DocDigestDetailView::showAddress( const KContacts::Addressee& addressee, const QString& manAddress ) { Q_UNUSED(addressee) QString content = "

            " + i18n("Customer") +"

            "; if( !manAddress.isEmpty() ) { content += "
            " + manAddress +"
            "; } else { content += QLatin1String("

            ")+i18n("not set")+QLatin1String("

            "); } _leftDetails->setText( content ); #if 0 // tmpl.setValue( "URL", mHtmlCanvas->baseURL().prettyUrl()); tmpl.setValue( DOCDIGEST_TAG( "CUSTOMER_LABEL" ), i18n("Customer")); KContacts::Addressee addressee = digest.addressee(); QString adr = digest.clientAddress(); adr.replace('\n', "
            " ); tmpl.setValue( DOCDIGEST_TAG("CUSTOMER_ADDRESS_FIELD"),adr ); QString addressBookInfo; if( addressee.isEmpty() ) { if( digest.clientId().isEmpty() ) { addressBookInfo = i18n("The address is not listed in an address book."); } else { addressBookInfo = i18n("The client has the address book id %1 but can not found in our address books.", digest.clientId()); } } else { addressBookInfo = i18n("The client can be found in our address books."); tmpl.createDictionary( "CLIENT_ADDRESS_SECTION"); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENTID" ), digest.clientId() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_ADDRESS" ), digest.clientAddress() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_NAME"), addressee.realName() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_ORGANISATION"), addressee.organization() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_URL"), addressee.url().toString() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_EMAIL"), addressee.preferredEmail() ); KContacts::Address clientAddress; clientAddress = addressee.address( KContacts::Address::Pref ); QString addressType = i18n("preferred address"); if( clientAddress.isEmpty() ) { clientAddress = addressee.address( KContacts::Address::Home ); addressType = i18n("home address"); } if( clientAddress.isEmpty() ) { clientAddress = addressee.address( KContacts::Address::Work ); addressType = i18n("work address"); } if( clientAddress.isEmpty() ) { clientAddress = addressee.address( KContacts::Address::Postal ); addressType = i18n("postal address"); } if( clientAddress.isEmpty() ) { clientAddress = addressee.address( KContacts::Address::Intl ); addressType = i18n("international address"); } if( clientAddress.isEmpty() ) { clientAddress = addressee.address( KContacts::Address::Dom ); addressType = i18n("domestic address"); } if( clientAddress.isEmpty() ) { addressType = i18n("unknown"); // qDebug () << "WRN: Address is still empty!"; } tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_POSTBOX" ), clientAddress.postOfficeBox() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_EXTENDED" ), clientAddress.extended() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_STREET" ), clientAddress.street() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_LOCALITY" ), clientAddress.locality() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_REGION" ), clientAddress.region() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_POSTCODE" ), clientAddress.postalCode() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_COUNTRY" ), clientAddress.country() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_REGION" ), clientAddress.region() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_LABEL" ), clientAddress.label() ); tmpl.setValue( "CLIENT_ADDRESS_SECTION", DOCDIGEST_TAG( "CLIENT_ADDRESS_TYPE" ), addressType ); } tmpl.setValue( DOCDIGEST_TAG("CUSTOMER_ADDRESSBOOK_INFO"), addressBookInfo ); #endif } void DocDigestDetailView::slotShowDocDetails( DocDigest digest ) { // qDebug () << "Showing details about this doc: " << digest.id(); if( _docTemplFileName.isEmpty() ) { // QString templFileName = QString( "kraftdoc_%1_ro.trml" ).arg( doc->docType() ); _docTemplFileName = DefaultProvider::self()->locateFile( "views/docdigest.thtml" ); } TextTemplate tmpl; // template file with name docdigest.trml tmpl.setTemplateFileName(_docTemplFileName); if( !tmpl.isOk() ) { return; } tmpl.setValue( DOCDIGEST_TAG( "HEADLINE" ), digest.type() + " " + digest.ident() ); tmpl.setValue( DOCDIGEST_TAG( "DATE" ), digest.date() ); tmpl.setValue( DOCDIGEST_TAG( "DATE_LABEL" ), i18n("Date") ); tmpl.setValue( DOCDIGEST_TAG( "WHITEBOARD"), digest.whiteboard() ); tmpl.setValue( DOCDIGEST_TAG( "WHITEBOARD_LABEL"), i18n("Whiteboard")); if( !digest.projectLabel().isEmpty() ) { tmpl.createDictionary( "PROJECT_INFO" ); tmpl.setValue( "PROJECT_INFO", DOCDIGEST_TAG( "PROJECT"), digest.projectLabel() ); tmpl.setValue( "PROJECT_INFO", DOCDIGEST_TAG( "PROJECT_LABEL"), i18n("Project")); } showAddress( digest.addressee(), digest.clientAddress() ); // Information about archived documents. ArchDocDigestList archDocs = digest.archDocDigestList(); if( archDocs.isEmpty() ) { // qDebug () << "No archived docs for this document!"; tmpl.createDictionary( DOCDIGEST_TAG( "NEVER_PRINTED" )); tmpl.setValue( "NEVER_PRINTED", DOCDIGEST_TAG("NEVER_PRINTED_LABEL"), i18n("This document was never printed.")); } else { ArchDocDigest digest = archDocs[0]; QFileInfo fi(digest.pdfArchiveFileName()); if (fi.exists()) { tmpl.createDictionary( DOCDIGEST_TAG( "PRINTED" )); tmpl.setValue( "PRINTED", DOCDIGEST_TAG("LAST_PRINT_LABEL"), i18n( "Last printed" ) ); tmpl.setValue( "PRINTED", DOCDIGEST_TAG("LAST_PRINT_TITLE"), i18n( "Opens last created PDF document" ) ); tmpl.setValue( "PRINTED", DOCDIGEST_TAG("LAST_PRINT_LINK_TEXT"), i18n( "open" ) ); tmpl.setValue( "PRINTED", DOCDIGEST_TAG("LAST_PRINT_DATE"), Format::toDateTimeString(digest.printDate(), Format::DateFormatLong)); tmpl.setValue( "PRINTED", DOCDIGEST_TAG("LAST_PRINTED_ID"), digest.archDocId().toString() ); if( archDocs.size() == 1 ) { tmpl.setValue( "PRINTED", DOCDIGEST_TAG("ARCHIVED_COUNT"), i18n("One older print")); } else { tmpl.setValue( "PRINTED", DOCDIGEST_TAG("ARCHIVED_COUNT"), i18n("%1 older prints", archDocs.count())); } } else { tmpl.createDictionary( DOCDIGEST_TAG( "NEVER_PRINTED" )); tmpl.setValue( "NEVER_PRINTED", DOCDIGEST_TAG("NEVER_PRINTED_LABEL"), i18n("Archived documents can not be found. Check PDF Output dir.")); } if (digest.isInvoice()) { tmpl.createDictionary( DOCDIGEST_TAG( "EXPORT_XRECHNUNG" )); tmpl.setValue( "EXPORT_XRECHNUNG", DOCDIGEST_TAG("EXPORT_XRECHNUNG_TITLE"), i18n("Export the invoice in XRechnung file format")); tmpl.setValue( "EXPORT_XRECHNUNG", DOCDIGEST_TAG("EXPORT_XRECHNUNG_LABEL"), i18n("XRechnung")); } } const QString details = tmpl.expand(); mHtmlCanvas->displayContent( details ); _rightDetails->setText(digest.whiteboard()); _leftDetails->setStyleSheet(widgetStylesheet(Left, Document)); _leftDetails->setAlignment(Qt::AlignLeft); _rightDetails->setStyleSheet(widgetStylesheet(Right, Document)); // qDebug () << "BASE-URL of htmlview is " << mHtmlCanvas->baseURL(); } kraft-1.1/src/docdigestdetailview.h000066400000000000000000000044701450127457600174650ustar00rootroot00000000000000/*************************************************************************** docdigestdetailview.cpp - Details of a doc digest ------------------- begin : februry 2011 copyright : (C) 2011 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DOCDIGESTDETAILVIEW_H #define DOCDIGESTDETAILVIEW_H #include #include #include "docdigest.h" #include "htmlview.h" class dbID; class TextTemplate; class DocDigestHtmlView : public HtmlView { Q_OBJECT public: DocDigestHtmlView( QWidget *parent ); signals: void showLastPrint( const dbID& ); void exportXRechnung(const dbID&); protected slots: void slotLinkClicked(const QUrl& url); }; class DocDigestDetailView : public QFrame { Q_OBJECT public: explicit DocDigestDetailView(QWidget *parent = 0); signals: void showLastPrint(const dbID&); void exportXRechnung(const dbID&); public slots: void slotShowDocDetails( DocDigest ); void slotClearView(); void slotShowMonthDetails( int year, int month ); void slotShowYearDetails( int year); private: void showAddress( const KContacts::Addressee& addressee, const QString& manAddress ); void documentListing( TextTemplate *tmpl, int year, int month ); enum Location { Left, Middle, Right }; enum Detail { Month, Year, Document }; QString widgetStylesheet( Location loc, Detail det ); DocDigestHtmlView *mHtmlCanvas; QLabel *_leftDetails; QLabel *_rightDetails; QString _docTemplFileName; QString _monthTemplFileName; QString _yearTemplFileName; }; #endif // DOCDIGESTDETAILVIEW_H kraft-1.1/src/docfooter.ui000066400000000000000000000071601450127457600156130ustar00rootroot00000000000000 DocFooterEdit 0 0 560 282 3 Qt::Vertical QSizePolicy::Expanding 20 16 Footer Texts &Summary Text on Last Page: false m_teSummary 0 0 &Greeting: false m_cbGreeting true false Tax Document &Tax: false mTaxCombo Qt::Horizontal QSizePolicy::Expanding 361 20 kraft-1.1/src/docguardedptr.h000066400000000000000000000002061450127457600162620ustar00rootroot00000000000000#ifndef DOCGUARDEDPTR #define DOCGUARDEDPTR #include class KraftDoc; typedef QPointer DocGuardedPtr; #endif kraft-1.1/src/docheader.ui000066400000000000000000000203611450127457600155430ustar00rootroot00000000000000 DocHeaderEdit 0 0 614 451 0 30 30 16777215 TextLabel Qt::Horizontal QSizePolicy::Expanding 0 0 true &Project: Qt::AlignTop false mProjectLabelEdit &Whiteboard: Qt::AlignTop false m_whiteboardEdit 0 0 Enter a label that describes the project. This may appear on the customer document. 255 Qt::Vertical 20 40 0 0 16777215 80 true Postal &Address: Qt::AlignTop false m_postAddressEdit not selected false Qt::Horizontal QSizePolicy::Fixed 10 20 Select an addressee from the address books. select... Qt::Horizontal QSizePolicy::Expanding 41 20 &Salutatory Address: false m_letterHead Customer: false 0 0 16777215 100 &Entry Text on First Page: false m_teEntry mButtLang m_cbType m_letterHead kraft-1.1/src/docposition.cpp000066400000000000000000000260501450127457600163250ustar00rootroot00000000000000/*************************************************************************** docposition.cpp - a position in a document ------------------- begin : Fri Jan 20 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include #include // application specific includes #include "einheit.h" #include "geld.h" #include "docposition.h" #include "ui_positionwidget.h" #include "positionviewwidget.h" #include "defaultprovider.h" #include "tagman.h" /** @author Klaas Freitag */ DocPositionBase::DocPositionBase() : QObject(), m_dbId( -1 ), mToDelete( false ), mTaxType( TaxFull ), mType( Position ), mAttribs( QString::fromLatin1( "Position" ) ) { } DocPositionBase::DocPositionBase( const PositionType& t ) : QObject(), m_dbId( -1 ), mToDelete( false ), mTaxType( TaxFull ), mType( t ), mAttribs( QString::fromLatin1( "Position" ) ) { } DocPositionBase::DocPositionBase(const DocPositionBase& b ) : QObject(), m_dbId( b.m_dbId ), m_position( b.m_position ), m_text( b.m_text ), mToDelete( b.mToDelete ), mTaxType( TaxFull ), mType( b.mType ), mAttribs( b.mAttribs ) { } DocPositionBase& DocPositionBase::operator=( const DocPositionBase& dp ) { if ( this == &dp ) return *this; m_dbId = dp.m_dbId; m_position = dp.m_position; m_text = dp.m_text; mToDelete = dp.mToDelete; mType = dp.mType; mAttribs = dp.mAttribs; mTaxType = dp.mTaxType; return *this; } void DocPositionBase::setAttribute( const Attribute& attrib ) { if( ! attrib.name().isEmpty() ) { mAttribs[ attrib.name() ] = attrib; } } AttributeMap DocPositionBase::attributes() { return mAttribs; } void DocPositionBase::setAttributeMap( AttributeMap attmap ) { mAttribs = attmap; } void DocPositionBase::loadAttributes() { if ( m_dbId == -1 ) { // qDebug () << "Can not load attributes, no valid database id!"; return; } mAttribs.load( m_dbId ); } void DocPositionBase::removeAttribute( const QString& name ) { if ( !name.isEmpty() ) mAttribs.markDelete( name ); } QString DocPositionBase::attribute( const QString& attName ) const { Attribute att = mAttribs[ attName ]; return att.value().toString(); } // The attribs tag contains a list of TagIDs separated by commas void DocPositionBase::setTag( const QString& tag ) { if ( tag.isEmpty() ) return; Attribute att; att.setPersistant(true); if ( mAttribs.contains( DocPosition::Tags ) ) { if ( hasTag( tag ) ) { return; } att = mAttribs[DocPosition::Tags]; } else { att = Attribute(DocPosition::Tags); } att.setListValue(true); // here: the attribute does not have the new tag. QStringList li = att.value().toStringList(); li.append(TagTemplateMan::self()->getTagTemplate(tag).dbId().toString()); att.setValue( QVariant(li) ); setAttribute( att ); } void DocPositionBase::replaceTags(const QStringList& newTags) { if (newTags.isEmpty()) { if (mAttribs.contains(DocPosition::Tags)) { removeAttribute(DocPosition::Tags); } return; } Attribute att = Attribute(DocPosition::Tags); att.setPersistant(true); att.setListValue(true); QStringList li; for( const QString& tag : newTags ) { li.append(TagTemplateMan::self()->getTagTemplate(tag).dbId().toString()); } att.setValue( QVariant(li) ); setAttribute( att ); } void DocPositionBase::removeTag( const QString& tag ) { if ( !hasTag( tag ) ) { return; } const QString tagId = TagTemplateMan::self()->getTagTemplate(tag).dbId().toString(); Attribute att = mAttribs[DocPosition::Tags]; QStringList li = att.value().toStringList(); li.removeAll( tagId ); att.setValue( QVariant( li ) ); setAttribute( att ); } bool DocPositionBase::hasTag( const QString& tag ) { const QString tagId = TagTemplateMan::self()->getTagTemplate(tag).dbId().toString(); if ( ! mAttribs.contains( DocPosition::Tags ) ) { return false; } Attribute att = mAttribs[DocPosition::Tags]; QStringList li = att.value().toStringList(); if( li.contains( tagId, Qt::CaseInsensitive ) && // ignore case !att.isMarkedDeleted() ) { return true; } return false; } QStringList DocPositionBase::tags() { QStringList tags, tagIDs; if ( mAttribs.hasAttribute(DocPosition::Tags) ) { // qDebug () << mAttribs[DocPosition::Tags].toString(); tagIDs = mAttribs[DocPosition::Tags].value().toStringList(); } for( const auto &tagId : tagIDs) { tags.append(TagTemplateMan::self()->getTagTemplateFromId(tagId).name()); } return tags; } DocPositionBase::TaxType DocPositionBase::taxType() { return mTaxType; } void DocPositionBase::setTaxType( TaxType tt ) { mTaxType = tt; } void DocPositionBase::setTaxType( int tt ) { mTaxType = (TaxType) tt; } int DocPositionBase::taxTypeNumeric() { if ( mTaxType == TaxNone ) return 1; else if ( mTaxType == TaxReduced ) return 2; else if ( mTaxType == TaxFull ) return 3; // qDebug () << "ERR: Vat-type ambigous!"; return 0; // Invalid } // ############################################################## const QString DocPosition::Kind( QString::fromLatin1( "kind" ) ); const QString DocPosition::Discount( QString::fromLatin1( "discount" ) ); const QString DocPosition::Tags( QString::fromLatin1( "tags" ) ); const QString DocPosition::ExtraDiscountTagRequired( QString::fromLatin1( "discountTagRequired" ) ); DocPosition::DocPosition(): DocPositionBase() ,m_amount( 1.0 ), mWidget( 0 ) { m_text = QString(); } DocPosition::DocPosition( const PositionType& t ) : DocPositionBase( t ), mWidget( 0 ) { } Geld DocPosition::overallPrice() { Geld g; AttributeMap atts = attributes(); // all kinds beside from no kind (which means Normal) mean that the position is not // counted for the overall price. // Once there are kinds different from Normal which need a counted price, this needs // to be fixed here. if (!atts.containsUndeleted(DocPosition::Kind) ) { g = unitPrice() * amount(); } return g; } // ############################################################## DocPositionList::DocPositionList() : QList() { // setAutoDelete( true ); } Geld DocPositionList::bruttoPrice(double fullTax, double reducedTax ) { Geld g = nettoPrice(); g += taxSum( fullTax, reducedTax ); return g; } Geld DocPositionList::nettoPrice() { Geld g; DocPositionListIterator it( *this ); while( it.hasNext() ) { DocPosition *dp = static_cast(it.next()); if (!dp->toDelete()) g += dp->overallPrice(); } return g; } Geld DocPositionList::fullTaxSum( double fullTax ) { Geld sum; if ( fullTax < 0 ) { qCritical() << "Full Tax is not loaded!"; } DocPositionListIterator it( *this ); while( it.hasNext() ) { DocPosition *dp = static_cast( it.next() ); if( !dp->toDelete() && dp->taxTypeNumeric() == DocPositionBase::TaxFull ) { sum += dp->overallPrice(); } } Geld tax; if( sum.toLong() > 0 ) { tax = sum.percent(fullTax); } return tax; } Geld DocPositionList::reducedTaxSum( double reducedTax ) { Geld sum; if ( reducedTax < 0 ) { qCritical() << "Reduced Tax is not loaded!"; } DocPositionListIterator it( *this ); while( it.hasNext() ) { DocPosition *dp = static_cast( it.next() ); if( !dp->toDelete() && dp->taxTypeNumeric() == DocPositionBase::TaxReduced ) { sum += dp->overallPrice(); } } Geld tax; if(sum.toLong() > 0 ) { tax = sum.percent(reducedTax); } return tax; } Geld DocPositionList::taxSum( double fullTax, double redTax ) { Geld sum; Geld fulltax = fullTaxSum(fullTax); Geld reducedtax = reducedTaxSum(redTax); sum += fulltax; sum += reducedtax; return sum; } QString DocPositionList::posNumber( DocPositionBase* pos ) { return QString::number( 1+indexOf( pos ) ); } #if 0 QDomElement DocPositionList::domElement( QDomDocument& doc ) { QDomElement topElem = doc.createElement( "positions" ); QDomElement posElem; int num = 1; DocPositionListIterator it( *this ); while( it.hasNext() ) { DocPosition *dpb = static_cast( it.next() ); if( dpb->type() == DocPositionBase::Position ) { DocPosition *dp = static_cast(dpb); posElem = doc.createElement( "position" ); posElem.setAttribute( "number", num++ ); topElem.appendChild( posElem ); posElem.appendChild( xmlTextElement( doc, "text", dp->text() ) ); double am = dp->amount(); QString h = QString::number(am, 'f', 2 ); posElem.appendChild( xmlTextElement( doc, "amount", h )); Einheit e = dp->unit(); posElem.appendChild( xmlTextElement( doc, "unit", e.einheit( am ) ) ); Geld g = dp->unitPrice(); posElem.appendChild( xmlTextElement( doc, "unitprice", QString::number(g.toDouble(), 'f', 2 ))); Geld sum(g * am); posElem.appendChild( xmlTextElement( doc, "sumprice", QString::number(sum.toDouble(), 'f', 2 ) ) ); } } return topElem; } #endif int DocPositionList::compareItems ( DocPosition *dp1, DocPosition *dp2 ) { //DocPositionBase *dpb1 = static_cast( item1 ); //DocPositionBase *dpb2 = static_cast( item2 ); int sortkey1 = dp1->positionNumber(); int sortkey2 = dp2->positionNumber(); int res = 0; if( sortkey1 > sortkey2 ) res = 1; if( sortkey2 < sortkey1 ) res = -1; // qDebug()<< "In sort: comparing " << p1 << " with " << p2 << " = " << res; return res; } QDomElement DocPositionList::xmlTextElement( QDomDocument& doc, const QString& name, const QString& value ) { QDomElement elem = doc.createElement( name ); QDomText t = doc.createTextNode( value ); elem.appendChild( t ); return elem; } DocPositionBase *DocPositionList::positionFromId( int id ) { DocPosition *dp = 0; DocPositionListIterator it( *this ); while( it.hasNext() ) { dp = static_cast( it.next() ); if( dp->dbId() == id ) { break; } } return dp; } kraft-1.1/src/docposition.h000066400000000000000000000111161450127457600157670ustar00rootroot00000000000000/*************************************************************************** docposition.h - a position in a document ------------------- begin : Fri Jan 20 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DOCPOSITION_H #define DOCPOSITION_H // include files for Qt #include #include #include // application specific includes #include "dbids.h" #include "calcpart.h" #include "attribute.h" #include "einheit.h" /** @author Klaas Freitag */ class QString; class QDomElement; class QDomDocument; class Geld; class dbID; class QLocale; class PositionViewWidget; class DocPositionBase : public QObject { public: enum PositionType { Position, ExtraDiscount }; enum TaxType { TaxInvalid = 0, TaxNone = 1, TaxReduced = 2, TaxFull = 3, TaxIndividual = 4 }; DocPositionBase(); DocPositionBase( const PositionType& ); ~DocPositionBase() {} DocPositionBase(const DocPositionBase&); void setDbId( int id ) { m_dbId = id; } dbID dbId() { return dbID( m_dbId ); } void setAttribute( const Attribute& ); void removeAttribute( const QString& ); void loadAttributes(); QString attribute(const QString& ) const; AttributeMap attributes(); void setAttributeMap( AttributeMap ); void setText( const QString& string ) { m_text = string; } QString text() const { return m_text; } void replaceTags(const QStringList& newTags); void setTag( const QString& ); void removeTag( const QString& ); bool hasTag( const QString& ); QStringList tags(); int taxTypeNumeric(); TaxType taxType(); void setTaxType( DocPositionBase::TaxType ); void setTaxType( int ); /** * Position means the number in the document */ int positionNumber() { return m_position; } void setPositionNumber( const int& pos ) { m_position = pos; } void setToDelete( bool doit ) { mToDelete = doit; } bool toDelete() { return mToDelete; } PositionType type() { return mType; } DocPositionBase& operator=( const DocPositionBase& ); protected: int m_dbId; int m_position; QString m_text; bool mToDelete; TaxType mTaxType; PositionType mType; AttributeMap mAttribs; }; class DocPosition : public DocPositionBase { public: DocPosition(); DocPosition( const PositionType& ); void setUnit( const Einheit& unit ) { m_unit = unit; } Einheit unit() const { return m_unit; } void setUnitPrice( const Geld& g ) { m_unitPrice = g; } Geld unitPrice() const { return m_unitPrice; } Geld overallPrice(); void setAmount( double amount ) { m_amount = amount; } double amount() { return m_amount; } PositionViewWidget* associatedWidget() { return mWidget; } void setAssociatedWidget( PositionViewWidget *w ) { mWidget = w; } static const QString Kind; static const QString Discount; static const QString Tags; static const QString ExtraDiscountTagRequired; private: Einheit m_unit; Geld m_unitPrice; double m_amount; PositionViewWidget *mWidget; // No calculation yet }; class DocPositionList : public QList { public: DocPositionList(); // QDomElement domElement( QDomDocument& ); DocPositionBase *positionFromId( int id ); QString posNumber( DocPositionBase* ); Geld nettoPrice(); Geld bruttoPrice( double fullTax, double reducedTax ); Geld taxSum(double fullTax, double redTax ); Geld fullTaxSum( double fullTax ); Geld reducedTaxSum( double reducedTax ); protected: int compareItems ( DocPosition *dp1, DocPosition *dp2 ); private: QDomElement xmlTextElement( QDomDocument&, const QString& , const QString& ); }; typedef QListIterator DocPositionListIterator; typedef QPointer DocPositionGuardedPtr; #endif kraft-1.1/src/docpostcard.cpp000066400000000000000000000266411450127457600163060ustar00rootroot00000000000000/*************************************************************************** DocPostCard - a postcard version of the document ------------------- begin : Aug 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "docpostcard.h" #include "kraftdoc.h" #include #include #include #include #include #define QL1(X) QLatin1String(X) DocPostCard::DocPostCard( QWidget *parent ) :HtmlView( parent ), mMode( Full ), mShowPrices(true) { setStylesheetFile( "docoverview.css" ); setTitle( i18n( "Document Overview" ) ); connect( this, SIGNAL(openUrl(QUrl)), this, SLOT(slotUrlSelected(QUrl)) ); } void DocPostCard::setHeaderData( const QString& type, const QString& date, const QString& address, const QString& id, const QString& pretext ) { mType = type; mDate = date; mAddress = address; mPreText = htmlify( pretext ); mId = id; } QString DocPostCard::htmlify( const QString& str ) const { QStringList li = str.toHtmlEscaped().split( "\n" ); return QL1("

            ") + li.join( "

            " ) + QL1("

            "); } #define REDUCED_TAX_MARK "²" #define NO_TAX_MARK "¹" void DocPostCard::setPositions( DocPositionList posList, DocPositionBase::TaxType taxType, double tax, double reducedTax ) { mPositions = "
            "; DocPositionListIterator it(posList); while( it.hasNext() ) { DocPositionBase *dpb = it.next(); DocPosition *dp = static_cast(dpb); mPositions += ""; mPositions += ""; if( mShowPrices ) { mPositions += ""; mPositions += ""; } mPositions += ""; } mPositions += "
            "; if ( dp->toDelete() ) mPositions += ""; mPositions += posList.posNumber( dpb ) + ". "; if ( dp->toDelete() ) mPositions += ""; mPositions += ""; if ( dp->toDelete() ) mPositions += ""; // set to italic if the item kind is not Normal bool italic = dp->attributes().containsUndeleted(DocPosition::Kind); if (italic) mPositions += ""; mPositions += htmlify(dp->text()); if (italic) mPositions += ""; if ( dp->toDelete() ) mPositions += ""; mPositions += ""; if (italic) mPositions += ""; if ( dp->toDelete() ) mPositions += ""; mPositions += dp->overallPrice().toHtmlString(); if ( dp->toDelete() ) mPositions += ""; mPositions += ""; if( taxType == DocPositionBase::TaxIndividual && (dp->taxType() == DocPositionBase::TaxReduced) ) { if ( dp->toDelete() ) mPositions += ""; mPositions += QString(REDUCED_TAX_MARK); if ( dp->toDelete() ) mPositions += ""; } if( taxType == DocPositionBase::TaxIndividual && (dp->taxType() == DocPositionBase::TaxNone) ) { if ( dp->toDelete() ) mPositions += ""; mPositions += QString(NO_TAX_MARK); if ( dp->toDelete() ) mPositions += ""; } if (italic) mPositions += ""; mPositions += "
            "; // Create the sum table mPositionCount = posList.count(); if( mShowPrices ) { mPositions += "
            "; mPositionCount = posList.count(); mTotal = posList.nettoPrice().toHtmlString(); QString brutto = posList.bruttoPrice( tax, reducedTax ).toHtmlString(); mPositions += QString( "" ); if ( taxType != DocPositionBase::TaxInvalid && taxType != DocPositionBase::TaxNone ) { mPositions += QString( "" ).arg( mTotal ); QString curTax; curTax.setNum( tax, 'f', 1 ); QString taxStr; if( taxType == DocPositionBase::TaxReduced || taxType == DocPositionBase::TaxIndividual ) { curTax.setNum( reducedTax, 'f', 1 ); taxStr = posList.reducedTaxSum( reducedTax ).toHtmlString(); mPositions += QString( "" ).arg( taxStr ).arg(REDUCED_TAX_MARK); } if( taxType == DocPositionBase::TaxFull || taxType == DocPositionBase::TaxIndividual ) { curTax.setNum( tax, 'f', 1 ); taxStr = posList.fullTaxSum( tax ).toHtmlString(); mPositions += QString( "" ).arg( taxStr ); } if( taxType == DocPositionBase::TaxIndividual ) { taxStr = posList.taxSum( tax, reducedTax ).toHtmlString(); mPositions += QString( "" ).arg( taxStr ); } } mPositions += QString( "" ).arg( brutto ); } // showPrices mPositions += "
            ______________________________
            " ) + i18n( "Netto:" )+ QString( "%1
            " ); mPositions += i18n( "+ %1% Tax:", curTax ) + QString( "%1%2
            " ) + i18n( "+ %1% Tax:", curTax ) + QString( "%1
            " ) + i18n( "Sum Tax:" ) + QString( "%1
            " ) + i18n( "Total:" )+ QString( "%1
            "; // qDebug() << "Positions-HTML: " << mPositions; } void DocPostCard::setFooterData( const QString& postText, const QString& goodbye ) { mPostText = htmlify( postText ); mGoodbye = goodbye; } void DocPostCard::renderDoc( int id ) { QString t; // qDebug() << "rendering postcard for active id " << id << //( mMode == Full ? " (full) " : " (mini) " ); if ( mMode == Full ) { t = renderDocFull( id ); } else if ( mMode == Mini ) { t = renderDocMini( id ); } else { // qDebug () << "Unknown postcard mode"; } // qDebug() << t; displayContent( t ); } #define SEL_STRING(X) ( id == X ? QL1("_selected"): QL1("")) QString DocPostCard::renderDocFull( int id ) { QString rethtml; QString t; rethtml = QL1( "" ); t += QL1(""); t += QString( "
            \n" ).arg( SEL_STRING(KraftDoc::Header) ); t += header( id == KraftDoc::Header, "headerlink", KraftDoc::partToString(KraftDoc::Header), "kraftdoc://header" ); QString h = mAddress; h.replace( '\n', "
            " ); t += ""; t += "
            "; t += QString( "%1\n" ).arg( h ); t += ""; t += QString( "%1
            %2\n" ).arg( mType ).arg( mDate ); t += "
            "; t += "

            " + mPreText + "

            \n"; t += "
            \n"; rethtml += t; // the Body section showing the positions t = QL1(""); t += QString( "
            \n" ).arg( SEL_STRING(KraftDoc::Positions ) ); t += header( id == KraftDoc::Positions, "bodylink", KraftDoc::partToString(KraftDoc::Positions), "kraftdoc://positions" ); t += mPositions; t += "\n
            \n"; rethtml += t; t = QL1(""); t += QString( "
            \n" ).arg( SEL_STRING(KraftDoc::Footer) ); t += header( id == KraftDoc::Footer, "footerlink", KraftDoc::partToString(KraftDoc::Footer), "kraftdoc://footer" ); t += "

            " + mPostText + "

            \n"; if ( ! mGoodbye.isEmpty() ) t += "

            " + mGoodbye + "

            \n"; t += "
            \n"; rethtml += t + ""; return rethtml; } QString DocPostCard::renderDocMini( int id ) const { QString t; QString rethtml = QL1( "" ); t = QString( "
            \n" ).arg( SEL_STRING(KraftDoc::Header) ); t += header( id == KraftDoc::Header, "headerlink", KraftDoc::partToString(KraftDoc::Header), "kraftdoc://header", QString( "%1, %2" ).arg( mType ).arg( mDate ) ); t += QL1("
            "); rethtml += t; t = QString( "
            \n" ).arg( SEL_STRING(KraftDoc::Positions)); QString d = i18n("%1 Items", mPositionCount); if( mShowPrices ) d = i18n("%1 Items, netto %2", mPositionCount, mTotal); // do not add another "Items" string to the header to not bloat t += header( id == KraftDoc::Positions, "bodylink", QString(), "kraftdoc://positions", d ); t += QL1("
            "); rethtml += t; t = QString( "
            \n" ).arg(SEL_STRING(KraftDoc::Footer)); t += header( id == KraftDoc::Footer, "footerlink", KraftDoc::partToString(KraftDoc::Footer), "kraftdoc://footer" ); t += QL1("
            "); rethtml += t; rethtml += QL1(""); return rethtml; } QString DocPostCard::header( bool selected, const QString& styleName, const QString& displayName, const QString& protocol, const QString& addons ) const { const QString content = QString("

            %2  %3

            ") .arg( styleName + (selected ? QL1("_selected") : QL1(""))) .arg(displayName).arg(addons); // These colors do the frame around the header boxes QString bgCol("#aaaaaa"); if( !selected ) bgCol = QL1("#cccccc"); return QString( "" "" "
            < a href=\"%2\">%3
            ").arg(bgCol).arg(protocol).arg(content); } void DocPostCard::slotUrlSelected( const QUrl& kurl) { KraftDoc::Part id = KraftDoc::Header; if ( kurl.scheme() == "kraftdoc" ) { if ( kurl.host() == "header" ) { // qDebug () << "Header selected!"; id = KraftDoc::Header; } else if ( kurl.host() == "positions" ) { // qDebug () << "Positions selected!"; id = KraftDoc::Positions; } else if ( kurl.host() == "footer" ) { // qDebug () << "Footer selected!"; id = KraftDoc::Footer; } emit selectPage( id ); } } void DocPostCard::slotSetMode( DisplayMode mode, int id ) { mMode = mode; renderDoc( id ); } void DocPostCard::slotShowPrices( bool showIt ) { mShowPrices = showIt; } kraft-1.1/src/docpostcard.h000066400000000000000000000043541450127457600157500ustar00rootroot00000000000000/*************************************************************************** DocPostCard - a postcard version of the document ------------------- begin : Aug 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DOCPOSTCARD_H #define DOCPOSTCARD_H #include #include "htmlview.h" #include "kraftdoc.h" class QUrl; class DocPostCard : public HtmlView { Q_OBJECT public: enum DisplayMode { Full, Mini }; DocPostCard( QWidget *parent = 0 ); signals: void selectPage( int ); public slots: void setHeaderData( const QString&, const QString&, const QString&, const QString&, const QString& ); void setPositions( DocPositionList, DocPositionBase::TaxType, double, double ); void setFooterData( const QString&, const QString& ); void renderDoc( int id = -1 ); void slotSetMode( DisplayMode, int id = -1 ); void slotShowPrices( bool showIt ); protected: QString renderDocMini( int ) const; QString renderDocFull( int ); QString header(bool, const QString&, const QString&, const QString& protocol, const QString& = QString() ) const; private slots: void slotUrlSelected( const QUrl& kurl); private: QString htmlify( const QString& ) const; DocGuardedPtr mDoc; QString mType; QString mId; QString mPreText; QString mPostText; QString mDate; QString mAddress; QString mPositions; QString mGoodbye; QString mTotal; int mPositionCount; DisplayMode mMode; bool mShowPrices; }; #endif kraft-1.1/src/doctext.cpp000066400000000000000000000051601450127457600154440ustar00rootroot00000000000000/*************************************************************************** doctext.cpp - texts like header or footer for documents ------------------- begin : March 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include "doctext.h" DocText::DocText() : mTextType( KraftDoc::Unknown ), mCurrentItem( 0 ) { } void DocText::setName( const QString& t ) { mName = t; } void DocText::setText( const QString& t ) { mText = t; } void DocText::setDescription( const QString& t ) { mDescription = t; } void DocText::setDocType( const QString& t ) { mDocType = t; } void DocText::setTextType( KraftDoc::Part t ) { mTextType = t; } bool DocText::isStandardText() const { return QString::compare(mName, i18n( "Standard" ), Qt::CaseInsensitive) == 0; // can surely be improved... } KraftDoc::Part DocText::stringToTextType( const QString& str ) { KraftDoc::Part tt = KraftDoc::Unknown; if ( str == textTypeToString( KraftDoc::Header ) ) tt = KraftDoc::Header; if ( str == textTypeToString( KraftDoc::Footer ) ) tt = KraftDoc::Footer; if ( str == textTypeToString( KraftDoc::Positions ) ) tt = KraftDoc::Positions; return tt; } QString DocText::textTypeToString( KraftDoc::Part tt ) { if ( tt == KraftDoc::Header ) return i18n( "Header Text" ); if ( tt == KraftDoc::Footer ) return i18n( "Footer Text" ); if ( tt == KraftDoc::Positions ) return i18n( "Items" ); return i18n( "Unknown" ); } bool DocText::operator==( const DocText& _dt ) const { return ( ( mName == _dt.mName ) && ( mDocType == _dt.mDocType ) && ( mTextType == _dt.mTextType ) ); } void DocText::setDbId( long id ) { mDbId = id ; } void DocText::setDbId( const dbID& id ) { mDbId = id ; } dbID DocText::dbId() const { return mDbId; } kraft-1.1/src/doctext.h000066400000000000000000000046101450127457600151100ustar00rootroot00000000000000/*************************************************************************** doctext.h - texts like header or footer for documents ------------------- begin : March 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DOCTEXT_H #define DOCTEXT_H #include #include "kraftcat_export.h" #include "kraftdoc.h" #include "dbids.h" class QTreeWidgetItem; class QPixmap; class KRAFTCAT_EXPORT DocText { public: DocText(); QString name() const { return mName; } void setName( const QString& ); QString text() const { return mText; } void setText( const QString& ); QString description() const { return mDescription; } void setDescription( const QString& ); KraftDoc::Part type() { return mTextType; } QString textTypeString() const { return textTypeToString( mTextType ); } bool isStandardText() const; void setTextType( KraftDoc::Part ); KraftDoc::Part textType() const { return mTextType; } QString docType() const { return mDocType; } void setDocType( const QString& ); QTreeWidgetItem *listViewItem() const { return mCurrentItem; } void setListViewItem( QTreeWidgetItem *item ) { mCurrentItem = item; } void setDbId( long ); void setDbId( const dbID& ); dbID dbId() const; static KraftDoc::Part stringToTextType( const QString& ); static QString textTypeToString( KraftDoc::Part ); bool operator==( const DocText& ) const; private: QString mName; QString mText; QString mDescription; QString mDocType; KraftDoc::Part mTextType; QTreeWidgetItem *mCurrentItem; dbID mDbId; }; typedef QList DocTextList; #endif kraft-1.1/src/doctype.cpp000066400000000000000000000451021450127457600154410ustar00rootroot00000000000000/*************************************************************************** doctype.cpp - doc type class ------------------- begin : Oct. 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include // application specific includes #include "doctype.h" #include "kraftdb.h" #include "numbercycle.h" #include "attribute.h" #include "defaultprovider.h" #include "stringutil.h" /** @author Klaas Freitag */ namespace { const QString XRechnungTmplStr {"XRechnungTmpl"}; const QString WatermarkFileStr {"watermarkFile"}; const QString DocTemplateFileStr {"docTemplateFile"}; const QString IdentNumberCycleStr{"identNumberCycle"}; const QString DocMergeIdentStr {"docMergeIdent"}; const QString DayCounterDateStr {"dayCounterDate"}; const QString DayCounterStr {"dayCounter"}; const QString AppendPDFStr {"AppendPDFFile"}; const QString DefaultTmplFileName {"invoice.trml"}; } idMap DocType::mNameMap = idMap(); DocType::DocType() : mAttributes( QStringLiteral( "DocType" ) ), mDirty( false ) { init(); } DocType::DocType( const QString& name, bool dirty ) : mAttributes( QStringLiteral( "DocType" ) ), mName( name ), mDirty( dirty ) { init(); if ( mNameMap.contains( name ) ) { dbID id = mNameMap[ name ]; mAttributes.load( id ); } readFollowerList(); readIdentTemplate(); } void DocType::init() { // === Start to fill static content if ( ! mNameMap.empty() ) return; QSqlQuery q; q.prepare( "SELECT docTypeID, name FROM DocTypes ORDER BY name" ); q.exec(); while ( q.next() ) { dbID id( q.value(0).toInt() ); QString name = q.value(1).toString(); mNameMap[ name ] = id; // QString h = DefaultProvider::self()->locale()->translate( cur.value( "name" ).toString() ); } } void DocType::clearMap() { mNameMap.clear(); } QStringList DocType::all() { init(); QStringList re; QSqlQuery q; q.prepare( "SELECT docTypeID, name FROM DocTypes ORDER BY name" ); q.exec(); while ( q.next() ) { re << q.value(1).toString(); } return re; } QStringList DocType::allLocalised() { return all(); } // static function to retrieve id of a certain doctype dbID DocType::docTypeId( const QString& docType ) { dbID id; init(); if ( mNameMap.contains( docType ) ) { id = mNameMap[ docType ]; return id; } else { qCritical()<< "Can not find id for doctype named " << docType; } return id; } bool DocType::allowDemand() { bool re = false; if ( mAttributes.contains( "AllowDemand" ) ) { re = true; } return re; } bool DocType::allowAlternative() { bool re = false; if ( mAttributes.contains( "AllowAlternative" ) ) { re = true; } return re; } bool DocType::pricesVisible() { bool re = true; if( mAttributes.contains("HidePrices")) { re = false; } return re; } bool DocType::substractPartialInvoice() { bool re = false; if( mAttributes.contains("SubstractPartialInvoice")) { re = true; } return re; } bool DocType::partialInvoice() { bool re = false; if( mAttributes.contains("PartialInvoice")) { re = true; } return re; } // returns the amount of followers added int DocType::setAllFollowers( const QStringList& followers) { QSqlQuery q; q.prepare("INSERT INTO DocTypeRelations (typeId, followerId, sequence) VALUES (:typeId, :followerId, 0)"); QSqlQuery qu; qu.prepare("UPDATE DocTypeRelations SET sequence=:seq WHERE typeId=:typeId AND followerId=:followerId"); // get "my" doc type Id int typeId = mNameMap[mName].toInt(); q.bindValue(":typeId", typeId); qu.bindValue(":typeId", typeId); // get the max sequence for me int seq = 0; { QSqlQuery cq; cq.prepare("SELECT MAX(sequence) FROM DocTypeRelations WHERE typeId=:tdId"); cq.bindValue(":tdId", typeId); cq.exec(); if( cq.next() ) { seq = cq.value(0).toInt(); } } const QStringList existingFollowers = follower(); int cnt = 0; // simple counter to return. for( const QString& f : followers ) { if( mNameMap.contains(f) ) { int followerId = mNameMap[f].toInt(); if( !existingFollowers.contains(f) ) { q.bindValue(":followerId", followerId ); q.exec(); cnt++; } // use the updater qu.bindValue(":seq", ++seq); qu.bindValue(":followerId", followerId); qu.exec(); } } return cnt; } QStringList DocType::follower() { return mFollowerList; } void DocType::readFollowerList() { QSqlQuery q; q.prepare( "SELECT typeId, followerId, sequence FROM DocTypeRelations WHERE typeId=:type ORDER BY sequence"); q.bindValue( ":type", mNameMap[mName].toInt() ); q.exec(); while ( q.next() ) { dbID followerId( q.value(1).toInt() ); idMap::Iterator it; for ( it = mNameMap.begin(); it != mNameMap.end(); ++it ) { if ( it.value() == followerId ) { mFollowerList << it.key(); } } } } QString DocType::numberCycleName() { QString re = NumberCycle::defaultName(); if ( mAttributes.hasAttribute(IdentNumberCycleStr) ) { re = mAttributes[IdentNumberCycleStr].value().toString(); } return re; } void DocType::setNumberCycleName( const QString& name ) { if ( name.isEmpty() ) return; if ( name != NumberCycle::defaultName() ) { Attribute att(IdentNumberCycleStr); att.setPersistant( true ); att.setValue( name ); mAttributes[IdentNumberCycleStr] = att; } else { // remove default value from map mAttributes.markDelete(IdentNumberCycleStr); // qDebug () << "Removing identNumberCycle Attribute"; } mDirty = true; readIdentTemplate(); } /* This method looks for the template file for the doctype. The rule is: * 1. Set the filename to look for to the name of the doc type, lowercase * and with spaces replaced * 2. Check for an attribute for this doc type. * - if that is an absolute path, return it. * - if not absolute, set the filename to look for to that value * 3. Look for the name in KRAFT_HOME * 4. Look for the name in rel. system Path * 5. Look for the name in QStandardPaths * 6. If still empty, fall back to default invoice.trml - which also * sets ReportLab as default */ QString DocType::templateFile() { QString tmplFile; const auto dfp = DefaultProvider::self(); QString searchStr; QString reportFileName = QString( "%1.trml").arg( name().toLower() ); reportFileName.replace(QChar(' '), QChar('_')); if ( mAttributes.hasAttribute(DocTemplateFileStr) ) { tmplFile = mAttributes[DocTemplateFileStr].value().toString(); qDebug() << "Template File:" << tmplFile; if( !tmplFile.isEmpty() ) { QFileInfo fi(tmplFile); if( fi.isAbsolute() ) { return tmplFile; } else { // it is not an absolute file name, try to find it reportFileName = tmplFile; } tmplFile.clear(); } } // check for reportlab template if (tmplFile.isEmpty()) { searchStr = QString("reports/%1.trml").arg(reportFileName); tmplFile = dfp->locateFile(searchStr); } // check for weasyprint template if (tmplFile.isEmpty()) { searchStr = QString("reports/%1.gtmpl").arg(reportFileName); tmplFile = dfp->locateFile(searchStr); } // not found - check invoice.trml if (tmplFile.isEmpty()) { searchStr = QString("reports/%1").arg(DefaultTmplFileName); tmplFile = dfp->locateFile(searchStr); } if( tmplFile.isEmpty() ) { qDebug () << "unable to find a template file for " << name(); } else { qDebug () << "Found template file " << tmplFile; } return tmplFile; } void DocType::setTemplateFile( const QString& name ) { if ( name.isEmpty() || name == DefaultTmplFileName) { // the default is returned anyway. // remove default value from map mAttributes.markDelete(DocTemplateFileStr); // qDebug () << "Removing docTemplateFile Attribute"; } else { Attribute att(DocTemplateFileStr); att.setPersistant( true ); att.setValue( name ); mAttributes[DocTemplateFileStr] = att; } mDirty = true; } QString DocType::mergeIdent() { QString re = "0"; if ( mAttributes.hasAttribute(DocMergeIdentStr) ) { re = mAttributes[DocMergeIdentStr].value().toString(); } return re; } void DocType::setMergeIdent( const QString& ident ) { if ( !ident.isEmpty() ) { Attribute att(DocMergeIdentStr); att.setPersistant( true ); att.setValue( ident ); mAttributes[DocMergeIdentStr] = att; } else { // remove default value from map mAttributes.markDelete(DocMergeIdentStr); // qDebug () << "Removing docMergeIdent Attribute"; } mDirty = true; } QString DocType::xRechnungTemplate() { return attributeValueString(XRechnungTmplStr); } void DocType::setXRechnungTemplate(const QString& tmpl) { setAttribute(XRechnungTmplStr, tmpl); } QString DocType::attributeValueString(const QString& attribName) const { QString re; if (attribName.isEmpty()) { return re; } if (mAttributes.hasAttribute(attribName)) { const auto att = mAttributes.value(attribName); re = att.value().toString(); } return re; } void DocType::setAttribute( const QString& attribute, const QString& val) { if ( !(attribute.isEmpty() || val.isEmpty()) ) { Attribute att( attribute ); att.setPersistant( true ); att.setValue( val); mAttributes[attribute] = att; mDirty = true; } // remove empty attribute if (!attribute.isEmpty() && val.isEmpty()) { mAttributes.markDelete(attribute); mDirty = true; } } QString DocType::watermarkFile() { QString re; if ( mAttributes.hasAttribute( WatermarkFileStr ) ) { re = mAttributes[WatermarkFileStr].value().toString(); } return re; } void DocType::setWatermarkFile( const QString& file ) { if ( !file.isEmpty() ) { Attribute att( WatermarkFileStr ); att.setPersistant( true ); att.setValue( file ); mAttributes[WatermarkFileStr] = att; } else { // remove default value from map mAttributes.markDelete( WatermarkFileStr ); // qDebug () << "Removing docMergeFile Attribute"; } mDirty = true; } QString DocType::appendPDF() const { return attributeValueString(AppendPDFStr); } void DocType::setAppendPDFFile(const QString& file) { setAttribute(AppendPDFStr, file); } /** * @brief DocType::generateDocumentIdent * @param docDate * @param addressUid * @param id: Current Id to be used. * @param dayCnt: Current day counter to be used. * @return */ QString DocType::generateDocumentIdent(const QDate& docDate, const QString& addressUid, int id, int dayCnt) { /* * The pattern may contain the following tags: * %y - the year of the documents date. * %w - the week number of the documents date * %d - the day number of the documents date * %m - the month number of the documents date * %M - the month number of the documents date * %c - the customer id from kaddressbook * %i - the uniq identifier from db. * %n - the uniq identifier that resets every day and starts from 1 * %type - the localised doc type (offer, invoice etc.) * %uid - the customer uid */ // Load the template and check if there is a uniq id included. QString pattern = identTemplate(); if ( pattern.indexOf( "%i" ) == -1 && pattern.indexOf("%n") == -1) { qWarning() << "No %i found in identTemplate, appending it to meet law needs!"; if (!pattern.endsWith('-')) pattern += QStringLiteral("-"); pattern += QStringLiteral("%i"); } QMap m; m[ "%yyyy" ] = docDate.toString( "yyyy" ); m[ "%yy" ] = docDate.toString( "yy" ); m[ "%y" ] = docDate.toString( "yyyy" ); QString h; h = QString("%1").arg( docDate.weekNumber(), 2, 10, QChar('0') ); m[ "%ww" ] = h; m[ "%w" ] = QString::number( docDate.weekNumber( ) ); m[ "%dd" ] = docDate.toString( "dd" ); m[ "%d" ] = docDate.toString( "d" ); m[ "%m" ] = QString::number( docDate.month() ); m[ "%MM" ] = docDate.toString( "MM" ); m[ "%M" ] = docDate.toString( "M" ); h = QString("%1").arg(id, 6, 10, QChar('0') ); m[ "%iiiiii" ] = h; h = QString("%1").arg(id, 5, 10, QChar('0') ); m[ "%iiiii" ] = h; h = QString("%1").arg(id, 4, 10, QChar('0') ); m[ "%iiii" ] = h; h = QString("%1").arg(id, 3, 10, QChar('0') ); m[ "%iii" ] = h; h = QString("%1").arg(id, 2, 10, QChar('0') ); m[ "%ii" ] = h; m[ "%i" ] = QString::number( id ); h = QString("%1").arg(dayCnt, 6, 10, QChar('0') ); m[ "%nnnnnn" ] = h; h = QString("%1").arg(dayCnt, 5, 10, QChar('0') ); m[ "%nnnnn" ] = h; h = QString("%1").arg(dayCnt, 4, 10, QChar('0') ); m[ "%nnnn" ] = h; h = QString("%1").arg(dayCnt, 3, 10, QChar('0') ); m[ "%nnn" ] = h; h = QString("%1").arg(dayCnt, 2, 10, QChar('0') ); m[ "%nn" ] = h; m[ "%n" ] = QString::number(dayCnt); m[ "%c" ] = addressUid; m[ "%type" ] = name(); m[ "%uid" ] = addressUid; QString re = StringUtil::replaceTagsInString( pattern, m ); // qDebug () << "Generated document ident: " << re; return re; } // if hot, the id is updated in the database, otherwise not. int DocType::nextIdentId( bool hot ) { QString numberCycle = numberCycleName(); if ( numberCycle.isEmpty() ) { qCritical() << "NumberCycle name is empty"; return -1; } QSqlQuery qLock; if ( hot ) { qLock.exec( "LOCK TABLES numberCycles WRITE" ); } QSqlQuery q; q.prepare( "SELECT lastIdentNumber FROM numberCycles WHERE name=:name" ); int num = -1; q.bindValue( ":name", numberCycle ); q.exec(); if ( q.next() ) { num = 1+( q.value( 0 ).toInt() ); // qDebug () << "Got current number: " << num; if ( hot ) { QSqlQuery setQuery; setQuery.prepare( "UPDATE numberCycles SET lastIdentNumber=:newNumber WHERE name=:name" ); setQuery.bindValue( ":name", numberCycle ); setQuery.bindValue( ":newNumber", num ); setQuery.exec(); if ( setQuery.isActive() ) { // qDebug () << "Successfully created new id number for numbercycle " << numberCycle << ": " << num; } } } if ( hot ) { qLock.exec( "UNLOCK TABLES" ); } return num; } int DocType::nextDayCounter(const QDate& docDate) { int dayCnt {0}; // Check the attribute for the day counter. QDate storedDate = mAttributes[DayCounterDateStr].value().toDate(); // increment the day counter by one dayCnt = 1+mAttributes[DayCounterStr].value().toInt(); if (storedDate != docDate) { // the daycounter is outdated. Reset the counter and update the date. setAttribute(DayCounterDateStr, docDate.toString(Qt::ISODate)); dayCnt = 1; } setAttribute(DayCounterStr, QString::number(dayCnt)); save(); return dayCnt; } QString DocType::identTemplate() { return mIdentTemplate; } void DocType::setIdentTemplate( const QString& t ) { mIdentTemplate = t; } void DocType::readIdentTemplate() { QSqlQuery q; QString tmpl; const QString defaultTempl = QString::fromLatin1( "%y%ww-%i" ); QString numberCycle = numberCycleName(); if ( numberCycle.isEmpty() ) { qCritical() << "Numbercycle for doctype is empty, returning default"; mIdentTemplate = defaultTempl; } // qDebug () << "Picking ident Template for numberCycle " << numberCycle; q.prepare( "SELECT identTemplate FROM numberCycles WHERE name=:name" ); q.bindValue( ":name", numberCycle ); q.exec(); if ( q.next() ) { tmpl = q.value( 0 ).toString(); // qDebug () << "Read ident template from database: " << tmpl; } // FIXME: Check again. if ( tmpl.isEmpty() ) { // qDebug () << "Writing ident template to database: " << pattern; QSqlQuery insQuery; insQuery.prepare( "UPDATE numberCycles SET identTemplate=:pattern WHERE name=:name" ); insQuery.bindValue( ":name", numberCycle ); insQuery.bindValue( ":pattern", defaultTempl); insQuery.exec(); tmpl = defaultTempl; } mIdentTemplate = tmpl; } QString DocType::name() const { return mName; } void DocType::setName( const QString& name ) { QString oldName = mName; dbID id = mNameMap[ oldName ]; // The old id. mNameMap[ name ] = id; mNameMap.remove( oldName ); mName = name; mDirty = true; } /* * Saves the name and the attriutes (numbercycle, demand, etc.) */ void DocType::save() { if ( !mDirty ) { // qDebug () << "Saving: not DIRTY!"; return; } if ( !mNameMap.contains( mName ) ) { qCritical() << "nameMap does not contain id for " << mName; return; } dbID id = mNameMap[ mName ]; QSqlQuery q; bool doInsert = false; if ( id.isOk() ) { q.prepare( "UPDATE DocTypes SET name=:name WHERE docTypeId=:id" ); q.bindValue( ":id", id.toInt() ); } else { q.prepare( "INSERT INTO DocTypes (name) VALUES (:name)" ); doInsert = true; } q.bindValue( ":name", mName ); q.exec(); if ( doInsert ) { mNameMap[mName] = KraftDB::self()->getLastInsertID(); } mAttributes.save( mNameMap[mName] ); } kraft-1.1/src/doctype.h000066400000000000000000000061501450127457600151060ustar00rootroot00000000000000/*************************************************************************** doctype.h - doc type class ------------------- begin : Oct. 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DOCTYPE_H #define DOCTYPE_H // include files for Qt #include #include #include "kraftcat_export.h" #include "dbids.h" #include "attribute.h" /** @author Klaas Freitag */ typedef QMap idMap; class KRAFTCAT_EXPORT DocType { public: DocType(); /** * create a doctype from its localised or tech name */ DocType( const QString&, bool dirty = false ); static QStringList all(); static QStringList allLocalised(); static dbID docTypeId( const QString& ); QString name() const; void setName( const QString& ); bool allowDemand(); bool allowAlternative(); bool pricesVisible(); bool partialInvoice(); bool substractPartialInvoice(); QStringList follower(); int setAllFollowers( const QStringList& followers); QString generateDocumentIdent(const QDate& docDate, const QString& addressUid, int id, int dayCnt); QString identTemplate(); void setIdentTemplate( const QString& ); QString numberCycleName(); void setNumberCycleName( const QString& ); QString templateFile(); void setTemplateFile( const QString& ); QString watermarkFile(); void setWatermarkFile( const QString& ); QString mergeIdent(); void setMergeIdent( const QString& ); QString xRechnungTemplate(); void setXRechnungTemplate(const QString&); QString appendPDF() const; void setAppendPDFFile(const QString& file); void setAttribute( const QString& attribute, const QString& val); QString attributeValueString(const QString& attribName) const; static void clearMap(); int nextIdentId( bool hot = true ); int nextDayCounter(const QDate& docDate); void save(); void readIdentTemplate(); protected: void readFollowerList(); private: static void init(); private: AttributeMap mAttributes; QStringList mFollowerList; QString mName; QString mIdentTemplate; bool mDirty; QString mMergeIdent; static idMap mNameMap; }; #endif kraft-1.1/src/doctypeedit.cpp000066400000000000000000000435161450127457600163160ustar00rootroot00000000000000/*************************************************************************** doctypeedit.h - the document type editor ------------------- begin : Fri Jan 2 2009 copyright : (C) 2009 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "prefsdialog.h" #include "kraftsettings.h" #include "kraftdb.h" #include "kraftdoc.h" #include "defaultprovider.h" #include "doctype.h" #include "doctypeedit.h" #include "numbercycledialog.h" // -------------------------------------------------------------------------------- DocTypeEdit::DocTypeEdit( QWidget *parent ) : QWidget(parent), Ui::DocTypeEditBase( ), mExampleDocType(i18n("")), mExampleAddressUid(i18n("
            ")) { setupUi( this ); connect( mTypeListBox, SIGNAL( currentTextChanged( const QString& ) ), this, SLOT( slotDocTypeSelected( const QString& ) ) ); QStringList types = DocType::allLocalised(); mTypeListBox->clear(); mTypeListBox->addItems( types ); for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) { DocType dt( *it ); mOrigDocTypes[*it] = dt; } mTypeListBox->setCurrentRow( 0, QItemSelectionModel::Select ); QString dtype; if(mTypeListBox->currentRow() != -1) dtype = mTypeListBox->currentItem()->text(); mPbAdd->setIcon( DefaultProvider::self()->icon( "plus" ) ); mPbEdit->setIcon( DefaultProvider::self()->icon( "pencil" ) ); mPbRemove->setIcon( DefaultProvider::self()->icon( "minus" ) ); const QIcon& icon = DefaultProvider::self()->icon("device-floppy"); if (!icon.isNull() ) { tmplFileSelectButton->setIcon(icon); tmplFileSelectButton->setText(""); watermarkSelectButton->setIcon(icon); watermarkSelectButton->setText(""); appendSelectButton->setIcon(icon); appendSelectButton->setText(""); } tmplFileSelectButton->setToolTip(i18n("Select template file from harddisk")); watermarkSelectButton->setToolTip(i18n("Select watermark file from harddisk")); appendSelectButton->setToolTip(i18n("Select PDF file to append to documents from harddisk")); connect(tmplFileSelectButton, &QPushButton::clicked, this, [this]() { QString file = QFileDialog::getOpenFileName(this, i18n("Find Template File"), QDir::homePath(), i18n("Kraft Templates (*.trml *.gtmpl)")); if (!file.isEmpty()) { mTemplateUrl->setText(file); } }); connect(watermarkSelectButton, &QPushButton::clicked, this, [this]() { QString file = QFileDialog::getOpenFileName(this, i18n("Find Watermark File"), QDir::homePath(), i18n("PDF file (*.pdf)")); if (!file.isEmpty()) { mWatermarkUrl->setText(file); } }); connect(appendSelectButton, &QPushButton::clicked, this, [this]() { QString file = QFileDialog::getOpenFileName(this, i18n("Find Append PDF File"), QDir::homePath(), i18n("PDF file (*.pdf)")); if (!file.isEmpty()) { mAppendUrl->setText(file); } }); connect( mPbAdd, SIGNAL( clicked() ), SLOT( slotAddDocType() ) ); connect( mPbEdit, SIGNAL( clicked() ), SLOT( slotEditDocType() ) ); connect( mPbRemove, SIGNAL( clicked() ), SLOT( slotRemoveDocType() ) ); connect( mNumberCycleCombo, SIGNAL( activated( const QString& ) ), SLOT( slotNumberCycleChanged( const QString& ) ) ); connect( mPbEditCycles, SIGNAL( clicked() ), SLOT( slotEditNumberCycles() ) ); connect( mWatermarkCombo, SIGNAL( activated( int ) ), SLOT( slotWatermarkModeChanged( int ) ) ); connect( mWatermarkUrl, SIGNAL( textChanged( const QString& ) ), SLOT( slotWatermarkUrlChanged( const QString& ) ) ); connect( mTemplateUrl, SIGNAL( textChanged( const QString& ) ), SLOT( slotTemplateUrlChanged( const QString& ) ) ); connect( mAppendUrl, &QLineEdit::textChanged, this, &DocTypeEdit::slotAppendPDFUrlChanged ); fillNumberCycleCombo(); DocType dt( dtype ); mNumberCycleCombo->setCurrentIndex(mNumberCycleCombo->findText( dt.numberCycleName() )); int newMode = dt.mergeIdent().toInt(); mWatermarkCombo->setCurrentIndex( newMode ); bool state = true; if ( newMode == 0 ) state = false; mWatermarkUrl->setEnabled( state ); } void DocTypeEdit::fillNumberCycleCombo() { QSqlQuery q; q.prepare( "SELECT name FROM numberCycles ORDER BY name" ); q.exec(); QStringList cycles; while ( q.next() ) { cycles << q.value( 0 ).toString(); } mNumberCycleCombo->clear(); mNumberCycleCombo->insertItems(-1, cycles ); } void DocTypeEdit::slotAddDocType() { // qDebug () << "Adding a doctype!"; QString newName = QInputDialog::getText( this, i18n( "Add Document Type" ), i18n( "Enter the name of a new document type" ) ); if ( newName.isEmpty() ) return; // qDebug () << "New Name to add: " << newName; if ( mTypeListBox->findItems(newName, Qt::MatchExactly).count() > 0 ) { // qDebug () << "New Name already exists"; } else { mTypeListBox->addItem( newName ); DocType newDt( newName, true ); mOrigDocTypes[newName] = newDt; mChangedDocTypes[newName] = newDt; // Check again! mAddedTypes.append( newName ); } } void DocTypeEdit::slotEditDocType() { // qDebug () << "Editing a doctype!"; QString currName = mTypeListBox->currentItem()->text(); if ( currName.isEmpty() ) return; QString newName = QInputDialog::getText( this, i18n( "Add Document Type" ), i18n( "Edit the name of a document type" ), QLineEdit::Normal, currName ); if ( newName.isEmpty() ) return; // qDebug () << "edit: " << currName << " became " << newName; if ( newName != currName ) { mTypeListBox->currentItem()->setText(newName); /* check if the word that was changed now was already changed before. */ bool prechanged = false; bool skipEntry = false; QMap::Iterator it; for ( it = mTypeNameChanges.begin(); !prechanged && it != mTypeNameChanges.end(); ++it ) { if (it.key() == currName ) { // it was changed back to an original name. mTypeNameChanges.erase( it ); skipEntry = true; } if ( !skipEntry && it.value() == currName ) { // qDebug () << "Was changed before, key is " << it.key(); currName = it.key(); prechanged = true; } } if ( ! skipEntry ) { mTypeNameChanges[currName] = newName; DocType dt( currName ); if ( mChangedDocTypes.contains( currName ) ) { dt = mChangedDocTypes[currName]; } dt.setName( newName ); mChangedDocTypes[newName] = dt; } } } void DocTypeEdit::slotRemoveDocType() { // qDebug () << "Removing a doctype!"; QListWidgetItem *currItem = mTypeListBox->currentItem(); if ( !currItem || currItem->text().isEmpty() ) { // qDebug () << "No current Item, return"; return; } QString currName = currItem->text(); if ( mAddedTypes.indexOf( currName ) != -1 ) { // remove item from recently added list. mChangedDocTypes.remove( currName ); mAddedTypes.removeAll( currName ); mOrigDocTypes.remove( currName ); } else { QString toRemove = currName; QMap::Iterator it; for ( it = mTypeNameChanges.begin(); it != mTypeNameChanges.end(); ++it ) { if ( currName == it.value() ) { // remove the original name toRemove = it.key(); // the original name } } mRemovedTypes.append( toRemove ); } delete currItem; // qDebug () << "removed type: " << mRemovedTypes; emit removedType( currName ); } void DocTypeEdit::slotDocTypeSelected( const QString& newValue ) { // qDebug () << "docTypeSelected: " << newValue << " and previous: " << mPreviousType; DocType dt( newValue ); if ( mChangedDocTypes.contains( newValue ) ) { dt = mChangedDocTypes[newValue]; // qDebug () << "new docType taken from ChangedDocTypes: "; } // store the previous type DocType prevType = mOrigDocTypes[mPreviousType]; if ( mChangedDocTypes.contains( mPreviousType ) ) { prevType = mChangedDocTypes[mPreviousType]; // qDebug () << "previous docType taken from ChangedDocTypes: "; } prevType.setNumberCycleName( mNumberCycleCombo->currentText() ); prevType.setTemplateFile( mTemplateUrl->text() ); prevType.setWatermarkFile( mWatermarkUrl->text() ); prevType.setAppendPDFFile(mAppendUrl->text()); prevType.setMergeIdent( QString::number( mWatermarkCombo->currentIndex() ) ); mChangedDocTypes[mPreviousType] = prevType; // dt.setNumberCycleName( dt.numberCycleName() ); // qDebug () << "Selected doc type " << newValue; mIdent->setText( dt.identTemplate() ); int nextNum = dt.nextIdentId( false )-1; mCounter->setText( QString::number( nextNum ) ); mNumberCycleCombo->setCurrentIndex(mNumberCycleCombo->findText( dt.numberCycleName() )); // mHeader->setText( i18n( "Details for %1:", dt.name() ) ); mExampleId->setText( dt.generateDocumentIdent( QDate::currentDate(), mExampleAddressUid, nextNum, 2 /* phantasie date counter */) ); mTemplateUrl->setText( dt.templateFile() ); mWatermarkUrl->setText( dt.watermarkFile() ); int mergeIdent = dt.mergeIdent().toInt(); mWatermarkCombo->setCurrentIndex( mergeIdent ); mWatermarkUrl->setEnabled( mergeIdent > 0 ); mAppendUrl->setText(dt.appendPDF()); mPreviousType = newValue; } void DocTypeEdit::slotEditNumberCycles() { saveDocTypes(); QString currNumbercycle = mNumberCycleCombo->currentText(); NumberCycleDialog dia( this, currNumbercycle ); if ( dia.exec() == QDialog::Accepted ) { fillNumberCycleCombo(); mNumberCycleCombo->setCurrentIndex(mNumberCycleCombo->findText( currNumbercycle )); DocType dt = currentDocType(); dt.readIdentTemplate(); // only the numbercycle has changed - refresh the display mIdent->setText( dt.identTemplate() ); int nextNum = dt.nextIdentId( false )-1; mCounter->setText( QString::number( nextNum ) ); mExampleId->setText( dt.generateDocumentIdent( QDate::currentDate(), mExampleAddressUid, nextNum, 2 ) ); } } DocType DocTypeEdit::currentDocType() { QString docType = mTypeListBox->currentItem()->text(); DocType dt = mOrigDocTypes[docType]; if ( mChangedDocTypes.contains( docType ) ) { dt = mChangedDocTypes[docType]; } return dt; } void DocTypeEdit::slotWatermarkModeChanged( int newMode ) { DocType dt = currentDocType(); QString newMergeIdent = QString::number( newMode ); if ( newMergeIdent != dt.mergeIdent() ) { dt.setMergeIdent( newMergeIdent ); if ( !mTypeListBox->currentItem()->text().isEmpty() ) { mChangedDocTypes[ mTypeListBox->currentItem()->text() ] = dt; } } bool state = true; if ( newMode == 0 ) state = false; mWatermarkUrl->setEnabled( state ); } void DocTypeEdit::slotAppendPDFUrlChanged(const QString& newUrl) { QString docType; if(mTypeListBox->currentRow() != -1) docType = mTypeListBox->currentItem()->text(); if( docType.isEmpty() || ! mOrigDocTypes.contains(docType) ) return; DocType dt = mOrigDocTypes[docType]; if ( mChangedDocTypes.contains( docType ) ) { dt = mChangedDocTypes[docType]; } if ( newUrl != dt.appendPDF() ) { dt.setAppendPDFFile(newUrl); mChangedDocTypes[docType] = dt; } } void DocTypeEdit::slotTemplateUrlChanged( const QString& newUrl ) { QString docType; if(mTypeListBox->currentRow() != -1) docType = mTypeListBox->currentItem()->text(); if( docType.isEmpty() || ! mOrigDocTypes.contains(docType) ) return; DocType dt = mOrigDocTypes[docType]; if ( mChangedDocTypes.contains( docType ) ) { dt = mChangedDocTypes[docType]; } if ( newUrl != dt.templateFile() ) { dt.setTemplateFile( newUrl ); mChangedDocTypes[docType] = dt; } } void DocTypeEdit::slotWatermarkUrlChanged( const QString& newUrl ) { QString docType = mTypeListBox->currentItem()->text(); DocType dt = mOrigDocTypes[docType]; if ( mChangedDocTypes.contains( docType ) ) { dt = mChangedDocTypes[docType]; } if ( newUrl != dt.watermarkFile() ) { dt.setWatermarkFile( newUrl ); mChangedDocTypes[docType] = dt; } } void DocTypeEdit::slotNumberCycleChanged( const QString& newCycle ) { QString docTypeName = mTypeListBox->currentItem()->text(); DocType dt = currentDocType(); dt.setNumberCycleName( newCycle ); mChangedDocTypes[docTypeName] = dt; // qDebug () << "Changing the cycle name of " << docTypeName << " to " << newCycle; mIdent->setText( dt.identTemplate() ); int nextNum = dt.nextIdentId( false )-1; mCounter->setText( QString::number( nextNum ) ); mExampleId->setText( dt.generateDocumentIdent( QDate::currentDate(), mExampleAddressUid, nextNum, 2 ) ); } QStringList DocTypeEdit::allNumberCycles() { QStringList re; re << NumberCycle::defaultName(); QSqlQuery q( "SELECT av.value FROM attributes a, attributeValues av " "WHERE a.id=av.attributeId AND a.hostObject='DocType' " "AND a.name='identNumberCycle'" ); while ( q.next() ) { QString cycleName = q.value(0).toString(); re << cycleName; } return re; } void DocTypeEdit::saveDocTypes() { // removed doctypes // FIXME: Remove unreferenced number cycles for ( QStringList::Iterator it = mRemovedTypes.begin(); it != mRemovedTypes.end(); ++it ) { if ( mOrigDocTypes.contains( *it ) ) { DocType dt = mOrigDocTypes[*it]; removeTypeFromDb( *it ); mOrigDocTypes.remove( *it ); mChangedDocTypes.remove( *it ); emit removedType( *it ); } } // added doctypes for ( QStringList::Iterator it = mAddedTypes.begin(); it != mAddedTypes.end(); ++it ) { QString name = *it; if ( mOrigDocTypes.contains( name ) ) { // just to check DocType dt = mChangedDocTypes[name]; QString numCycleName = dt.numberCycleName(); // qDebug () << "Number cycle name for to add doctype " << name << ": " << numCycleName; dt.save(); } } // edited doctypes QMap::Iterator it; for ( it = mTypeNameChanges.begin(); it != mTypeNameChanges.end(); ++it ) { QString oldName( it.key() ); if ( mOrigDocTypes.contains( oldName ) ) { QString newName = it.value(); // qDebug () << "Renaming " << oldName << " to " << newName; DocType dt = mOrigDocTypes[oldName]; if ( mChangedDocTypes.contains( newName ) ) { dt = mChangedDocTypes[newName]; } else { dt.setName( newName ); } mOrigDocTypes.remove( oldName ); mOrigDocTypes[newName] = dt; dt.save(); } else { qCritical() << "Can not find doctype to change named " << oldName; } } // check if numberCycles have changed. QMap::Iterator mapit; for ( mapit = mChangedDocTypes.begin(); mapit != mChangedDocTypes.end(); ++mapit ) { DocType dt = mapit.value(); dt.save(); } // now the list of document types should be up to date and reflected into // the database. DocType::clearMap(); } void DocTypeEdit::removeTypeFromDb( const QString& name ) { QSqlQuery delQuery; dbID id = DocType::docTypeId( name ); if ( !id.isOk() ) { // qDebug () << "Can not find doctype " << name << " to remove!"; return; } // delete in DocTypeRelations delQuery.prepare( "DELETE FROM DocTypeRelations WHERE followerId=:id or typeId=:id" ); delQuery.bindValue( ":id", id.toString() ); delQuery.exec(); // delete in DocTexts delQuery.prepare( "DELETE FROM DocTexts WHERE DocTypeId=:id" ); delQuery.bindValue( ":id", id.toString() ); delQuery.exec(); // delete in the DocTypes table delQuery.prepare( "DELETE FROM DocTypes WHERE docTypeId=:id" ); delQuery.bindValue( ":id", id.toString() ); delQuery.exec(); AttributeMap attMap( "DocType" ); attMap.dbDeleteAll( id ); } void DocTypeEdit::renameTypeInDb( const QString& oldName, const QString& newName ) { QSqlQuery q; q.prepare( "UPDATE DocTypes SET name=:newName WHERE docTypeID=:oldId" ); dbID id = DocType::docTypeId( oldName ); if ( id.isOk() ) { q.bindValue( ":newName", newName ); q.bindValue( ":oldId", id.toInt() ); q.exec(); if ( q.numRowsAffected() == 0 ) { qCritical() << "Database update failed for renaming " << oldName << " to " << newName; } else { // qDebug () << "Renamed doctype " << oldName << " to " << newName; } } else { qCritical() << "Could not find the id for doctype named " << oldName; } } kraft-1.1/src/doctypeedit.h000066400000000000000000000051261450127457600157560ustar00rootroot00000000000000/*************************************************************************** doctypeedit.h - the document type editor ------------------- begin : Fri Jan 2 2009 copyright : (C) 2009 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DOCTYPEEDIT_H #define DOCTYPEEDIT_H #include #include #include #include "doctype.h" #include "ui_doctypeeditbase.h" class QLineEdit; class QLabel; class QPushButton; class QComboBox; class QCheckBox; /** * @author Klaas Freitag */ // ################################################################################ class DocTypeEdit : public QWidget, protected Ui::DocTypeEditBase { Q_OBJECT public: DocTypeEdit( QWidget *parent = 0 ); void saveDocTypes(); public slots: void slotDocTypeSelected( const QString& = QString() ); void slotAddDocType(); void slotEditDocType(); void slotRemoveDocType(); protected slots: void fillNumberCycleCombo(); void slotNumberCycleChanged( const QString& ); void slotEditNumberCycles(); void slotWatermarkModeChanged( int ); void slotWatermarkUrlChanged( const QString& ); void slotTemplateUrlChanged( const QString& ); void slotAppendPDFUrlChanged( const QString& ); signals: /** * emitted for every doctype which is deleted */ void removedType( const QString& ); private: DocType currentDocType(); DocType mOrigDocType; QStringList allNumberCycles(); QStringList removedTypes() { return mRemovedTypes; } void removeTypeFromDb( const QString& ); void renameTypeInDb( const QString&, const QString& ); QMap mTypeNameChanges; QMap mChangedDocTypes; QMap mOrigDocTypes; QStringList mAddedTypes; QStringList mRemovedTypes; QString mPreviousType; QString mExampleDocType; QString mExampleAddressUid; }; #endif kraft-1.1/src/doctypeeditbase.ui000066400000000000000000000256341450127457600170050ustar00rootroot00000000000000 DocTypeEditBase 0 0 710 415 0 0 0 0 Qt::Horizontal QSizePolicy::Expanding 37 20 Click to add a new document type to the list. Add click to edit the selected document type name Edit click to remove the current document type Remove Unique Document Number Number &Cycle: false mNumberCycleCombo example Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false ident Template: false Example Id: false example Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false example Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false Counter: false Qt::Horizontal QSizePolicy::Expanding 71 20 &Edit Number Cycles... Qt::Vertical QSizePolicy::Expanding 20 54 PDF Creation and Postprocessing &Template File: false mTemplateUrl 0 0 select W&atermark: false mWatermarkCombo no watermark on first page on all pages alternating (3 pages) different first and last page (3 pages) &Watermark File: false mWatermarkUrl 0 0 0 0 select Append PDF: false mWatermarkUrl 0 0 0 0 select kraft-1.1/src/documentman.cpp000066400000000000000000000147621450127457600163140ustar00rootroot00000000000000/*************************************************************************** documentman.cpp - Document Manager ------------------- begin : 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include "documentman.h" #include "defaultprovider.h" #include "docdigest.h" #include "kraftdb.h" #include "doctype.h" #include "kraftsettings.h" Q_GLOBAL_STATIC(DocumentMan, mSelf) DocumentMan *DocumentMan::self() { return mSelf; } DocumentMan::DocumentMan() : mFullTax( -1 ), mReducedTax( -1 ) { } DocGuardedPtr DocumentMan::copyDocument( const QString& copyFromId ) { DocGuardedPtr doc = new KraftDoc( ); if ( ! copyFromId.isEmpty() ) { // copy the content from the source document to the new doc. DocGuardedPtr sourceDoc = openDocument( copyFromId ); if ( sourceDoc ) { *doc = *sourceDoc; // copies all data from the previous doc doc->setPredecessor(QString()); // clear the predecessor } doc->setLastModified( QDateTime::currentDateTime()); } return doc; } DocGuardedPtr DocumentMan::createDocument( const QString& docType, const QString& copyFromId, const DocPositionList& listToCopy) { DocGuardedPtr doc = new KraftDoc(); // qDebug () << "new document ID: " << doc->docID().toString(); if ( ! copyFromId.isEmpty() ) { // copy the content from the source document to the new doc. DocGuardedPtr sourceDoc = openDocument( copyFromId ); if ( sourceDoc ) { *doc = *sourceDoc; // copies all data from the previous doc doc->setIdent(QString()); doc->setDocType(docType); // sets the defaults for the new doc type doc->deleteItems(); // remove all items that exist so far doc->setPositionList(listToCopy, true); // check for relations between old and new doc DocType sourceDocType( sourceDoc->docType() ); // for new docs check if it should substract the sum of the predecessor doc DocType newDocType(docType); if( newDocType.substractPartialInvoice() ) { if( sourceDocType.partialInvoice() ) { Geld g = sourceDoc->nettoSum(); DocPosition *pos = doc->createPosition(DocPositionBase::Position); if(pos) { Einheit e; pos->setUnit(e); pos->setAmount(1.0); Geld ng(-1 * g.toLong()); pos->setUnitPrice(ng); pos->setText(i18nc("Text to be inserted into a doc, if the sum of another doc needs to be substracted " "ie. in a final invoice if there was a partial invoice before" "%1 is substited by the doc type, %2 by the id of the predecessor doc.", "Substract sum from %1 %2", sourceDocType.name(), sourceDoc->ident())); } } } doc->setPredecessor(sourceDoc->ident()); // Take the default pre- and posttext for the new docType, or, if that is empty, the texts of the old doc QString newText = DefaultProvider::self()->defaultText( docType, KraftDoc::Header ); if (newText.isEmpty() ) { newText = sourceDoc->preTextRaw(); } doc->setPreTextRaw(newText); newText = DefaultProvider::self()->defaultText( docType, KraftDoc::Footer ); if (newText.isEmpty() ) { newText = sourceDoc->postTextRaw(); } doc->setPostTextRaw(newText); delete sourceDoc; } } else { // Absolute new document doc->setDocType(docType); doc->setPreTextRaw(DefaultProvider::self()->defaultText(docType, KraftDoc::Header)); doc->setPostTextRaw(DefaultProvider::self()->defaultText(docType, KraftDoc::Footer)); doc->setGoodbye( KraftSettings::greeting() ); } // set the proper texts and other data doc->setLastModified( QDateTime::currentDateTime()); return doc; } DocGuardedPtr DocumentMan::openDocumentbyIdent( const QString& ident ) { QSqlQuery q; q.prepare("SELECT docID FROM document WHERE ident=:ident"); q.bindValue(":ident", ident); q.exec(); if( q.next() ) { const QString id = q.value(0).toString(); return openDocument(id); } return nullptr; } DocGuardedPtr DocumentMan::openDocument( const QString& id ) { // qDebug () << "Opening Document with id " << id; DocGuardedPtr doc = new KraftDoc(); doc->openDocument( id ); return doc; } void DocumentMan::clearTaxCache() { mFullTax = -1; mReducedTax = -1; } double DocumentMan::tax( const QDate& date ) { if ( mFullTax < 0 || date != mTaxDate ) readTaxes( date ); return mFullTax; } double DocumentMan::reducedTax( const QDate& date ) { if ( mReducedTax < 0 || date != mTaxDate ) readTaxes( date ); return mReducedTax; } bool DocumentMan::readTaxes( const QDate& date ) { QString sql; QSqlQuery q; sql = "SELECT fullTax, reducedTax, startDate FROM taxes "; sql += "WHERE startDate <= :date ORDER BY startDate DESC LIMIT 1"; q.prepare( sql ); QString dateStr = date.toString( "yyyy-MM-dd" ); // qDebug () << "** Datestring: " << dateStr; q.bindValue( ":date", dateStr ); q.exec(); if ( q.next() ) { mFullTax = q.value( 0 ).toDouble(); mReducedTax = q.value( 1 ).toDouble(); mTaxDate = date; // qDebug () << "* Taxes: " << mFullTax << "/" << mReducedTax << " from " << q.value( 2 ).toDate(); } return ( mFullTax > 0 && mReducedTax > 0 ); } DocumentMan::~DocumentMan() { } kraft-1.1/src/documentman.h000066400000000000000000000034761450127457600157610ustar00rootroot00000000000000/*************************************************************************** documentman.h - Document Manager ------------------- begin : 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DOCUMENTMAN_H #define DOCUMENTMAN_H #include "kraftdoc.h" class DocPosition; class QSqlQuery; typedef QMap DocumentMap; class DocumentMan { public: ~DocumentMan(); static DocumentMan *self(); DocGuardedPtr createDocument(const QString& docType, const QString& copyFromId = QString(), const DocPositionList &listToCopy = DocPositionList() ); DocGuardedPtr copyDocument( const QString& copyFromId ); DocGuardedPtr openDocument( const QString& ); DocGuardedPtr openDocumentbyIdent( const QString& ident ); double tax( const QDate& ); double reducedTax( const QDate& ); void clearTaxCache(); DocumentMan(); private: bool readTaxes( const QDate& ); double mFullTax; double mReducedTax; QDate mTaxDate; }; #endif kraft-1.1/src/documentsaverbase.cpp000066400000000000000000000023151450127457600175030ustar00rootroot00000000000000/*************************************************************************** documentsaverbase - saver for documents ------------------- begin : 2006-20-01 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt // include files for KDE #include #include "documentsaverbase.h" DocumentSaverBase::DocumentSaverBase( ) : QObject() { } DocumentSaverBase::~DocumentSaverBase( ) { } /* END */ kraft-1.1/src/documentsaverbase.h000066400000000000000000000026001450127457600171450ustar00rootroot00000000000000/*************************************************************************** documentsaverbase - Base class of a document save class ------------------- begin : 2006-02-21 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _DOCUMENTSAVERBASE_H #define _DOCUMENTSAVERBASE_H // include files #include /** * */ class KraftDoc; class dbID; class DocumentSaverBase : public QObject { Q_OBJECT public: DocumentSaverBase(); virtual ~DocumentSaverBase(); virtual bool saveDocument( KraftDoc* ) = 0; virtual void load( const QString&, KraftDoc * ) = 0; }; #endif /* END */ kraft-1.1/src/documentsaverdb.cpp000066400000000000000000000377411450127457600171710ustar00rootroot00000000000000/*************************************************************************** templatesaverbase - ------------------- begin : 2005-20-01 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include #include // include files for KDE #include #include "documentsaverdb.h" #include "docposition.h" #include "kraftdoc.h" #include "kraftdb.h" #include "unitmanager.h" #include "dbids.h" #include "kraftsettings.h" #include "doctype.h" #include "defaultprovider.h" /* Table document: * +----------------+--------------+------+-----+-------------------+----------------+ * | Field | Type | Null | Key | Default | Extra | * +----------------+--------------+------+-----+-------------------+----------------+ * | docID | int(11) | NO | PRI | NULL | auto_increment | * | ident | varchar(32) | YES | MUL | NULL | | * | docType | varchar(255) | YES | | NULL | | * | docDescription | text | YES | | NULL | | * | clientID | varchar(32) | YES | MUL | NULL | | * | clientAddress | text | YES | | NULL | | * | salut | varchar(255) | YES | | NULL | | * | goodbye | varchar(128) | YES | | NULL | | * | lastModified | timestamp | NO | | CURRENT_TIMESTAMP | | * | date | date | YES | | NULL | | * | pretext | text | YES | | NULL | | * | posttext | text | YES | | NULL | | * | country | varchar(32) | YES | | NULL | | * | language | varchar(32) | YES | | NULL | | * | projectLabel | varchar(255) | YES | | NULL | | * | predecessor | varchar(32) | YES | | NULL | | * +----------------+--------------+------+-----+-------------------+----------------+ * 14 rows in set (0.00 sec) * */ namespace { void checkAndSet(bool& changes, QSqlRecord& record, const QString& name, const QVariant& setValue) { Q_ASSERT(record.contains(name)); // the record must have the column if( record.value(name) != setValue) { record.setValue(name, setValue); changes = true; } } bool fillDocumentBuffer(QSqlRecord &buf, KraftDoc *doc) { bool changes {false}; if( doc ) { checkAndSet(changes, buf, "ident", doc->ident()); checkAndSet(changes, buf, "docType", doc->docType()); checkAndSet(changes, buf, "docDescription", KraftDB::self()->mysqlEuroEncode(doc->whiteboard())); checkAndSet(changes, buf, "clientID", doc->addressUid()); checkAndSet(changes, buf, "clientAddress", doc->address()); checkAndSet(changes, buf, "salut", doc->salut()); checkAndSet(changes, buf, "goodbye", doc->goodbye()); checkAndSet(changes, buf, "date", doc->date()); checkAndSet(changes, buf, "pretext", KraftDB::self()->mysqlEuroEncode( doc->preTextRaw())); checkAndSet(changes, buf, "posttext", KraftDB::self()->mysqlEuroEncode( doc->postTextRaw())); // The locale can be reconstructed from the name of the locale. checkAndSet(changes, buf, "country", DefaultProvider::self()->locale()->name()); // ...while the language setting is not really needed, but for beauty written to db. checkAndSet(changes, buf, "language", QLocale::languageToString(DefaultProvider::self()->locale()->language())); checkAndSet(changes, buf, "projectLabel", doc->projectLabel()); checkAndSet(changes, buf, "predecessor", doc->predecessor()); } return changes; } } DocumentSaverDB::DocumentSaverDB( ) : DocumentSaverBase(), PosTypePosition( QString::fromLatin1( "Position" ) ), PosTypeExtraDiscount( QString::fromLatin1( "ExtraDiscount" ) ), PosTypeHeader( QString::fromLatin1( "Header" ) ) { } bool DocumentSaverDB::saveDocument(KraftDoc *doc ) { if( ! doc ) return false; QSqlTableModel model; model.setTable("document"); QSqlRecord record; // qDebug () << "############### Document Save ################"; if( doc->isNew() ) { record = model.record(); } else { model.setFilter("docID=" + doc->docID().toString()); model.select(); if ( model.rowCount() > 0 ) { record = model.record(0); } else { qCritical() << "Could not select document record"; return false; } // The document was already saved. } QString ident; if( doc->isNew() || doc->docTypeChanged() ) { // an existing doc has a new document type. Fix the doc number cycle and pick a new ident DocType dt( doc->docType() ); int id = dt.nextIdentId(true); int dayCnt = dt.nextDayCounter(QDate::currentDate()); ident = dt.generateDocumentIdent(doc->date(), doc->addressUid(), id, dayCnt); doc->setIdent( ident ); } bool hasChanges = fillDocumentBuffer( record, doc ); if( doc->isNew() ) { // qDebug () << "Doc is new, inserting"; if( !model.insertRecord(-1, record)) { QSqlError err = model.lastError(); // qDebug () << "################# SQL Error: " << err.text(); } model.submitAll(); dbID id = KraftDB::self()->getLastInsertID(); doc->setDocID( id ); model.setFilter("docID=" + id.toString()); model.select(); if ( model.rowCount() > 0 ) { model.setData(model.index(0, 1), ident); model.submitAll(); } } else { // qDebug () << "Doc is not new, updating #" << doc->docID().intID(); checkAndSet(hasChanges, record, "docID", doc->docID().toString()); if (!hasChanges) { // if there haven't been changes in the document record, we update the changes // timestamp manually, otherwise it is not updated at all. const QString dt = QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm:ss"); checkAndSet(hasChanges, record, "lastModified", QVariant(dt)); } } model.setRecord(0, record); model.submitAll(); saveDocumentPositions( doc ); // qDebug () << "Saved document no " << doc->docID().toString(); return true; } void DocumentSaverDB::saveDocumentPositions( KraftDoc *doc ) { DocPositionList posList = doc->positions(); // invert all pos numbers to avoid a unique violation // FIXME: We need non-numeric ids QSqlQuery upq; QString queryStr = "UPDATE docposition SET ordNumber = -1 * ordNumber WHERE docID="; queryStr += doc->docID().toString(); queryStr += " AND ordNumber > 0"; upq.prepare( queryStr ); upq.exec(); int ordNumber = 1; QSqlTableModel model; model.setTable("docposition"); model.setEditStrategy(QSqlTableModel::OnManualSubmit); QVector deleteIds; DocPositionListIterator it( posList ); while( it.hasNext() ) { DocPositionBase *dpb = it.next(); DocPosition *dp = static_cast(dpb); int posDbID = dp->dbId().toInt(); if( dp->toDelete() ) { qDebug () << "Delete doc item id" << posDbID; // delete all existing attributes dp->attributes().dbDeleteAll( dp->dbId() ); deleteIds.append(posDbID); continue; } QSqlRecord record ; bool doInsert = true; if( posDbID > -1 ) { const QString selStr = QString("docID=%1 AND positionID=%2").arg( doc->docID().toInt() ).arg( posDbID ); // qDebug() << "Selecting with " << selStr; model.setFilter(selStr); model.select(); if ( model.rowCount() > 0 ) { record = model.record(0); doInsert = false; } else { qCritical() << "ERR: Could not select document position record"; return; } } else { // The record is new record = model.record(); } // qDebug() << "Updating position " << dp->position() << " is " << dp->text(); QString typeStr = PosTypePosition; double price = dp->unitPrice().toDouble(); if ( dp->type() == DocPositionBase::ExtraDiscount ) { typeStr = PosTypeExtraDiscount; } record.setValue( "docID", QVariant(doc->docID().toInt())); record.setValue( "ordNumber", QVariant(ordNumber)); record.setValue( "text", QVariant(dp->text())); record.setValue( "postype", QVariant(typeStr)); record.setValue( "amount", QVariant(dp->amount())); int unitId = dp->unit().id(); record.setValue( "unit", QVariant(unitId)); record.setValue( "price", QVariant(price)); record.setValue( "taxType", QVariant(dp->taxType())); ordNumber++; // FIXME if( doInsert ) { // qDebug () << "Inserting!"; model.insertRecord(-1, record); model.submitAll(); dp->setDbId( KraftDB::self()->getLastInsertID().toInt() ); } else { // qDebug () << "Updating!"; model.setRecord(0, record); model.submitAll(); } QSqlError err = model.lastError(); if( err.type() != QSqlError::NoError ) { qDebug () << "SQL-ERR: " << err.text() << " in " << model.tableName(); } dp->attributes().save( dp->dbId() ); } model.submitAll(); /* remove the docpositions that were marked to be deleted */ if( deleteIds.count() ) { QSqlQuery delQuery; delQuery.prepare( "DELETE FROM docposition WHERE positionID=:id and docID=:docId" ); int docId = doc->docID().toInt(); for( int id : deleteIds ) { // kDebug() << "Deleting attribute id " << id; delQuery.bindValue(":id", id ); delQuery.bindValue(":docId", docId); delQuery.exec(); } } } void DocumentSaverDB::load( const QString& id, KraftDoc *doc ) { if( !id.isEmpty() ) { QSqlQuery q; q.prepare("SELECT ident, docType, clientID, clientAddress, salut, goodbye, date, lastModified, language, country, " "pretext, posttext, docDescription, projectlabel, predecessor FROM document WHERE docID=:docID"); q.bindValue(":docID", id); q.exec(); // qDebug () << "Loading document id " << id; if( q.next()) { // qDebug () << "loading document with id " << id; dbID dbid; dbid = id; doc->setDocID(dbid); doc->setIdent( q.value( 0 ).toString() ); doc->setDocType( q.value( 1 ).toString() ); doc->setAddressUid( q.value( 2 ).toString() ); doc->setAddress( q.value( 3 ).toString() ); QString salut = q.value(4).toString(); doc->setSalut( salut ); doc->setGoodbye( q.value( 5 ).toString() ); doc->setDate ( q.value( 6 ).toDate() ); QDateTime dt = q.value(7).toDateTime(); // Sqlite stores the timestamp as UTC in the database. Mysql does not. if (KraftDB::self()->isSqlite()) { dt.setTimeSpec(Qt::UTC); doc->setLastModified(dt.toLocalTime()); } else { doc->setLastModified(dt); } // Removed, as with Kraft 0.80 there is no locale management on doc level any more // Later, the locale can be read from here again. // doc->setCountryLanguage( q.value( 8 ).toString(), // q.value( 9 ).toString()); doc->setPreTextRaw( KraftDB::self()->mysqlEuroDecode( q.value( 10 ).toString() ) ); doc->setPostTextRaw( KraftDB::self()->mysqlEuroDecode( q.value( 11 ).toString() ) ); doc->setWhiteboard( KraftDB::self()->mysqlEuroDecode( q.value( 12 ).toString() ) ); doc->setProjectLabel( q.value(13).toString() ); doc->setPredecessor( q.value(14).toString() ); } } // load the dbID of the predecessor document from the database. const QString pIdent = doc->predecessor(); if( ! pIdent.isEmpty() ) { QSqlQuery q1; q1.prepare("SELECT docID FROM document WHERE ident=:docID"); q1.bindValue(":docID", pIdent); q1.exec(); if( q1.next() ) { const QString pDbId = q1.value(0).toString(); doc->setPredecessorDbId(pDbId); } } // finally load the item data. loadPositions( id, doc ); } /* docposition: +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | positionID | int(11) | | PRI | NULL | auto_increment | | docID | int(11) | | MUL | 0 | | | ordNumber | int(11) | | | 0 | | | text | mediumtext | YES | | NULL | | | amount | decimal(6,2) | YES | | NULL | | | unit | varchar(64) | YES | | NULL | | | price | decimal(6,2) | YES | | NULL | | +------------+--------------+------+-----+---------+----------------+ */ void DocumentSaverDB::loadPositions( const QString& id, KraftDoc *doc ) { QSqlQuery q; q.prepare("SELECT positionID, postype, text, amount, unit, price, taxType FROM docposition WHERE docID=:docID ORDER BY ordNumber"); q.bindValue(":docID", id); q.exec(); // qDebug () << "* loading document positions for document id " << id; while( q.next() ) { // qDebug () << " loading position id " << q.value( 0 ).toInt(); DocPositionBase::PositionType type = DocPositionBase::Position; QString typeStr = q.value( 1 ).toString(); if ( typeStr == PosTypeExtraDiscount ) { type = DocPositionBase::ExtraDiscount; } else if ( typeStr == PosTypePosition ) { // nice, default position type. type = DocPositionBase::Position; } else { // qDebug () << "ERROR: Strange type string loaded from db: " << typeStr; } DocPosition *dp = doc->createPosition( type ); dp->setDbId( q.value(0).toInt() ); dp->setText( q.value(2).toString() ); // Note: empty fields are treated as Positions which is intended because // the type col was added later and thus might be empty for older entries dp->setAmount( q.value(3).toDouble() ); dp->setUnit( UnitManager::self()->getUnit( q.value(4).toInt() ) ); dp->setUnitPrice( q.value(5).toDouble() ); dp->setTaxType( q.value(6).toInt() ); dp->loadAttributes(); } } DocumentSaverDB::~DocumentSaverDB( ) { } /* END */ kraft-1.1/src/documentsaverdb.h000066400000000000000000000031741450127457600166270ustar00rootroot00000000000000/*************************************************************************** documentsaverdb - save documents to the database ------------------- begin : 2006-02-21 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _DOCUMENTSAVERDB_H #define _DOCUMENTSAVERDB_H #include "documentsaverbase.h" class KraftDoc; class QSqlRecord; class dbID; class QString; class DocumentSaverDB : public DocumentSaverBase { Q_OBJECT public: DocumentSaverDB(); virtual ~DocumentSaverDB(); virtual bool saveDocument( KraftDoc* ); virtual void load( const QString& , KraftDoc * ); protected: virtual void loadPositions( const QString&, KraftDoc* ); virtual void saveDocumentPositions( KraftDoc* ); private: const QString PosTypePosition; const QString PosTypeExtraDiscount; const QString PosTypeHeader; }; #endif /* END */ kraft-1.1/src/documenttemplate.cpp000066400000000000000000000477471450127457600173650ustar00rootroot00000000000000/*************************************************************************** Template for Kraft Documents - Grantlee and ctemplate ------------------- begin : March 2020 copyright : (C) 2020 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "documenttemplate.h" #include "epcqrcode.h" #include "texttemplate.h" #include "grantleetemplate.h" #include "format.h" #include "kraftsettings.h" #include "version.h" #include #define TAG( THE_TAG ) QStringLiteral( THE_TAG ) #define DICT( THE_DICT ) QStringLiteral( THE_DICT ) // ================================================================================== namespace { QString escapeTrml2pdfXML( const QString& str ) { return( str.toHtmlEscaped() ); } QString rmlString( const QString& str, const QString& paraStyle = QString() ) { QString rml; QString style( paraStyle ); if ( style.isEmpty() ) style = QStringLiteral("text"); // QStringList li = QStringList::split( "\n", escapeTrml2pdfXML( str ) ); QStringList li = escapeTrml2pdfXML( str ).split( "\n" ); rml = QString( "" ).arg( style ); rml += li.join( QString( "" ).arg( style ) ) + ""; // qDebug () << "Returning " << rml; return rml; } QVariantHash contactToVariantHash(const KContacts::Addressee& contact ) { QVariantHash hash; QString n = contact.realName(); if (n.isEmpty()) n = QStringLiteral("Not set!"); hash.insert( QStringLiteral( "NAME" ), escapeTrml2pdfXML(n) ); if( contact.isEmpty() ) return hash; QString co = contact.organization(); if( co.isEmpty() ) { co = contact.realName(); } hash.insert( QStringLiteral( "ORGANISATION" ), escapeTrml2pdfXML( co ) ); const QUrl url = contact.url().url(); hash.insert( QStringLiteral( "URL" ), escapeTrml2pdfXML( url.url() ) ); hash.insert( QStringLiteral( "EMAIL" ), escapeTrml2pdfXML( contact.preferredEmail() ) ); hash.insert( QStringLiteral( "PHONE" ), escapeTrml2pdfXML( contact.phoneNumber( KContacts::PhoneNumber::Work ).number() ) ); hash.insert( QStringLiteral( "FAX" ), escapeTrml2pdfXML( contact.phoneNumber( KContacts::PhoneNumber::Fax ).number() ) ); hash.insert( QStringLiteral( "CELL" ), escapeTrml2pdfXML( contact.phoneNumber( KContacts::PhoneNumber::Cell ).number() ) ); KContacts::Address address; address = contact.address( KContacts::Address::Pref ); if( address.isEmpty() ) address = contact.address(KContacts::Address::Work ); if( address.isEmpty() ) address = contact.address(KContacts::Address::Home ); if( address.isEmpty() ) address = contact.address(KContacts::Address::Postal ); hash.insert( QStringLiteral( "POSTBOX" ), escapeTrml2pdfXML( address.postOfficeBox() ) ); hash.insert( QStringLiteral( "EXTENDED" ), escapeTrml2pdfXML( address.extended() ) ); hash.insert( QStringLiteral( "STREET" ), escapeTrml2pdfXML( address.street() ) ); hash.insert( QStringLiteral( "LOCALITY" ), escapeTrml2pdfXML( address.locality() ) ); hash.insert( QStringLiteral( "REGION" ), escapeTrml2pdfXML( address.region() ) ); hash.insert( QStringLiteral( "POSTCODE" ), escapeTrml2pdfXML( address.postalCode() ) ); hash.insert( QStringLiteral( "COUNTRY" ), escapeTrml2pdfXML( address.country() ) ); hash.insert( QStringLiteral( "REGION" ), escapeTrml2pdfXML( address.region() ) ); hash.insert( QStringLiteral("LABEL" ), escapeTrml2pdfXML( address.label() ) ); return hash; } QVariantHash labelVariantHash() { QVariantHash hash; hash.insert( TAG( "NO_SHORT"), i18nc("Sequence number printed on the document", "No.") ); hash.insert( TAG( "ITEM"), i18nc("Document item printed on the document", "Item") ); hash.insert( TAG( "QUANTITY_SHORT"), i18nc("Abbrev. of Quantity printed on the document", "Qty.") ); hash.insert( TAG( "UNIT"), i18nc("Unit printed on the document", "Unit") ); hash.insert( TAG( "PRICE"), i18nc("Price of an item printed on the document", "Price") ); hash.insert( TAG( "SUM"), i18nc("Printed on the document", "Sum") ); hash.insert( TAG( "NET"), i18nc("printed on the document", "Net") ); hash.insert( TAG( "VAT"), i18nc("Printed on the document", "VAT") ); hash.insert( TAG( "TYPE"), i18nc("Document type, printed on the document", "Type") ); hash.insert( TAG( "PHONE"), i18nc("Printed on the document", "Phone")); hash.insert( TAG( "FAX"), i18nc("Printed on the document", "FAX")); hash.insert( TAG( "MOBILE"), i18nc("Printed on the document", "Mobile")); hash.insert( TAG( "EMAIL"), i18nc("Printed on the document", "Email")); hash.insert( TAG( "WEBSITE"), i18nc("Printed on the document", "Website")); hash.insert( TAG( "PAGE"), i18nc("Printed on the document", "Page")); hash.insert( TAG( "PREDECESSOR"), i18nc("Label of Predecessor document number", "Predecessor-Doc")); hash.insert( TAG( "PAGE_OF"), i18nc("the 'of' in page X of Y", "of")); hash.insert( TAG( "DOC_NO"), i18nc("Document number on document", "Document No.")); hash.insert( TAG( "DATE"), i18nc("Date on document", "Date")); hash.insert( TAG( "PROJECT"), i18nc("Project label", "Project")); hash.insert( TAG( "CUST_ID"), i18nc("Customer ID on document", "Customer Id")); hash.insert( TAG( "CURRENCY_SIGN"), DefaultProvider::self()->currencySymbol()); return hash; } QVariantHash kraftVariantHash() { QVariantHash hash; QString h = QString("Kraft %1 %2").arg(Kraft::Version::number()). arg(Kraft::Version::codeName()); hash.insert(TAG("VERSION"), h); h = QString("DB-Scheme %1").arg(Kraft::Version::dbSchemaVersion()); hash.insert(TAG("DB_SCHEME"), h); h = qgetenv("USER"); if (h.isEmpty()) h = qgetenv("USERNAME"); hash.insert(TAG("SYS_USER"), h); h = qgetenv("HOSTNAME"); if (h.isEmpty()) h = qgetenv("HOST"); if (!h.isEmpty()) hash.insert(TAG("HOSTNAME"), h); return hash; } void variantHashToTemplate( TextTemplate& tmpl, const QString& prefix, const QVariantHash& hash) { QVariantHash::const_iterator i; for (i = hash.constBegin(); i != hash.constEnd(); ++i) { QString key = i.key(); if (!prefix.isEmpty()) { key = QString("%1_%2").arg(prefix).arg(i.key()); } tmpl.setValue(key, i.value().toString()); } } void contactToTemplate( TextTemplate& tmpl, const QString& prefix, const KContacts::Addressee& contact ) { const QVariantHash hash = contactToVariantHash(contact); variantHashToTemplate(tmpl, prefix, hash); } void addLabelsToTemplate(TextTemplate& tmpl) { const QVariantHash hash = labelVariantHash(); variantHashToTemplate(tmpl, QStringLiteral("LAB"), hash); } QString generateEPCQRCodeFile(ArchDoc *archDoc) { QString tempFile; if (!archDoc) return tempFile; const QString bacName = KraftSettings::self()->bankAccountName(); const QString bacIBAN = KraftSettings::self()->bankAccountIBAN(); const QString bacBIC = KraftSettings::self()->bankAccountBIC(); EPCQRCode qrCode; const QString reason = i18nc("Credit Transfer reason string, 1=DocType, 2=DocIdent, 3=Date, ie. Invoice 2022-183 dated 2022-03-22", "%1 %2 dated %3",archDoc->docTypeStr(), archDoc->ident(), archDoc->dateStr()); const QString svgText = qrCode.asSvg(archDoc->bruttoSum(), bacName, bacBIC, bacIBAN, reason); // -- save the EPC QR Code to a temp file if (svgText.isEmpty()) { qWarning() << "Failed to generate SVG text"; } else { QTemporaryFile tFile(QString("%1/XXXXXX.svg").arg(QDir::tempPath())); tFile.setAutoRemove(false); if (tFile.open()) { tempFile = tFile.fileName(); QTextStream stream(&tFile); stream << svgText; tFile.close(); } } return tempFile; } } // ================================================================================== DocumentTemplate::DocumentTemplate( const QString& tmplFile ) :_tmplFile(tmplFile) { } // ================================================================================== CTemplateDocumentTemplate::CTemplateDocumentTemplate(const QString& tmplFile) :DocumentTemplate(tmplFile) { } const QString CTemplateDocumentTemplate::expand(ArchDoc *archDoc, const KContacts::Addressee& myContact, const KContacts::Addressee& customerContact) { if (archDoc == nullptr) { return QString(); } // create a text template TextTemplate tmpl; tmpl.setTemplateFileName(_tmplFile); /* replace the placeholders */ /* A placeholder has the format */ const ArchDocPositionList posList = archDoc->positions(); QString h; ArchDocPositionList::const_iterator it; int specialPosCnt = 0; int taxFreeCnt = 0; int reducedTaxCnt = 0; int fullTaxCnt = 0; bool individualTax = false; /* Check for the tax settings: If the taxType is not the same for all items, * we have individual Tax setting and show the tax marker etc. */ DocPositionBase::TaxType ttype = DocPositionBase::TaxInvalid; for ( it = posList.begin(); it != posList.end(); ++it ) { ArchDocPosition pos (*it); if( ttype == DocPositionBase::TaxInvalid ) { ttype = pos.taxType(); } else { if( ttype != pos.taxType() ) { // different from previous one? individualTax = true; break; } } } /* now loop over the items to fill the template structures */ for ( it = posList.begin(); it != posList.end(); ++it ) { ArchDocPosition pos (*it); tmpl.createDictionary( "POSITIONS" ); tmpl.setValue( DICT("POSITIONS"), TAG( "POS_NUMBER" ) , pos.posNumber() ); tmpl.setValue( DICT("POSITIONS"), TAG("POS_TEXT"), rmlString( pos.text(), QString( "%1text" ).arg( pos.kind().toLower() ) ) ); // format the amount value of the item, do not show the precision if there is no fraction double amount = pos.amount(); h = Format::localeDoubleToString(amount, *DefaultProvider::self()->locale()); tmpl.setValue( DICT("POSITIONS"), TAG("POS_AMOUNT"), h ); tmpl.setValue( DICT("POSITIONS"), TAG("POS_UNIT"), escapeTrml2pdfXML( pos.unit() ) ); tmpl.setValue( DICT("POSITIONS"), TAG("POS_UNITPRICE"), pos.unitPrice().toLocaleString() ); tmpl.setValue( DICT("POSITIONS"), TAG("POS_TOTAL"), pos.nettoPrice().toLocaleString() ); tmpl.setValue( DICT("POSITIONS"), TAG("POS_KIND"), pos.kind().toLower() ); QString taxType; if( individualTax ) { if( pos.taxType() == 1 ) { taxFreeCnt++; taxType = "TAX_FREE"; } else if( pos.taxType() == 2 ) { reducedTaxCnt++; taxType = "REDUCED_TAX"; } else { // ATTENTION: Default for all non known tax types is full tax. fullTaxCnt++; taxType = "FULL_TAX"; } tmpl.createSubDictionary( "POSITIONS", taxType ); } /* item kind: Normal, alternative or demand item. For normal items, the kind is empty. */ if ( !pos.kind().isEmpty() ) { specialPosCnt++; } } if ( specialPosCnt ) { tmpl.createDictionary( "SPECIAL_POS" ); tmpl.setValue( DICT("SPECIAL_POS"), TAG("COUNT"), QString::number( specialPosCnt ) ); tmpl.setValue( DICT("SPECIAL_POS"), TAG("LAB_SPECIAL_ITEMS"), i18n("Please note: This offer contains %1 alternative or demand positions, printed in italic font. These do not add to the overall sum.", QString::number( specialPosCnt ) ) ); } /* * Just show the tax index if we have multiple tax settings */ if( individualTax ) { tmpl.createDictionary( "TAX_FREE_ITEMS" ); tmpl.setValue( DICT("TAX_FREE_ITEMS"), TAG("COUNT"), QString::number( taxFreeCnt )); tmpl.setValue( DICT("TAX_FREE_ITEMS"), TAG( "LAB_TAX_FREE_ITEMS"), i18n("tax free items (%1 pcs.)", QString::number( taxFreeCnt )) ); tmpl.createDictionary( "REDUCED_TAX_ITEMS" ); tmpl.setValue( DICT("REDUCED_TAX_ITEMS"), TAG("COUNT"), QString::number( reducedTaxCnt )); tmpl.setValue( DICT("REDUCED_TAX_ITEMS"), TAG("TAX"), DefaultProvider::self()->locale()->toString( archDoc->reducedTax()) ); tmpl.setValue( DICT("REDUCED_TAX_ITEMS"), TAG("LAB_TAX_REDUCED_ITEMS"), i18n("items with reduced tax of %1% (%2 pcs.)", DefaultProvider::self()->locale()->toString( archDoc->reducedTax()), QString::number( reducedTaxCnt )) ); tmpl.createDictionary( "FULL_TAX_ITEMS" ); tmpl.setValue( DICT("FULL_TAX_ITEMS"), TAG("COUNT"), QString::number( fullTaxCnt )); tmpl.setValue( DICT("FULL_TAX_ITEMS"), TAG("TAX"), DefaultProvider::self()->locale()->toString( archDoc->tax()) ); tmpl.setValue( DICT("FULL_TAX_ITEMS"), TAG("LAB_TAX_FULL_ITEMS"), i18n("No label: items with full tax of %1% (%2 pcs.)", DefaultProvider::self()->locale()->toString( archDoc->tax()), QString::number( fullTaxCnt )) ); } /* now replace stuff in the whole document */ tmpl.setValue( TAG( "DATE" ), Format::toDateString(archDoc->date(), KraftSettings::self()->dateFormat())); tmpl.setValue( TAG( "DOCTYPE" ), escapeTrml2pdfXML( archDoc->docTypeStr() ) ); tmpl.setValue( TAG( "ADDRESS" ), escapeTrml2pdfXML( archDoc->address() ) ); contactToTemplate( tmpl, "CLIENT", customerContact ); contactToTemplate( tmpl, "MY", myContact ); tmpl.setValue( TAG( "DOCID" ), escapeTrml2pdfXML( archDoc->ident() ) ); tmpl.setValue( TAG( "PROJECTLABEL" ), escapeTrml2pdfXML( archDoc->projectLabel() ) ); tmpl.setValue( TAG( "SALUT" ), escapeTrml2pdfXML( archDoc->salut() ) ); tmpl.setValue( TAG( "GOODBYE" ), escapeTrml2pdfXML( archDoc->goodbye() ) ); tmpl.setValue( TAG( "PRETEXT" ), rmlString( archDoc->preText() ) ); tmpl.setValue( TAG( "POSTTEXT" ), rmlString( archDoc->postText() ) ); tmpl.setValue( TAG( "BRUTTOSUM" ), archDoc->bruttoSum().toLocaleString() ); tmpl.setValue( TAG( "NETTOSUM" ), archDoc->nettoSum().toLocaleString() ); h = DefaultProvider::self()->locale()->toString( archDoc->tax() ); // qDebug () << "Tax in archive document: " << h; if ( archDoc->reducedTaxSum().toLong() != 0 ) { tmpl.createDictionary( DICT( "SECTION_REDUCED_TAX" ) ); tmpl.setValue( DICT("SECTION_REDUCED_TAX"), TAG( "REDUCED_TAX_SUM" ), archDoc->reducedTaxSum().toLocaleString() ); h = DefaultProvider::self()->locale()->toString( archDoc->reducedTax() ); tmpl.setValue( DICT("SECTION_REDUCED_TAX"), TAG( "REDUCED_TAX" ), h ); tmpl.setValue( DICT("SECTION_REDUCED_TAX"), TAG( "REDUCED_TAX_LABEL" ), i18n( "reduced VAT" ) ); } if ( archDoc->fullTaxSum().toLong() != 0 ) { tmpl.createDictionary( DICT( "SECTION_FULL_TAX" ) ); tmpl.setValue( DICT("SECTION_FULL_TAX"), TAG( "FULL_TAX_SUM" ), archDoc->fullTaxSum().toLocaleString() ); h = DefaultProvider::self()->locale()->toString( archDoc->tax() ); tmpl.setValue( DICT("SECTION_FULL_TAX"), TAG( "FULL_TAX" ), h ); tmpl.setValue( DICT("SECTION_FULL_TAX"), TAG( "FULL_TAX_LABEL" ), i18n( "VAT" ) ); } h = DefaultProvider::self()->locale()->toString( archDoc->tax() ); tmpl.setValue( TAG( "VAT" ), h ); tmpl.setValue( TAG( "VATSUM" ), archDoc->taxSum().toLocaleString() ); addLabelsToTemplate(tmpl); #if 0 /* this is still disabled as reportlab can not read SVG files * When it can or the EPC QR Code can be generated as PNG, this needs to be added * to the template: * * {{#EPC_QR_CODE}} *
            * * * * {{/EPC_QR_CODE}} */ QString qrcodefile; if (archDoc->isInvoice()) { qrcodefile = generateEPCQRCodeFile(archDoc); _tmpFiles.append(qrcodefile); tmpl.createDictionary( DICT( "EPC_QR_CODE" ) ); tmpl.setValue( DICT("EPC_QR_CODE"), TAG( "SVG_FILE_NAME" ), qrcodefile); } #endif // finalize the template const QString output = tmpl.expand(); return output; } // ================================================================================== GrantleeDocumentTemplate::GrantleeDocumentTemplate(const QString& tmplFile) : DocumentTemplate(tmplFile) { } const QString GrantleeDocumentTemplate::expand( ArchDoc *archDoc, const KContacts::Addressee &myContact, const KContacts::Addressee &customerContact) { Grantlee::registerMetaType(); Grantlee::registerMetaType(); QFileInfo fi(_tmplFile); if (!fi.exists()) { _errorStr = i18n("Template to convert is not existing!"); } if (!fi.isReadable()) { _errorStr = i18n("Can not read template file!"); } QString rendered; if (_errorStr.isEmpty()) { GrantleeFileTemplate gtmpl(_tmplFile); gtmpl.addToObjMapping("doc", archDoc); const auto mtt = contactToVariantHash(myContact); gtmpl.addToMappingHash(QStringLiteral("me"), mtt); const auto cct = contactToVariantHash(customerContact); gtmpl.addToMappingHash(QStringLiteral("customer"), cct); const QVariantHash labelHash = labelVariantHash(); gtmpl.addToMappingHash(QStringLiteral("label"), labelHash); // -- save the EPC QR Code which is written into a temp file QVariantHash epcHash; auto qrcodefile = generateEPCQRCodeFile(archDoc); epcHash.insert("valid", false); epcHash.insert("show", false); if (qrcodefile.isEmpty()) { qDebug() << "No Giro Code file available."; } else { _tmpFiles.append(qrcodefile); // remember file to delete later. qDebug() << "Generated Giro Code file" << qrcodefile; epcHash.insert("svgfilename", QVariant(qrcodefile)); epcHash["valid"] = true; epcHash["show"] = true; // there is a setting value of the maximum sum the EPC Code should // be printed on the document. The idea is that for very big sums, // the QR code should not be displayed. double maxEPCSum = KraftSettings::self()->displayEPCCodeMaxSum(); if (archDoc->bruttoSum().toDouble() > maxEPCSum) { epcHash["show"] = false; } gtmpl.addToMappingHash(QStringLiteral("epcqrcode"), epcHash); } const QVariantHash kraftHash = kraftVariantHash(); gtmpl.addToMappingHash(QStringLiteral("kraft"), kraftHash); bool ok; rendered = gtmpl.render(ok); if (!ok) { _errorStr = rendered; rendered.clear(); } } return rendered; } kraft-1.1/src/documenttemplate.h000066400000000000000000000051401450127457600170070ustar00rootroot00000000000000/*************************************************************************** Template for Kraft Documents - Grantlee and ctemplate ------------------- begin : March 2020 copyright : (C) 2020 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DOCUMENTTEMPLATE_H #define DOCUMENTTEMPLATE_H #include #include "archdoc.h" class DocumentTemplate { public: DocumentTemplate( const QString& tmplFile ); virtual ~DocumentTemplate(){ }; virtual const QString expand(ArchDoc *archDoc, const KContacts::Addressee &myContact, const KContacts::Addressee &customerContact) = 0; QString error() const { return _errorStr; } // The collection of temp files this process created, to be able to delete // them later when the PDF was created. // Example: The EPC QR Code SVG image. QStringList tempFilesCreated() { return _tmpFiles; } protected: QString _tmplFile; QString _errorStr; QStringList _tmpFiles; }; // ================================================================================== class CTemplateDocumentTemplate : public DocumentTemplate { public: CTemplateDocumentTemplate(const QString& tmplFile); const QString expand(ArchDoc *archDoc, const KContacts::Addressee &myContact, const KContacts::Addressee &customerContact) override; }; // ================================================================================== class GrantleeDocumentTemplate : public DocumentTemplate { public: GrantleeDocumentTemplate(const QString& tmplFile); const QString expand(ArchDoc *archDoc, const KContacts::Addressee &myContact, const KContacts::Addressee &customerContact) override; }; #endif // DOCUMENTTEMPLATE_H kraft-1.1/src/einheit.cpp000066400000000000000000000037111450127457600154170ustar00rootroot00000000000000/*************************************************************************** einheit.cpp - ------------------- begin : Don Jan 1 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "einheit.h" Einheit::Einheit() :m_dbId(-1) { } Einheit::Einheit(int id, const QString& einh, const QString& einhLong, const QString& einhPlu, const QString& einhPluLong, const QString &ec20) : m_dbId(id) { m_einheitSingular = einh; m_einheitPlural = einhPlu; m_einheitSingularLong = einhLong; m_einheitPluralLong = einhPluLong; m_ec20 = ec20; } Einheit::Einheit( int id ) : m_dbId(id) { // Ask the Unitmanager here. } Einheit::Einheit( const QString& einhText ) { m_einheitSingular = einhText; m_einheitPlural = einhText; m_einheitSingularLong = einhText; m_einheitPluralLong = einhText; } Einheit::~Einheit(){ } QString Einheit::einheit( int anz ) const { if( anz == 1 ) return einheitSingular(); else return einheitPlural(); } QString Einheit::einheit( double anz ) const { if( anz == 1.0 ) return einheitSingular(); else return einheitPlural(); } kraft-1.1/src/einheit.h000066400000000000000000000037351450127457600150720ustar00rootroot00000000000000/*************************************************************************** einheit.h - ------------------- begin : Don Jan 1 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef EINHEIT_H #define EINHEIT_H #include #include #include "kraftcat_export.h" /** *@author Klaas Freitag */ class KRAFTCAT_EXPORT Einheit { public: typedef QList List; Einheit(); Einheit( int id ); Einheit( const QString& ); // Einheit with arbitrary text. Einheit( int id, const QString&, const QString&, const QString&, const QString&, const QString& ); ~Einheit(); QString einheitSingular() const { return m_einheitSingular; } QString einheitSingularLong() const { return m_einheitSingularLong; } QString einheitPlural() const { return m_einheitPlural; } QString einheitPluralLong() const { return m_einheitPluralLong; } QString ec20() const { return m_ec20; } QString einheit( int anz ) const; QString einheit( double anz ) const; int id() { return m_dbId; } private: int m_dbId; QString m_einheitSingular; QString m_einheitPlural; QString m_einheitSingularLong; QString m_einheitPluralLong; QString m_ec20; }; #endif kraft-1.1/src/epcqrcode.cpp000066400000000000000000000077211450127457600157440ustar00rootroot00000000000000/*************************************************************************** EPC QR Code generator --------------------- begin : August 2022 copyright : (C) 2022 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include "epcqrcode.h" #include "geld.h" #include <3rdparty/qrcodegen.hpp> #include #include using namespace qrcodegen; /* * Based on this code: https://www.nayuki.io/page/qr-code-generator-library */ namespace { // Returns a string of SVG code for an image depicting the given QR Code, with the given number // of border modules. The string always uses Unix newlines (\n), regardless of the platform. std::string toSvgString(const QrCode &qr, int border) { if (border < 0) throw std::domain_error("Border must be non-negative"); if (border > INT_MAX / 2 || border * 2 > INT_MAX - qr.getSize()) throw std::overflow_error("Border too large"); std::ostringstream sb; sb << "\n"; sb << "\n"; sb << "\n"; sb << "\t\n"; sb << "\t\n"; sb << "\n"; return sb.str(); } } EPCQRCode::EPCQRCode() { } QByteArray EPCQRCode::asText(const Geld& g, const QString& bacName, const QString& bacBIC, const QString& bacIBAN, const QString& reason) { QByteArray re; double sum = g.toDouble(); if ( bacName.isEmpty() || bacIBAN.isEmpty() || sum < 0.1) { qDebug() << "Unable to generate EPC Code - insufficient bank account data."; return re; } re.append("BCD\n" "001\n" "1\n" "SCT\n"); re.append(bacBIC.toLocal8Bit()); re.append("\n"); re.append(bacName.toLocal8Bit()); re.append("\n"); re.append(bacIBAN.toLocal8Bit()); re.append("\n"); const QString money = QString("EUR%1").arg(QString::number(sum, 'f', 2)); re.append(money.toLocal8Bit()); re.append("\n\n\n"); re.append(reason.toLocal8Bit()); return re; } QString EPCQRCode::asSvg(const Geld& g, const QString &bacName, const QString &bacBIC, const QString &bacIBAN, const QString &reason) { int border = 2; QString svg; QByteArray arr = asText(g, bacName, bacBIC, bacIBAN, reason); if (!arr.isEmpty()) { QrCode qr0 = QrCode::encodeText(arr.data(), QrCode::Ecc::MEDIUM); svg = QString::fromStdString(toSvgString(qr0, border)); } return svg; } kraft-1.1/src/epcqrcode.h000066400000000000000000000033501450127457600154030ustar00rootroot00000000000000/*************************************************************************** EPC QR Code generator --------------------- begin : August 2022 copyright : (C) 2022 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef EPCQRCODE_H #define EPCQRCODE_H #include "kcontacts/addressee.h" #include #include class Geld; class EPCQRCode { public: EPCQRCode(); QByteArray asText(const Geld& g, const QString &bacName, const QString &bacBIC, const QString &bacIBAN, const QString &reason); QString asSvg(const Geld& g, const QString &bacName, const QString &bacBIC, const QString &bacIBAN, const QString &reason); // QPixmap asPng(const Geld& g, const QString &bacName, const QString &bacBIC, const QString &bacIBAN, const QString &reason, const QSize& s); private: KContacts::Addressee _contact; const QString _App {"KAddressbook"}; const QString _IBAN {"IBAN"}; const QString _BIC {"BIC"}; }; #endif // EPCQRCODE_H kraft-1.1/src/exportxrechnung.cpp000066400000000000000000000122711450127457600172360ustar00rootroot00000000000000/*************************************************************************** exporterXRechnung - Save Documents as XRechnung ------------------- begin : Feb. 2022 copyright : (C) 2022 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include "exportxrechnung.h" #include "archdoc.h" #include "documentman.h" #include "docposition.h" #include "kraftdoc.h" #include "kraftdb.h" #include "unitmanager.h" #include "dbids.h" #include "kraftsettings.h" #include "doctype.h" #include "defaultprovider.h" #include "format.h" #include "addressprovider.h" #include "grantleetemplate.h" #include "documenttemplate.h" namespace { QString xRechnungTemplate() { DocType dt("Rechnung"); // FIXME hardcoded const QString re = dt.xRechnungTemplate(); return re; } } ExporterXRechnung::ExporterXRechnung(QObject *parent) : QObject(parent), _validateWithSchema {false} { mAddressProvider = new AddressProvider(this); connect(mAddressProvider, &AddressProvider::lookupResult, this, &ExporterXRechnung::slotAddresseeFound); } void ExporterXRechnung::setDueDate(const QDate& d) { _dueDate = d; } void ExporterXRechnung::setBuyerRef(const QString& br) { _buyerRef = br; } QString ExporterXRechnung::templateFile() const { return xRechnungTemplate(); } bool ExporterXRechnung::exportDocument(const ArchDocDigest& digest) { _archDoc.loadFromDb(digest.archDocId()); _archDoc.setDueDate(_dueDate); _archDoc.setBuyerRef(_buyerRef); if (xRechnungTemplate().isEmpty()) { qDebug () << "tmplFile is empty, exit reportgenerator!"; return false; } lookupCustomerAddress(); return true; } void ExporterXRechnung::lookupCustomerAddress() { const QString clientUid = _archDoc.clientUid(); _customerContact = KContacts::Addressee(); if( ! clientUid.isEmpty() ) { AddressProvider::LookupState state = mAddressProvider->lookupAddressee( clientUid ); switch( state ) { case AddressProvider::LookupFromCache: _customerContact = mAddressProvider->getAddresseeFromCache(clientUid); break; case AddressProvider::LookupNotFound: case AddressProvider::ItemError: case AddressProvider::BackendError: // set an empty contact break; case AddressProvider::LookupOngoing: case AddressProvider::LookupStarted: // Not much to do, just wait and let the addressprovider // hit the slotAddresseFound return; } } QTimer::singleShot(0, this, &ExporterXRechnung::slotSkipLookup); } void ExporterXRechnung::slotSkipLookup() { slotAddresseeFound(QString(), _customerContact); } void ExporterXRechnung::slotAddresseeFound(const QString& uid, const KContacts::Addressee& contact) { KContacts::Addressee myContact; // leave empty for now // now the three pillars archDoc, myContact and mCustomerContact are defined. QString output; QScopedPointer templateEngine; const QString tmplFile = xRechnungTemplate(); if (tmplFile.isEmpty()) { qDebug() << "Empty template file -> exit!"; } else { qDebug() << "Using this XRechnung Template:" << tmplFile; } templateEngine.reset(new GrantleeDocumentTemplate(tmplFile)); // expand the template... const QString expanded = templateEngine->expand(&_archDoc, myContact, contact); if (expanded.isEmpty()) { // emit failure(i18n("The template expansion failed.")); qDebug() << "Expansion failed, empty result"; return; } QTemporaryFile tempFile("/tmp/xrech_XXXXXX"); tempFile.setAutoRemove(false); if (tempFile.open()) { const QString fName = tempFile.fileName(); qDebug() << "########## XRechnung written to" << fName; QTextStream outStream(&tempFile); outStream << expanded; tempFile.close(); emit xRechnungTmpFile(fName); #if 0 if (_validateWithSchema && _schema.isValid()) { QFile file(fName); file.open(QIODevice::ReadOnly); QXmlSchemaValidator validator(_schema); if (validator.validate(&file, QUrl::fromLocalFile(file.fileName()))) qDebug() << "instance document is valid"; else qDebug() << "instance document is invalid"; } #endif } } ExporterXRechnung::~ExporterXRechnung( ) { } /* END */ kraft-1.1/src/exportxrechnung.h000066400000000000000000000043071450127457600167040ustar00rootroot00000000000000/*************************************************************************** exporterXRechnung - Save Documents as XRechnung ------------------- begin : Feb. 2022 copyright : (C) 2022 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _EXPORTERXRECHNUNG_H #define _EXPORTERXRECHNUNG_H #include #include #include #include "addressprovider.h" #include "archdoc.h" class QSqlRecord; class dbID; class QString; class ArchDoc; class ExporterXRechnung : public QObject { Q_OBJECT signals: /** * @brief xRechnungTmpFile * emits the file name of a temporary file that is the XRechnung result file. * Needs to be deleted after copied to the right target file. */ void xRechnungTmpFile(const QString&); public: ExporterXRechnung(QObject *parent = nullptr); virtual ~ExporterXRechnung(); virtual bool exportDocument(const ArchDocDigest& digest); QString templateFile() const; void setDueDate(const QDate&); void setBuyerRef(const QString&); protected: void lookupCustomerAddress(); protected slots: void slotAddresseeFound(const QString &uid = QString(), const KContacts::Addressee &contact = KContacts::Addressee()); void slotSkipLookup(); private: ArchDoc _archDoc; bool _validateWithSchema; AddressProvider *mAddressProvider; KContacts::Addressee _customerContact; QString _buyerRef; QDate _dueDate; }; #endif /* END */ kraft-1.1/src/extractrc000077500000000000000000000347661450127457600152310ustar00rootroot00000000000000#! /usr/bin/env perl ### TODO: other copyrights, license? # Copyright (c) 2004 Richard Evans sub usage { warn <<"EOF"; extractrc [flags] filenames This script extracts messages from designer (.ui) and XMLGUI (.rc) files and writes on standard output (usually redirected to rc.cpp) the equivalent i18n() calls so that xgettext can parse them. --tag=name : Also extract the tag name(s). Repeat the flag to specify multiple names: --tag=tag_one --tag=tag_two --tag-group=group : Use a group of tags - uses 'default' if omitted. Valid groups are: @{[TAG_GROUPS()]} --context=name : Give i18n calls a context name: i18nc("name", ...) --lines : Include source line numbers in comments (deprecated, it is switched on by default now) --cstart=chars : Start of to-EOL style comments in output, defaults to // --language=lang : Create i18n calls appropriate for KDE bindings in the given language. Currently known languages: C++ (default), Python --ignore-no-input : Do not warn if there were no filenames specified --help|? : Display this summary --no-unescape-xml : Don't do xml unescaping EOF exit; } ########################################################################################### use strict; use warnings; use Getopt::Long; use Data::Dumper; use constant TAG_GROUP => { default => "[tT][eE][xX][tT]|title|string|whatsthis|tooltip|label", koffice => "Example|GroupName|Text|Comment|Syntax|TypeName", none => "", }; use constant TAG_GROUPS => join ", ", map "'$_'", sort keys %{&TAG_GROUP}; # Specification to extract nice element-context for strings. use constant ECTX_SPEC => { # Data structure: extension => {tag => [ctxlevel, [attribute, ...]], ...} # Order of attributes determines their order in the extracted comment. "ui" => { "widget" => [10, ["class", "name"]], "item" => [15, []], "property" => [20, ["name"]], "attribute" => [20, ["name"]], }, "rc" => { "Menu" => [10, ["name"]], "ToolBar" => [10, ["name"]], }, "kcfg" => { "group" => [10, ["name"]], "entry" => [20, ["name"]], "whatsthis" => [30, []], "tooltip" => [30, []], "label" => [30, []], }, }; # Specification to exclude strings by trailing section of element-context. use constant ECTX_EXCLUDE => [ # Data structure: [[tag, attribute, attrvalue], [...]] # Empty ("") attribute means all elements with given tag, # empty attrvalue means element with given tag and attribute of any value. [["widget", "class", "KFontComboBox"], ["item", "", ""], ["property", "", ""]], [["widget", "class", "KPushButton"], ["attribute", "name", "buttonGroup"]], [["widget", "class", "QRadioButton"], ["attribute", "name", "buttonGroup"]], [["widget", "class", "QToolButton"], ["attribute", "name", "buttonGroup"]], [["widget", "class", "QCheckBox"], ["attribute", "name", "buttonGroup"]], [["widget", "class", "QPushButton"], ["attribute", "name", "buttonGroup"]], [["widget", "class", "KTimeZoneWidget"], ["property", "name", "text"]], ]; # The parts between the tags of the extensions will be copied verbatim # Same data structure as in ECTX_EXCLUDE, but per extension. my %EXTENSION_VERBATIM_TAGS = ( "kcfg" => [["code", "", ""], ["default", "code", "true"], ["min", "code", "true"], ["max", "code", "true"]], ); # Add attribute lists as hashes, for membership checks. for my $ext ( keys %{&ECTX_SPEC} ) { for my $tag ( keys %{ECTX_SPEC->{$ext}} ) { my $arr = ECTX_SPEC->{$ext}{$tag}[1]; ECTX_SPEC->{$ext}{$tag}[2] = {map {$_ => 1} @{$arr}}; } } ########################################################################################### # Add options here as necessary - perldoc Getopt::Long for details on GetOptions GetOptions ( "tag=s" => \my @opt_extra_tags, "tag-group=s" => \my $opt_tag_group, "context=s" => \my $opt_context, # I18N context "lines" => \my $opt_lines, "cstart=s" => \my $opt_cstart, "language=s" => \my $opt_language, "ignore-no-input" => \my $opt_ignore_no_input, "no-unescape-xml" => \my $opt_no_unescape_xml, "help|?" => \&usage ); unless( @ARGV ) { warn "No filename specified" unless $opt_ignore_no_input; exit; } $opt_tag_group ||= "default"; die "Unknown tag group: '$opt_tag_group', should be one of " . TAG_GROUPS unless exists TAG_GROUP->{$opt_tag_group}; my $tags = TAG_GROUP->{$opt_tag_group}; my $extra_tags = join "", map "|" . quotemeta, @opt_extra_tags; my $text_string = qr/($tags$extra_tags)( [^>]*)?>/; # Precompile regexp my $cstart = $opt_cstart; # no default, selected by language if not given my $language = $opt_language || "C++"; my $ectx_known_exts = join "|", keys %{&ECTX_SPEC}; ########################################################################################### # Unescape basic XML entities. sub unescape_xml ($) { my $text = shift; if (not $opt_no_unescape_xml) { $text =~ s/<//g; $text =~ s/&/&/g; $text =~ s/"/"/g; } return $text; } # Convert uic to C escaping. sub escape_uic_to_c ($) { my $text = shift; $text = unescape_xml($text); $text =~ s/\\/\\\\/g; # escape \ $text =~ s/\"/\\\"/g; # escape " $text =~ s/\r//g; # remove CR (Carriage Return) $text =~ s/\n/\\n\"\n\"/g; # escape LF (Line Feed). uic also change the code line at a LF, we do not do that. return $text; } ########################################################################################### sub dummy_call_infix { my ($cstart, $stend, $ctxt, $text, @cmnts) = @_; for my $cmnt (@cmnts) { print qq|$cstart $cmnt\n|; } if (defined $text) { $text = escape_uic_to_c($text); if (defined $ctxt) { $ctxt = escape_uic_to_c($ctxt); print qq|i18nc("$ctxt", "$text")$stend\n|; } else { print qq|i18n("$text")$stend\n|; } } } my %dummy_calls = ( "C++" => sub { dummy_call_infix($cstart || "//", ";", @_); }, "Python" => sub { dummy_call_infix($cstart || "#", "", @_); }, ); die "unknown language '$language'" if not defined $dummy_calls{$language}; my $dummy_call = $dummy_calls{$language}; # Program start proper - NB $. is the current line number for my $file_name ( @ARGV ) { my $fh; unless ( open $fh, "<", $file_name ) { # warn "Failed to open: '$file_name': $!"; next; } # Ready element-context extraction. my $ectx_ext; my $ectx_string; if ( $file_name =~ /\.($ectx_known_exts)(\.(in|cmake))?$/ ) { $ectx_ext = $1; my $ectx_tag_gr = join "|", keys %{ECTX_SPEC->{$ectx_ext}}; $ectx_string = qr/($ectx_tag_gr)( [^>]*)?>/; # precompile regexp } my $string = ""; my $origstring = ""; my $in_text = 0; my $start_line_no = 0; my $in_skipped_prop = 0; my $tag = ""; my $attr = ""; my $context = ""; my $notr = ""; # Element-context data: [[level, tag, [[attribute, value], ...]], ...] # such that subarrays are ordered increasing by level. my @ectx = (); # All comments to pending dummy call. my @comments = (); while ( <$fh> ) { if ( $. == 1 and $_ !~ /^(?:{$ectx_ext}{$tag} ) { my @atts; for my $ectx_att ( @{ECTX_SPEC->{$ectx_ext}{$tag}[1]} ) { if ( $attr and $attr =~ /\b$ectx_att\s*=\s*(["'])([^"']*?)\1/ ) { my $aval = $2; push @atts, [$ectx_att, $aval]; } } # Kill all tags in element-context with level higer or equal to this, # and add it to the end. my $clevel = ECTX_SPEC->{$ectx_ext}{$tag}[0]; for ( my $i = 0; $i < @ectx; ++$i ) { if ( $clevel <= $ectx[$i][0] ) { @ectx = @ectx[0 .. ($i - 1)]; last; } } push @ectx, [$clevel, $tag, [@atts]]; } if ( ($tag, $attr) = $string =~ /<$text_string/o ) { my ($attr_comment) = $attr =~ /\bcomment=\"([^\"]*)\"/ if $attr; $context = $attr_comment if $attr_comment; my ($attr_context) = $attr =~ /\bcontext=\"([^\"]*)\"/ if $attr; $context = $attr_context if $attr_context; # It is unlikely that both attributes 'context' and 'comment' # will be present, but if so happens, 'context' has priority. my ($attr_extracomment) = $attr =~ /\bextracomment=\"([^\"]*)\"/ if $attr; push @comments, "i18n: $attr_extracomment" if $attr_extracomment; my ($attr_notr) = $attr =~ /\bnotr=\"([^\"]*)\"/ if $attr; $notr = $attr_notr if $attr_notr; my $nongreedystring = $string; $string =~ s/^.*<$text_string//so; $nongreedystring =~ s/^.*?<$text_string//so; if ($string cmp $nongreedystring) { print STDERR "Warning: Line $origstring in file $file_name has more than one tag to extract on the same line, that is not supported by extractrc\n"; } if ( not $attr or $attr !~ /\/ *$/ ) { $in_text = 1; $start_line_no = $.; } } else { @comments = (); $string = ""; } } next unless $in_text; next unless $string =~ /<\/$text_string/o; my $text = $string; $text =~ s/<\/$text_string.*$//o; if ( $text cmp "" ) { # See if the string should be excluded by trailing element-context. my $exclude_by_ectx = 0; my @rev_ectx = reverse @ectx; for my $ectx_tail (@{&ECTX_EXCLUDE}) { my @rev_ectx_tail = reverse @{$ectx_tail}; my $i = 0; $exclude_by_ectx = (@rev_ectx > 0 and @rev_ectx_tail > 0); while ($i < @rev_ectx and $i < @rev_ectx_tail) { my ($tag, $attr, $aval) = @{$rev_ectx_tail[$i]}; $exclude_by_ectx = (not $tag or ($tag eq $rev_ectx[$i][1])); if ($exclude_by_ectx and $attr) { $exclude_by_ectx = 0; for my $ectx_attr_aval (@{$rev_ectx[$i][2]}) { if ($attr eq $ectx_attr_aval->[0]) { $exclude_by_ectx = $aval ? $aval eq $ectx_attr_aval->[1] : 1; last; } } } last if not $exclude_by_ectx; ++$i; } last if $exclude_by_ectx; } if (($context and $context eq "KDE::DoNotExtract") or ($notr eq "true")) { push @comments, "Manually excluded message at $file_name line $."; } elsif ( $exclude_by_ectx ) { push @comments, "Automatically excluded message at $file_name line $."; } else { (my $norm_fname = $file_name) =~ s/^\.\///; push @comments, "i18n: file: $norm_fname:$."; if ( @ectx ) { # Format element-context. my @tag_gr; for my $tgr (reverse @ectx) { my @attr_gr; for my $agr ( @{$tgr->[2]} ) { #push @attr_gr, "$agr->[0]=$agr->[1]"; push @attr_gr, "$agr->[1]"; # no real nead for attribute name } my $attr = join(", ", @attr_gr); push @tag_gr, "$tgr->[1] ($attr)" if $attr; push @tag_gr, "$tgr->[1]" if not $attr; } my $ectx_str = join ", ", @tag_gr; push @comments, "i18n: ectx: $ectx_str"; } push @comments, "xgettext: no-c-format" if $text =~ /%/o; $dummy_call->($context, $text, @comments); @comments = (); } } else { push @comments, "Skipped empty message at $file_name line $."; } $string =~ s/^.*<\/$text_string//o; $in_text = 0; # Text can be multiline in .ui files (possibly), but we warn about it in XMLGUI .rc files. warn "there is floating in: '$file_name'" if $. != $start_line_no and $file_name =~ /\.rc$/i; } close $fh or warn "Failed to close: '$file_name': $!"; die "parsing error in $file_name" if $in_text; if ($ectx_ext && exists $EXTENSION_VERBATIM_TAGS{$ectx_ext}) { unless ( open $fh, "<", $file_name ) { # warn "Failed to open: '$file_name': $!"; next; } while ( <$fh> ) { chomp; $string .= "\n" . $_; for my $elspec (@{ $EXTENSION_VERBATIM_TAGS{$ectx_ext} }) { my ($tag, $attr, $aval) = @{$elspec}; my $rx; if ($attr and $aval) { $rx = qr/<$tag[^<]*$attr=["']$aval["'][^<]*>(.*)<\/$tag>/s } elsif ($attr) { $rx = qr/<$tag[^<]*$attr=[^<]*>(.*)<\/$tag>/s } else { $rx = qr/<$tag>(.*)<\/$tag>/s } if ($string =~ $rx) { # Add comment before any line that has an i18n substring in it. my @matched = split /\n/, $1; my $mlno = $.; (my $norm_fname = $file_name) =~ s/^\.\///; for my $mline (@matched) { # Assume verbatim code is in language given by --language. # Therefore format only comment, and write code line as-is. if ($mline =~ /i18n/) { $dummy_call->(undef, undef, ("i18n: file: $norm_fname:$mlno")); } $mline = unescape_xml($mline); print "$mline\n"; ++$mlno; } $string = ""; } } } close $fh or warn "Failed to close: '$file_name': $!"; } } kraft-1.1/src/filelicense.txt000066400000000000000000000017401450127457600163110ustar00rootroot00000000000000/*************************************************************************** - ------------------- begin : Son Nov 11 2010 copyright : (C) 2010 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ kraft-1.1/src/filterheader.cpp000066400000000000000000000064451450127457600164370ustar00rootroot00000000000000/*************************************************************************** filterheader.cpp ------------------- copyright : (C) 2005 by Cornelius Schumacher (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "filterheader.h" #include #include #include #include #include #include #include #include #include #include #include FilterHeader::FilterHeader(QWidget *parent , QTreeWidget *listView) : QWidget( parent ), _treeWidget(listView) { QBoxLayout *filterLayout = new QHBoxLayout; setLayout(filterLayout); QLabel *label = new QLabel( i18n("&Search:")); filterLayout->addWidget( label ); mSearchLine = new QLineEdit( this ); mSearchLine->setClearButtonEnabled(true); label->setBuddy(mSearchLine); connect( mSearchLine, SIGNAL(textChanged(QString) ), SLOT( slotTextChanged(QString) ) ); filterLayout->addWidget( mSearchLine ); } void FilterHeader::slotTextChanged( const QString& filter ) { if( ! _treeWidget ) { return; } QTreeWidgetItemIterator it(_treeWidget); while (*it) { // items without parent are root items. Never hide. QTreeWidgetItem *item = (*it); if( item->parent() ) { bool showIt = false; for(int i = 0; !showIt && i < item->columnCount(); i++) { if( item->text(i).contains(filter, Qt::CaseInsensitive)) { showIt = true; } } item->setHidden(!showIt); if( showIt && ! filter.isEmpty() ) { // Make sure that all the parent items are visible too QTreeWidgetItem *parent = nullptr, *child = item; while((parent = child->parent()) != nullptr) { parent->setHidden(false); if( !parent->isExpanded() ) { parent->setExpanded(true); _openedItems[parent] = 1; } child = parent; } } if (filter.isEmpty()) { for( auto item : _openedItems.uniqueKeys()) { item->setExpanded(false); } _openedItems.clear(); } } ++it; } } void FilterHeader::setListView( QTreeWidget* view ) { _treeWidget = view; } void FilterHeader::clear() { mSearchLine->clear(); } kraft-1.1/src/filterheader.h000066400000000000000000000031711450127457600160750ustar00rootroot00000000000000/*************************************************************************** filterheader.h ------------------- copyright : (C) 2005 by Cornelius Schumacher (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef FILTERHEADER_H #define FILTERHEADER_H #include #include #include #include "kraftcat_export.h" class QTreeWidget; class QLabel; class QString; class KRAFTCAT_EXPORT FilterHeader : public QWidget { Q_OBJECT public: FilterHeader(QWidget *parent = 0, QTreeWidget *tree = 0); public slots: void clear(); void setListView( QTreeWidget* ); private slots: void slotTextChanged( const QString& filter ); private: QLineEdit *mSearchLine; QLabel *mTitleLabel; QTreeWidget *_treeWidget; QHash _openedItems; }; #endif kraft-1.1/src/fixcalcdialog.cpp000066400000000000000000000045251450127457600165670ustar00rootroot00000000000000/*************************************************************************** zeitcalcdialog - ------------------- begin : 2004-23-09 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include // include files for KDE #include #include "fixcalcdialog.h" #include "fixcalcpart.h" #include "stdsatzman.h" #include "defaultprovider.h" FixCalcDialog::FixCalcDialog(QWidget *parent) :CalcDialogBase(parent), _fixWidget(new Ui_calcdetailFix), m_part(0) { setWindowTitle( i18n("Calculation Fix Item")); _fixWidget->setupUi(_centralWidget); _fixWidget->m_inpPreis->setSuffix( DefaultProvider::self()->currencySymbol() ); } void FixCalcDialog::setCalcPart( FixCalcPart *cp ) { if( ! cp ) return; m_part = cp; _fixWidget->m_nameEdit->setText( cp->getName()); _fixWidget->m_inpMenge->setValue( cp->getMenge()); _fixWidget->m_inpPreis->setValue(cp->unitPreis().toDouble()); } void FixCalcDialog::accept() { if( m_part ) { m_part->setMenge( _fixWidget->m_inpMenge->value() ); m_part->setName( _fixWidget->m_nameEdit->text()); m_part->setUnitPreis(Geld(_fixWidget->m_inpPreis->value())); } if( m_part && m_part->isDirty() ) { emit fixCalcPartChanged(m_part); } CalcDialogBase::accept(); } QString FixCalcDialog::getName() { return _fixWidget->m_nameEdit->text(); } double FixCalcDialog::getMenge() { return _fixWidget->m_inpMenge->value(); } double FixCalcDialog::getPreis() { return _fixWidget->m_inpPreis->value(); } /* END */ kraft-1.1/src/fixcalcdialog.h000066400000000000000000000030561450127457600162320ustar00rootroot00000000000000/*************************************************************************** fixcalcdialog - ------------------- begin : 2004-23-09 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _FIXCALCDIALOG_H #define _FIXCALCDIALOG_H #include #include "calcdialogbase.h" #include "ui_fixpartui.h" // designer file zeitpartui.ui /** * */ class FixCalcPart; class FixCalcDialog : public CalcDialogBase { Q_OBJECT public: FixCalcDialog(QWidget *parent=0); QString getName(); double getMenge(); double getPreis(); void setCalcPart( FixCalcPart* ); signals: void fixCalcPartChanged(FixCalcPart*); protected slots: void accept(); private: Ui_calcdetailFix *_fixWidget; FixCalcPart *m_part; }; #endif /* END */ kraft-1.1/src/fixcalcpart.cpp000066400000000000000000000034051450127457600162720ustar00rootroot00000000000000/*************************************************************************** fixcalcpart.cpp - ------------------- begin : Don Jan 1 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "fixcalcpart.h" FixCalcPart::FixCalcPart() :CalcPart(), m_amount( 0 ) { } FixCalcPart::FixCalcPart(QString name, Geld preis, int prozent ) : CalcPart(name, prozent), m_fixPreis(preis), m_amount(1.0) { // setProzentPlus(prozent); } void FixCalcPart::setMenge( double val ) { if( val != m_amount ) { m_amount = val; setDirty(true); } } QString FixCalcPart::getType() const { return KALKPART_FIX; } Geld FixCalcPart::unitPreis() { return m_fixPreis; } void FixCalcPart::setUnitPreis( Geld g ) { if( g != m_fixPreis ) { m_fixPreis = g; setDirty(true); } } FixCalcPart::~FixCalcPart() { } Geld FixCalcPart::basisKosten() { Geld g = m_fixPreis; g = (Geld) m_fixPreis*m_amount; return g; } kraft-1.1/src/fixcalcpart.h000066400000000000000000000031521450127457600157360ustar00rootroot00000000000000/*************************************************************************** fixcalcpart.h - ------------------- begin : Don Jan 1 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef FIXCALCPART_H #define FIXCALCPART_H #include "calcpart.h" /**Implementiert einen fixen Betrag pro kalkulierter Einheit. *@author Klaas Freitag */ class FixCalcPart : public CalcPart { public: FixCalcPart(); FixCalcPart( QString name, Geld preis, int prozent = 0); ~FixCalcPart(); virtual Geld basisKosten(); /* der Preis fr eine Einheit */ Geld unitPreis(); void setUnitPreis( Geld ); void setMenge(double); double getMenge() const { return m_amount; } QString getType() const; private: // Private attributes /** */ Geld m_fixPreis; double m_amount; }; #endif kraft-1.1/src/fixpartui.ui000066400000000000000000000075011450127457600156410ustar00rootroot00000000000000 calcdetailFix 0 0 321 137 Calculation Parts Fix <h1>Fix Cost Parts</h1> false Add a fix cost for one unit of the template: Qt::AlignVCenter false &Label: false m_nameEdit describing text amortisation &Amount: false m_inpMenge amount multiplier 99999.000000000000000 1.000000000000000 at &Price: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false m_inpPreis Price for one piece 99999.000000000000000 10.000000000000000 999999 m_nameEdit m_inpMenge m_inpPreis kraft-1.1/src/floskel.cpp000066400000000000000000000020601450127457600154250ustar00rootroot00000000000000/*************************************************************************** floskel.cpp - ------------------- begin : Mit Dez 31 2003 copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "floskel.h" Floskel::Floskel(){ } Floskel::~Floskel(){ } kraft-1.1/src/floskel.h000066400000000000000000000023611450127457600150760ustar00rootroot00000000000000/*************************************************************************** floskel.h - ------------------- begin : Mit Dez 31 2003 copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef FLOSKEL_H #define FLOSKEL_H #include #include "kraftglobals.h" #include "einheit.h" /** *@author Klaas Freitag */ class Floskel { public: Floskel(); ~Floskel(); private: QString text; Einheit einheit; }; #endif kraft-1.1/src/floskeltemplate.cpp000066400000000000000000000274771450127457600172040ustar00rootroot00000000000000/*************************************************************************** floskeltemplate.cpp - ------------------- begin : Don Jan 1 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include "kraftdb.h" #include "templatesaverbase.h" #include "templatesaverdb.h" #include "floskeltemplate.h" #include "unitmanager.h" #include "calcpart.h" #include "materialcalcpart.h" #include "fixcalcpart.h" #include "timecalcpart.h" #include "stockmaterial.h" FloskelTemplate::FloskelTemplate() : CatalogTemplate(), mTemplId(-1), m_chapter(0), mTimeAdd(true), m_listViewItem(0), m_saver(0) { m_calcType = Calculation; } FloskelTemplate::FloskelTemplate( int tID, const QString& text, int einheit, int chapter, int calcKind ) : CatalogTemplate(), mTemplId(tID), m_chapter(chapter), mTimeAdd(true), m_preis(long(0)), m_listViewItem(0), m_saver(0) { if( calcKind == 1 ) { setCalculationType( ManualPrice ); } else if( calcKind == 2 ) { setCalculationType( Calculation ); } else if ( calcKind == 3 ) { setCalculationType( AutoCalc ); } setText( text ); this->setUnitId(einheit); setChapterId( dbID(chapter), false ); } FloskelTemplate::FloskelTemplate( FloskelTemplate& templ ) : CatalogTemplate( templ ), mTemplId( templ.mTemplId ), m_preis( templ.m_preis ), m_listViewItem(templ.m_listViewItem ), m_saver( 0 ) { deepCopyCalcParts( templ ); setModifyDate( templ.modifyDate() ); setEnterDate( templ.enterDate() ); setText( templ.getText() ); setUnitId(templ.unit().id()); // m_calcParts.setAutoDelete(true); } FloskelTemplate& FloskelTemplate::operator= ( FloskelTemplate& src ) { if ( this == &src ) return *this; mText = src.mText; setUnitId(src.unit().id()); mTemplId = src.mTemplId; mChapterId = src.mChapterId; m_preis = src.m_preis; m_listViewItem = src.m_listViewItem; m_saver = 0; // src.m_saver; deepCopyCalcParts( src ); return *this; } FloskelTemplate::~FloskelTemplate() { delete m_saver; } void FloskelTemplate::deepCopyCalcParts( FloskelTemplate& templ ) { CalcPart *cp = 0; m_calcParts.clear(); QListIterator i( templ.m_calcParts ); while( i.hasNext()) { cp = i.next(); CalcPart *ncp = 0; if( cp->getType() == KALKPART_TIME ) { ncp = new TimeCalcPart( *( static_cast(cp) ) ); } else if( cp->getType() == KALKPART_FIX ) { ncp = new FixCalcPart( *( static_cast(cp) ) ); } else if( cp->getType() == KALKPART_MATERIAL ) { ncp = new MaterialCalcPart( *( static_cast(cp) ) ); } else { // qDebug () << "ERROR: Unknown Calculation-Type!"; } m_calcParts.append( ncp ); } } void FloskelTemplate::setBenefit( double g ) { /* Every calc part has an value for benefit. Set the benefit value for each calc part, later on each can have its own value */ for( auto *cp: m_calcParts) { cp->setProzentPlus(g); } } double FloskelTemplate::getBenefit( ) { bool first = true; double b = 0.0; for( auto *cp: m_calcParts) { if( first ) { b = cp->getProzentPlus(); first = false; } // all benefits are the same atm, thus this ASSERT. Q_ASSERT( fabs(b - cp->getProzentPlus()) < std::numeric_limits::epsilon()); } return b; } void FloskelTemplate::setTemplID( int newID ) { mTemplId = newID; } Geld FloskelTemplate::unitPrice() { return calcPreis(); } Geld FloskelTemplate::calcPreis() { Geld g; if( calcKind() == ManualPrice ) { g = m_preis; } else { g = m_calcParts.calcPrice(); double b = getBenefit(); g += g.percent(b); } return g; } CalcPartList FloskelTemplate::getCalcPartsList() { return getCalcPartsList(ALL_KALKPARTS); } // Returns a calcpartlist where all calcparts have lost their connection // to the database from the dbID POV. That's needed for the transition // from template -> document calculations. CalcPartList FloskelTemplate::decoupledCalcPartsList() { return m_calcParts.decoupledCalcPartsList(); } CalcPartList FloskelTemplate::getCalcPartsList( const QString& calcPart ) { return m_calcParts.getCalcPartsList( calcPart ); } void FloskelTemplate::addCalcPart( CalcPart* cpart ) { m_calcParts.append(cpart); } void FloskelTemplate::removeCalcPart( CalcPart *cpart ) { if( cpart) { cpart->setToDelete(true); cpart->setDirty(true); } } void FloskelTemplate::clearCalcParts() { for(int i=0; isaveTemplate( this ); } else { // qDebug () << "ERR: No saver available!"; return false; } } void FloskelTemplate::saveChapterId() { TemplateSaverBase *saver = getSaver(); if( saver ) { saver->saveTemplateChapter( this ); } } #if 0 QDomElement FloskelTemplate::toXML( QDomDocument& doc) { QDomElement templ = doc.createElement("template"); templ.appendChild( createDomNode(doc, "unit", getUnit().einheitSingular())); templ.appendChild( createDomNode(doc, "text", getText())); templ.appendChild( createDomNode(doc, "id", QString::number(getTemplID()))); templ.appendChild( createDomNode(doc, "benefit", QString::number(getBenefit()))); templ.appendChild( createDomNode(doc, "timecount", hasTimeslice() ? "yes": "no" )); QDomElement calcParts = doc.createElement( "calcParts" ); templ.appendChild(calcParts); fixPartsToXML(doc, calcParts); timePartsToXML(doc, calcParts); materialPartsToXML(doc, calcParts); /* Material Calculation Parts */ materialPartsToXML(doc); CalcPartList tpList = getCalcPartsList(KALKPART_MATERIAL); MaterialCalcPart *mc = 0; mc = static_cast(tpList.first()); for( ; mc; mc = static_cast(tpList.next()) ) { QDomElement calcPart = doc.createElement( "MaterialCalcpart" ); calcParts.appendChild(calcPart); calcPart.appendChild(createDomNode(doc, "name", mc->getName())); calcPart.appendChild(createDomNode(doc, "dbid", mc->getDbID().toString())); StockMaterialList materials = mc->getCalcMaterialList(); StockMaterialListIterator it( materials ); StockMaterial *mat=0; while ( (mat = it.current()) != 0 ) { ++it; QDomElement matElem = doc.createElement("Material"); matElem.appendChild(createDomNode(doc, "MatName", mat->getName())); QString h; h = h.setNum(mc->getCalcAmount(mat)); matElem.appendChild(createDomNode(doc, "Amount", h)); matElem.appendChild(createDomNode(doc, "PriceSum", mc->getPriceForMaterial(mat).toString())); matElem.appendChild(createDomNode(doc, "CostSum", mc->getCostsForMaterial(mat).toString())); matElem.appendChild(createDomNode(doc, "Price", mat->salesPrice().toString())); matElem.appendChild(createDomNode(doc, "Cost", mat->purchPrice().toString())); Einheit e = mat->getUnit(); h = e.einheitSingular(); matElem.appendChild(createDomNode(doc, "Unit", h)); calcPart.appendChild(matElem); } } return templ; } void FloskelTemplate::fixPartsToXML( QDomDocument& doc, QDomElement& calcParts ) { CalcPartList tpList = getCalcPartsList(KALKPART_FIX); FixCalcPart *fc = 0; fc = static_cast(tpList.first()); for( ; fc; fc = static_cast(tpList.next()) ) { QDomElement calcPart = doc.createElement("FixCalcPart"); calcParts.appendChild(calcPart); calcPart.appendChild(createDomNode(doc, "name", fc->getName())); calcPart.appendChild(createDomNode(doc, "dbid", fc->getDbID().toString())); QString h; h.setNum(fc->getMenge()); calcPart.appendChild(createDomNode(doc, "amount", h)); Geld g = fc->unitPreis(); calcPart.appendChild(createDomNode(doc, "price", g.toString( mLocale ))); } } void FloskelTemplate::timePartsToXML( QDomDocument& doc, QDomElement& calcParts ) { CalcPartList tpList = getCalcPartsList(KALKPART_TIME); TimeCalcPart *tc = 0; tc = static_cast(tpList.first()); for( ; tc; tc = static_cast(tpList.next()) ) { QDomElement calcPart = doc.createElement("TimeCalcPart"); calcParts.appendChild(calcPart); calcPart.appendChild(createDomNode(doc, "name", tc->getName())); calcPart.appendChild(createDomNode(doc, "dbid", tc->getDbID().toString())); QString h; h.setNum( tc->getMinuten()); calcPart.appendChild(createDomNode(doc, "minutes", h)); StdSatz ss = tc->getStundensatz(); calcPart.appendChild(createDomNode(doc, "stundensatz", ss.getName())); calcPart.appendChild(createDomNode(doc, "globalHourSetup", tc->globalStdSetAllowed() ? "yes" : "no")); } } void FloskelTemplate::materialPartsToXML( QDomDocument& doc, QDomElement& calcParts ) { /* Material Calculation Parts */ CalcPartList tpList = getCalcPartsList(KALKPART_MATERIAL); MaterialCalcPart *mc = 0; mc = static_cast(tpList.first()); for( ; mc; mc = static_cast(tpList.next()) ) { QDomElement calcPart = doc.createElement( "MaterialCalcpart" ); calcParts.appendChild(calcPart); calcPart.appendChild(createDomNode(doc, "name", mc->getName())); calcPart.appendChild(createDomNode(doc, "dbid", mc->getDbID().toString())); StockMaterialList materials = mc->getCalcMaterialList(); StockMaterialListIterator it( materials ); StockMaterial *mat=0; while ( (mat = it.current()) != 0 ) { ++it; QDomElement matElem = doc.createElement("Material"); matElem.appendChild(createDomNode(doc, "MaterialName", mat->name())); QString h; h = h.setNum(mc->getCalcAmount(mat)); matElem.appendChild(createDomNode(doc, "Amount", h)); matElem.appendChild(createDomNode(doc, "Price", mc->getCostsForMaterial(mat).toString())); Einheit e = mat->getUnit(); h = e.einheitSingular(); matElem.appendChild(createDomNode(doc, "Unit", h)); calcPart.appendChild(matElem); } } } QDomElement FloskelTemplate::createDomNode( QDomDocument doc, const QString& name, const QString& value) { QDomElement elem = doc.createElement(name); QDomText text = doc.createTextNode(value); elem.appendChild(text); return elem; } #endif kraft-1.1/src/floskeltemplate.h000066400000000000000000000066511450127457600166400ustar00rootroot00000000000000/*************************************************************************** floskeltemplate.h - ------------------- begin : Don Jan 1 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef FLOSKELTEMPLATE_H #define FLOSKELTEMPLATE_H #include #include #include #include #include "kraftglobals.h" #include "einheit.h" #include "calcpart.h" #include "catalogtemplate.h" /** *@author Klaas Freitag */ class QTreeWidgetItem; class TemplateSaverBase; class QDomDocument; class QDomElement; class FloskelTemplate: public CatalogTemplate { public: FloskelTemplate(); FloskelTemplate(int tID, const QString& text, int einheit, int chapter, int calcKind ); FloskelTemplate( FloskelTemplate& ); virtual ~FloskelTemplate(); /** No descriptions */ void setManualPrice( Geld p ) { m_preis = p; } Geld manualPrice() { return m_preis; } Geld unitPrice(); Geld costsByCalcPart( const QString& part); void addCalcPart( CalcPart* cpart ); void removeCalcPart( CalcPart *cpart ); void clearCalcParts(); CalcPartList getCalcPartsList(); CalcPartList getCalcPartsList(const QString& ); CalcPartList decoupledCalcPartsList(); void setBenefit( double ); double getBenefit(); int getTemplID() { return mTemplId; } void setTemplID( int ); bool hasTimeslice() { return mTimeAdd; } void setHasTimeslice(bool ts) { mTimeAdd = ts; } void setListViewItem( QTreeWidgetItem *it ) { m_listViewItem = it; } QTreeWidgetItem* getListViewItem() { return m_listViewItem; } virtual bool save(); // virtual QDomElement toXML( QDomDocument&); FloskelTemplate& operator= ( FloskelTemplate& ); protected: virtual TemplateSaverBase* getSaver(); virtual void deepCopyCalcParts( FloskelTemplate& ); void saveChapterId(); private: // Private methods #if 0 QDomElement createDomNode( QDomDocument, const QString&, const QString&); void materialPartsToXML( QDomDocument&, QDomElement& ); void fixPartsToXML( QDomDocument&, QDomElement& ); void timePartsToXML( QDomDocument&, QDomElement& ); #endif virtual Geld calcPreis(); int mTemplId; // Database ID int m_chapter; CalcPartList m_calcParts; bool mTimeAdd; Geld m_preis; // preis only valid for manual calculation. QTreeWidgetItem *m_listViewItem; TemplateSaverBase *m_saver; /** */ }; class FloskelTemplateList :public QList { public: FloskelTemplateList() { } }; typedef QListIterator FloskelTemplateListIterator; #endif kraft-1.1/src/flostempldialog.cpp000066400000000000000000000600751450127457600171650ustar00rootroot00000000000000/*************************************************************************** flostempldialog - dialog to edit templates ------------------- begin : 2004-15-08 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include #include #include #include #include #include #include #include #include #include // include files for KDE #include #include #include #include #include "floskeltemplate.h" #include "catalogtemplate.h" #include "flostempldialog.h" #include "unitmanager.h" #include "timecalcpart.h" #include "fixcalcpart.h" #include "portal.h" #include "materialcalcpart.h" #include "matcalcdialog.h" #include "stockmaterial.h" #include "timecalcdialog.h" #include "fixcalcdialog.h" #include "stdsatzman.h" #include "katalogman.h" #include "katalog.h" #include "materialselectdialog.h" #include "defaultprovider.h" FlosTemplDialog::FlosTemplDialog( QWidget *parent, bool modal ) : QDialog( parent ), m_template(0), m_katalog(0), m_fixCalcDia(0), m_timePartDialog(0), m_matPartDialog(0) { QWidget *w = new QWidget( this ); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(w); setupUi( w ); setWindowTitle( i18n("Create or Edit Template Items") ); setModal( modal ); _buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = _buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(_buttonBox); okButton->setDefault(true); //Initialise the buttongroup to switch between manual and calculated price m_gbPriceSrc = new QButtonGroup(this); m_gbPriceSrc->addButton(m_rbManual, 0); m_gbPriceSrc->addButton(m_rbCalculation, 1); m_timeParts->header()->setSectionResizeMode(QHeaderView::ResizeToContents); m_fixParts->header()->setSectionResizeMode(QHeaderView::ResizeToContents); m_matParts->header()->setSectionResizeMode(QHeaderView::ResizeToContents); // disable for now, not used cbMwst->setVisible(false); m_mwstLabel->setVisible(false); setupConnections(); setButtonIcons(); } void FlosTemplDialog::setupConnections() { connect(m_gbPriceSrc, SIGNAL(buttonClicked(int)), this, SLOT(slCalcOrFix(int))); /* connect a value Changed signal of the manual price field */ connect( m_manualPriceVal, SIGNAL( valueChanged(double)), this, SLOT( slManualPriceChanged(double))); connect( m_text, SIGNAL(textChanged()),this, SLOT(slSetNewText())); connect( spBenefit, SIGNAL(valueChanged(int)), this, SLOT(slBenefitChange(int))); //Time calculation connect(m_butAddTime, SIGNAL(clicked()), this, SLOT(slAddTimePart())); connect(m_butEditTime, SIGNAL(clicked()), this, SLOT(slEditTimePart())); connect(m_butRemoveTime, SIGNAL(clicked()), this, SLOT(slRemoveTimePart())); //Fix costs connect(m_butAddFix, SIGNAL(clicked()), this, SLOT(slAddFixPart())); connect(m_butEditFix, SIGNAL(clicked()), this, SLOT(slEditFixPart())); connect(m_butRemoveFix, SIGNAL(clicked()), this, SLOT(slRemoveFixPart())); //Material connect(m_butAddMat, SIGNAL(clicked()), this, SLOT(slAddMatPart())); connect(m_butEditMat, SIGNAL(clicked()), this, SLOT(slEditMatPart())); connect(m_butRemoveMat, SIGNAL(clicked()), this, SLOT(slRemoveMatPart())); } void FlosTemplDialog::setButtonIcons() { m_butAddTime->setIcon(DefaultProvider::self()->icon("plus")); m_butEditTime->setIcon(DefaultProvider::self()->icon("edit")); m_butRemoveTime->setIcon(DefaultProvider::self()->icon("minus")); m_butAddFix->setIcon(DefaultProvider::self()->icon("plus")); m_butEditFix->setIcon(DefaultProvider::self()->icon("edit")); m_butRemoveFix->setIcon(DefaultProvider::self()->icon("minus")); m_butAddMat->setIcon(DefaultProvider::self()->icon("plus")); m_butEditMat->setIcon(DefaultProvider::self()->icon("edit")); m_butRemoveMat->setIcon(DefaultProvider::self()->icon("minus")); } void FlosTemplDialog::setTemplate( FloskelTemplate *t, const QString& katalogname, bool newTempl ) { if( ! t ) return; m_template = t; m_templateIsNew = newTempl; m_katalog = KatalogMan::self()->getKatalog(katalogname); if( m_katalog == 0 ) { // qDebug () << "ERR: Floskel Dialog called without valid Katalog!"; return; } QList chapters = m_katalog->getKatalogChapters( ); QStringList chapNames; foreach( CatalogChapter chap, chapters ) { chapNames.append( chap.name() ); } cbChapter->insertItems(-1, chapNames ); int chapID = t->chapterId().toInt(); QString chap = m_katalog->chapterName(dbID(chapID)); cbChapter->setCurrentIndex(cbChapter->findText( chap )); m_manualPriceVal->setSuffix(m_katalog->locale()->currencySymbol()); /* Text of the template */ m_text->setText( t->getText()); /* Unit */ m_unit->clear(); m_unit->insertItems(-1, UnitManager::self()->allUnits()); m_unit->setCurrentIndex(m_unit->findText( m_template->unit().einheitSingular() )); m_manualPriceVal->setValue( t->unitPrice().toDouble()); /* Kind of Calculation: Manual or calculated? */ _origCalcType = m_template->calcKind(); if( t->calcKind() == CatalogTemplate::ManualPrice ) { slCalcOrFix(0); m_rbManual->setChecked(true); m_rbCalculation->setChecked(false); } else { slCalcOrFix(1); m_rbManual->setChecked(false); m_rbCalculation->setChecked(true); } /* set up the different calculation parts */ setCalcparts(); _calcPartsModified = false; /* set text */ slSetNewText(); m_addTime->setChecked( m_template->hasTimeslice() ); m_text->setFocus(); m_text->selectAll(); } void FlosTemplDialog::setCalcparts( ) { /* time calculation in widget m_timeParts */ CalcPartList tpList = m_template->getCalcPartsList( KALKPART_TIME ); m_timeParts->clear(); QListIterator it( tpList ); while( it.hasNext() ) { TimeCalcPart *cp = static_cast(it.next()); QString stdStd = i18n("No"); if( cp->globalStdSetAllowed() ) stdStd = i18n("Yes"); QTreeWidgetItem *lvItem = new QTreeWidgetItem( m_timeParts ); drawTimeListEntry( lvItem, cp ); mCalcPartDict.insert(lvItem, cp ); } /* Fix calculation parts */ m_fixParts->clear(); tpList = m_template->getCalcPartsList( KALKPART_FIX ); QListIterator fixIt( tpList ); while( fixIt.hasNext() ) { FixCalcPart *fc = static_cast(fixIt.next()); QTreeWidgetItem *lvItem = new QTreeWidgetItem( m_fixParts ); drawFixListEntry( lvItem, fc ); mCalcPartDict.insert( lvItem, fc ); } /* Material calculation */ m_matParts->clear(); tpList = m_template->getCalcPartsList( KALKPART_MATERIAL ); QListIterator matIt( tpList ); while( matIt.hasNext() ) { MaterialCalcPart *mc = static_cast(matIt.next()); QTreeWidgetItem *lvItem = new QTreeWidgetItem( m_matParts ); mCalcPartDict.insert( lvItem, mc ); drawMatListEntry( lvItem, mc ); } } void FlosTemplDialog::refreshPrices() { if( ! m_template ) return; /* assemble the pricing label */ QString t; t = i18n("Calculated Price: "); if( m_template->calcKind() == CatalogTemplate::ManualPrice ) { t = i18n("Manual Price: "); } else if( m_template->calcKind() == CatalogTemplate::Calculation ) { int benefit = spBenefit->value(); QString benefitStr = i18n("(+%1%)", benefit); if( benefit < 0 ) { benefitStr = QLatin1String("")+i18n("%1%", benefit)+QLatin1String(""); } benefitStr += i18n(": "); t += benefitStr; } else { // qDebug () << "ERR: unknown calculation type!"; } m_resPreisName->setText(t); m_resPreisName->setTextFormat(Qt::RichText); /* set Price */ t = m_template->unitPrice().toLocaleString(); m_resultPrice->setText( t ); m_manualPriceVal->setValue( m_template->unitPrice().toDouble() ); /* Price parts per calculation part */ Geld g( m_template->costsByCalcPart( KALKPART_TIME )); m_textTimePart->setText( g.toLocaleString()); g = m_template->costsByCalcPart( KALKPART_FIX ); m_textFixPart->setText( g.toLocaleString()); g = m_template->costsByCalcPart( KALKPART_MATERIAL ); m_textMaterialPart->setText(g.toLocaleString()); // Benefit double b = m_template->getBenefit(); spBenefit->setValue( qRound(b)); } FlosTemplDialog::~FlosTemplDialog( ) { delete m_fixCalcDia; delete m_timePartDialog; delete m_matPartDialog; } // Check if the template was modified in the dialog bool FlosTemplDialog::templModified() { bool modified = false; QString str = m_text->toPlainText(); modified = str != m_template->getText(); modified = modified || (m_unit->currentText() != m_template->unit().einheitSingular()); modified = modified || (m_addTime->isChecked() != m_template->hasTimeslice()); str = spBenefit->cleanText(); bool b; int new_val = str.toInt(&b); modified = modified || ( b && new_val != qRound(m_template->getBenefit())); // calculation kind CatalogTemplate::CalculationType currCalcType = m_template->calcKind(); modified = modified || (currCalcType != _origCalcType); modified = modified || _calcPartsModified; return modified; } void FlosTemplDialog::accept() { if( m_template ) { // qDebug () << "Saving template ID " << m_template->getTemplID(); QString h; h = m_text->toPlainText(); if( h != m_template->getText() ) { // qDebug () << "Template Text dirty -> update"; m_template->setText( h ); } h = m_unit->currentText(); if( h != m_template->unit().einheitSingular()) { // qDebug () << "Template Einheit dirty -> update to " << h; m_template->setUnitId( UnitManager::self()->getUnitIDSingular(h)); } /* count time */ bool c = m_addTime->isChecked(); if( c != m_template->hasTimeslice() ) { m_template->setHasTimeslice(c); } /* benefit */ h = spBenefit->cleanText(); bool b; int new_val = h.toInt(&b); if( b && new_val != qRound(m_template->getBenefit())) { m_template->setBenefit(new_val); // qDebug () << "benefit dirty ->update to " << g; } // Calculationtype int selId = m_gbPriceSrc->checkedId(); CatalogTemplate::CalculationType calcType = CatalogTemplate::Unknown; if( selId == 0 ) { calcType = CatalogTemplate::ManualPrice; } else if( selId == 1 ) { calcType = CatalogTemplate::Calculation; } else { // qDebug () << "ERROR: Calculation type not selected, id is " << selId; } m_template->setCalculationType( calcType ); // reread the manual price double dd = m_manualPriceVal->value(); m_template->setManualPrice( Geld( dd ) ); h = cbChapter->currentText(); // qDebug () << "catalog chapter is " << h; _calcPartsModified = false; if( m_template->save() ) { emit( editAccepted( m_template ) ); KatalogMan::self()->notifyKatalogChange( m_katalog, m_template->getTemplID() ); } else { QMessageBox::warning(0, i18n("Template Error"), i18n("Saving of this template failed, sorry")); } } // qDebug () << "*** Saving finished "; QDialog::accept(); } void FlosTemplDialog::reject() { if(confirmClose() == true) { // let QDialog clean away the dialog. QDialog::reject(); } } void FlosTemplDialog::closeEvent ( QCloseEvent * event ) { if(confirmClose() == false) event->ignore(); else event->accept(); } bool FlosTemplDialog::confirmClose() { if( templModified() ) { QMessageBox msgBox; msgBox.setText(i18n("The template has been modified.")); msgBox.setInformativeText(i18n("Do you want to discard your changes?")); msgBox.setStandardButtons(QMessageBox::Discard | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Cancel); int ret = msgBox.exec(); if( ret == QMessageBox::Cancel ) { return false; } } mCalcPartDict.clear(); m_timeParts->clear (); m_fixParts->clear (); m_matParts->clear (); m_katalog->reload(m_template->getTemplID()); if ( m_templateIsNew ) { // remove the listview item if it was created newly emit editRejected(); } return true; } bool FlosTemplDialog::askChapterChange( FloskelTemplate*, int ) { QMessageBox msgBox; msgBox.setText(i18n( "The catalog chapter was changed for this template.\n" "Do you really want to move the template to the new chapter?")); msgBox.setInformativeText(i18n("Chapter Change")); msgBox.setStandardButtons(QMessageBox::Yes| QMessageBox::No); msgBox.setDefaultButton(QMessageBox::Yes); int ret = msgBox.exec(); return( ret == QMessageBox::Yes); } void FlosTemplDialog::slManualPriceChanged(double dd) { qDebug () << "Changing manual price:" << dd; if( ! m_template ) return; // qDebug () << "Updating manual price!"; m_template->setManualPrice( Geld( dd )); refreshPrices(); } double FlosTemplDialog::benefitValue() { double val = 0; CalcPartList cparts = m_template->getCalcPartsList(); // Currently still all calcparts have the same value of benefit. // once this changes, this needs to be fixed accordingly. if( cparts.size() > 0 ) { val = cparts.at(0)->getProzentPlus(); } return val; } void FlosTemplDialog::slBenefitChange( int newBen ) { int oldBen = qRound(m_template->getBenefit()); if( oldBen != newBen ) { m_template->setBenefit(newBen); refreshPrices(); _calcPartsModified = true; } } void FlosTemplDialog::slAddFixPart() { if( ! m_template ) return; FixCalcDialog dia(this); if( dia.exec() == QDialog::Accepted ) { FixCalcPart *cp = new FixCalcPart( dia.getName(), dia.getPreis()); cp->setMenge( dia.getMenge()); cp->setProzentPlus(benefitValue()); cp->setDirty(true); QTreeWidgetItem *lvItem = new QTreeWidgetItem( m_fixParts); drawFixListEntry( lvItem, cp ); mCalcPartDict.insert( lvItem, cp ); m_template->addCalcPart( cp ); refreshPrices(); _calcPartsModified = true; } } void FlosTemplDialog::slRemoveFixPart() { if( ! m_template || ! m_fixParts ) return; QTreeWidgetItem *item = m_fixParts->currentItem(); if( item ) { CalcPart *cp = mCalcPartDict[item]; if( cp ) { m_template->removeCalcPart(cp); } delete item; refreshPrices(); _calcPartsModified = true; } } void FlosTemplDialog::slEditFixPart() { if( ! m_template || !m_fixParts ) return; // qDebug () << "Edit fix part!"; QTreeWidgetItem *item = m_fixParts->currentItem(); if( item ) { FixCalcPart *cp = static_cast(mCalcPartDict[item]); if( cp ) { m_fixCalcDia = new FixCalcDialog(this); m_fixCalcDia->setCalcPart(cp); connect( m_fixCalcDia, SIGNAL(fixCalcPartChanged(FixCalcPart*)), this, SLOT(slFixCalcPartChanged(FixCalcPart*))); m_fixCalcDia->show(); } } } void FlosTemplDialog::slFixCalcPartChanged(FixCalcPart *cp) { refreshPrices(); _calcPartsModified = true; drawFixListEntry(m_fixParts->currentItem(), cp); } void FlosTemplDialog::slTimeCalcPartChanged(TimeCalcPart *cp) { refreshPrices(); _calcPartsModified = true; drawTimeListEntry(m_timeParts->currentItem(), cp); } void FlosTemplDialog::slAddTimePart() { if( ! m_template ) return; TimeCalcDialog dia(this); if( dia.exec() == QDialog::Accepted ) { TimeCalcPart *cp = new TimeCalcPart( dia.getName(), dia.getDauer(), TimeCalcPart::timeUnitFromString(dia.unitStr()), 0 ); cp->setGlobalStdSetAllowed( dia.allowGlobal()); StdSatz std = StdSatzMan::self()->getStdSatz( dia.getStundensatzName()); cp->setStundensatz( std ); cp->setProzentPlus(benefitValue()); QTreeWidgetItem *lvItem = new QTreeWidgetItem( m_timeParts); drawTimeListEntry( lvItem, cp ); mCalcPartDict.insert( lvItem, cp ); m_template->addCalcPart( cp ); refreshPrices(); _calcPartsModified = true; } } /* * stellt einen TimeCalcPart als ListViewItem dar. Wird gebraucht, wenn das * item neu ist, aber auch beim Editieren */ void FlosTemplDialog::drawTimeListEntry( QTreeWidgetItem *it, TimeCalcPart *cp ) { if( !( it && cp) ) return; it->setText( 0, cp->getName()); it->setText( 1, QString::number(cp->duration()) + QLatin1Char(' ') + TimeCalcPart::timeUnitString(cp->timeUnit())); it->setText( 2, cp->getStundensatz().getName()); it->setText( 3, cp->globalStdSetAllowed() ? i18n("Yes") : i18n("No")); } void FlosTemplDialog::drawFixListEntry( QTreeWidgetItem* it, FixCalcPart *cp ) { if( !( it && cp) ) return; it->setText( 0, DefaultProvider::self()->locale()->toString(cp->getMenge())); it->setText( 1, cp->getName()); it->setText( 2, cp->unitPreis().toLocaleString()); it->setText( 3, cp->basisKosten().toLocaleString()); } void FlosTemplDialog::drawMatListEntry( QTreeWidgetItem *it, MaterialCalcPart *mc ) { it->setText( 0, mc->getName()); it->setText( 1, QString::number(mc->getCalcAmount(), 'f',2)); it->setText( 2, mc->getMaterial()->unit().einheitSingular()); it->setText( 3, mc->basisKosten().toLocaleString()); it->setText( 4, QString::number(mc->getMaterial()->getAmountPerPack(), 'f',2)); it->setText( 5, mc->getMaterial()->salesPrice().toLocaleString()); } void FlosTemplDialog::slRemoveTimePart() { if( ! m_template || !m_timeParts ) return; QTreeWidgetItem *item = m_timeParts->currentItem(); if( item ) { CalcPart *cp = mCalcPartDict[item]; if( cp ) { m_template->removeCalcPart(cp); } delete item; refreshPrices(); _calcPartsModified = true; } } void FlosTemplDialog::slEditTimePart() { if( ! m_template || !m_timeParts ) return; // qDebug () << "Edit time part!"; QTreeWidgetItem *item = m_timeParts->currentItem(); if( item ) { TimeCalcPart *cp = static_cast(mCalcPartDict[item]); if( cp ) { m_timePartDialog = new TimeCalcDialog(this); m_timePartDialog->setTimeCalcPart(cp); connect( m_timePartDialog, SIGNAL(timeCalcPartChanged(TimeCalcPart*)), this, SLOT(slTimeCalcPartChanged(TimeCalcPart*)) ); m_timePartDialog->show(); } else { // qDebug () << "No time calc part found for this item"; } } else { // qDebug () << "No current Item!"; } refreshPrices(); _calcPartsModified = true; } /* * Achtung: slAddMatPart fgt keinen neuen kompletten Materialpart * hinzu, sondern nur ein neues Material zu dem einen, bestehenden * Materialpart. */ void FlosTemplDialog::slAddMatPart() { if( ! m_template ) return; MaterialSelectDialog dia( this ); connect( &dia, SIGNAL( materialSelected( int, double ) ), this, SLOT( slNewMaterial( int, double ) ) ); dia.exec(); } /* * Slot, der aufgerufen wird, wenn im Materialeditor ein Material zur Kalkulation * geschickt wird. */ void FlosTemplDialog::slNewMaterial( int matID, double amount ) { // qDebug () << "Material ID: " << matID; // TODO: Checken, ob der richtige Tab aktiv ist. // TODO: Check if the material is already in the calcpart (is this really needed??) MaterialCalcPart *mc = new MaterialCalcPart(matID, 0, amount); if( mc && ! mc->getMaterial() ) { // the material is still unknown to the catalog because it was just entered // in the material catalog qDebug() << "ERR: MaterialCalcPart without Material!"; return; } if( mc ) { mc->setProzentPlus(benefitValue()); m_template->addCalcPart( mc ); QTreeWidgetItem *lvItem = new QTreeWidgetItem(m_matParts); drawMatListEntry( lvItem, mc ); mCalcPartDict.insert( lvItem, mc ); refreshPrices(); _calcPartsModified = true; } } void FlosTemplDialog::slEditMatPart() { if( ! m_template || !m_matParts ) return; // qDebug () << "Edit Material part!"; QTreeWidgetItem *item = m_matParts->currentItem(); MaterialCalcPart *mc = static_cast( mCalcPartDict[item] ); if( mc ) { m_matPartDialog = new MatCalcDialog( mc, this); connect( m_matPartDialog, SIGNAL(matCalcPartChanged(MaterialCalcPart*)), this, SLOT(slMatCalcPartChanged(MaterialCalcPart*))); m_matPartDialog->setModal(true); m_matPartDialog->show(); } else { // qDebug () << "No such MaterialCalcPart!"; } } void FlosTemplDialog::slMatCalcPartChanged(MaterialCalcPart *mc) { drawMatListEntry(m_matParts->currentItem(), mc); refreshPrices(); _calcPartsModified = true; } void FlosTemplDialog::slRemoveMatPart() { if( ! m_template || ! m_matParts ) return; QTreeWidgetItem *item = m_matParts->currentItem(); if( item ) { CalcPart *cp = mCalcPartDict[item]; if( cp ) { m_template->removeCalcPart(cp); } delete item; refreshPrices(); _calcPartsModified = true; } } /* * Slot for managing the switch from manual to calculated price * and vice versa */ void FlosTemplDialog::slCalcOrFix(int button) { bool ok = true; bool manualEnabled = true; if( button == 0 ) { /* switched to manual price */ if( m_template ) { m_template->setCalculationType( CatalogTemplate::ManualPrice ); } } else if( button == 1 ) { /* switched to calculated */ if( m_template ) { m_template->setCalculationType( CatalogTemplate::Calculation ); } manualEnabled = false; } else { /* unknown knob*/ ok = false; } if( ok ) { m_manualPriceVal->setEnabled( manualEnabled ); m_textTimePart->setEnabled(!manualEnabled); m_textFixPart->setEnabled(!manualEnabled); m_textMaterialPart->setEnabled(!manualEnabled); m_tLabelMat->setEnabled(!manualEnabled); m_tLabelFix->setEnabled(!manualEnabled); m_tLabelTime->setEnabled(!manualEnabled); m_tLabelProfit->setEnabled(!manualEnabled); spBenefit->setEnabled(!manualEnabled); refreshPrices(); } } void FlosTemplDialog::slSetNewText() { QPushButton *okButton = _buttonBox->button(QDialogButtonBox::Ok); if( ! m_text || m_text->toPlainText().isEmpty() ) { okButton->setEnabled(false); } else { okButton->setEnabled(true); } if( m_text ) { const QString t = Portal::textWrap( m_text->toPlainText(), 80, 5 ); const QStringList li = t.split(QLatin1Char('\n')); QString longest; for( const QString& p : li ) { if( p.length() > longest.length() ) longest = p; } QFontMetrics fm(m_textDispFix->font()); int w = 10+fm.width(longest); if( m_textDispTime) { m_textDispTime->setText(t); m_textDispTime->setMinimumWidth(w); } if( m_textDispFix) { m_textDispFix->setText(t); m_textDispFix->setMinimumWidth(w); } if( m_textDispMat) { m_textDispMat->setText(t); m_textDispMat->setMinimumWidth(w); } } } /* END */ kraft-1.1/src/flostempldialog.h000066400000000000000000000072551450127457600166330ustar00rootroot00000000000000/*************************************************************************** flostempldialog - ------------------- begin : 2004-15-08 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _FLOSTEMPLDIALOG_H #define _FLOSTEMPLDIALOG_H // include files #include #include "kraftglobals.h" #include "ui_calctemplate.h" #include "calcpart.h" #include "stockmaterial.h" class FloskelTemplate; class TimeCalcPart; class MaterialCalcPart; class FixCalcPart; class FixCalcDialog; class MatCalcDialog; class TimeCalcDialog; class Katalog; class QDialogButtonBox; class FlosTemplDialog : public QDialog, protected Ui::d_calcTempl { Q_OBJECT public: FlosTemplDialog(QWidget *parent=0, bool modal=false ); virtual ~FlosTemplDialog(); void setTemplate( FloskelTemplate* t, const QString&, bool ); bool templateIsNew() { return m_templateIsNew; }; signals: void takeMaterialAnswer(const QString&); void editAccepted( FloskelTemplate* ); void editRejected(); void chapterChanged(int); public slots: virtual void slAddFixPart(); virtual void slEditFixPart(); virtual void slRemoveFixPart(); virtual void slEditTimePart(); virtual void slAddTimePart(); virtual void slRemoveTimePart(); virtual void slAddMatPart(); virtual void slEditMatPart(); virtual void slRemoveMatPart(); virtual void slCalcOrFix(int); virtual void slBenefitChange(int newBen ); /* slot for adding a new material to the material calculation */ void slNewMaterial( int, double ); void refreshPrices(); void slManualPriceChanged(double ); void slSetNewText(); void setCalcparts(); void slFixCalcPartChanged(FixCalcPart*); void slTimeCalcPartChanged(TimeCalcPart*); void slMatCalcPartChanged(MaterialCalcPart*); virtual void accept(); virtual void reject(); virtual void closeEvent ( QCloseEvent * event ); bool confirmClose(); private: void setupConnections(); void setButtonIcons(); double benefitValue(); bool templModified(); virtual void drawTimeListEntry( QTreeWidgetItem *, TimeCalcPart * ); virtual void drawFixListEntry( QTreeWidgetItem*, FixCalcPart* ); virtual void drawMatListEntry( QTreeWidgetItem*, MaterialCalcPart* ); bool askChapterChange( FloskelTemplate*, int); virtual QString stdMaterialKalcPartName() { return i18n("Calculated material"); } FloskelTemplate *m_template; Katalog *m_katalog; /* dict das qlistviewitems auf calcparts abbildet */ QHash mCalcPartDict; QButtonGroup *m_gbPriceSrc; QDialogButtonBox *_buttonBox; FixCalcDialog *m_fixCalcDia; TimeCalcDialog *m_timePartDialog; MatCalcDialog *m_matPartDialog; bool m_templateIsNew; bool _calcPartsModified; CatalogTemplate::CalculationType _origCalcType; }; #endif /* END */ kraft-1.1/src/footertemplateprovider.cpp000066400000000000000000000060051450127457600205760ustar00rootroot00000000000000/*************************************************************************** footertemplateprovider - template provider classes for footer data like addresses or texts ------------------- begin : 2007-05-02 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include "footertemplateprovider.h" #include "texteditdialog.h" #include "doctext.h" #include "defaultprovider.h" FooterTemplateProvider::FooterTemplateProvider( QWidget *parent ) :TemplateProvider( parent ) { } void FooterTemplateProvider::slotNewTemplate() { // qDebug () << "SlotNewTemplate called!"; TextEditDialog dia( mParent, KraftDoc::Footer ); DocText dt; dt.setTextType( KraftDoc::Footer ); dt.setDocType( mDocType ); dia.setDocText( dt ); if ( dia.exec() ) { // qDebug () << "Successfully edited new text"; DocText dt = dia.docText(); /* save to database */ dbID newId = DefaultProvider::self()->saveDocumentText( dt ); dt.setDbId( newId ); emit newFooterText( dt ); } } void FooterTemplateProvider::slotEditTemplate() { // qDebug () << "SlotEditTemplate called!"; TextEditDialog dia( mParent, KraftDoc::Footer ); /* mCurrentText is set through the slot slotSetCurrentDocText */ DocText dt = currentText(); if ( dt.type() == KraftDoc::Unknown ) { dt.setTextType( KraftDoc::Footer ); dt.setDocType( mDocType ); } dia.setDocText( dt ); if ( dia.exec() ) { // qDebug () << "Successfully edited texts"; DocText dt = dia.docText(); /* write back the listview item stored in the input text */ dt.setListViewItem( currentText().listViewItem() ); /* save to database */ DefaultProvider::self()->saveDocumentText( dt ); // this ends up in the footerselection, slot updateDocText emit updateFooterText( dt ); } } void FooterTemplateProvider::slotDeleteTemplate() { DocText dt = currentText(); emit deleteFooterText( dt ); DefaultProvider::self()->deleteDocumentText( dt ); } void FooterTemplateProvider::slotTemplateToDocument() { // qDebug () << "Moving template to document"; emit footerTextToDocument(currentText(), true); } void FooterTemplateProvider::slotInsertTemplateToDocument() { emit footerTextToDocument(currentText(), false); } kraft-1.1/src/footertemplateprovider.h000066400000000000000000000033551450127457600202500ustar00rootroot00000000000000/*************************************************************************** footertemplateprovider - template provider classes for footer data like addresses or texts ------------------- begin : 2007-05-02 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef FOOTERTEMPLATEPROVIDER_H #define FOOTERTEMPLATEPROVIDER_H #include "templateprovider.h" class QWidget; class DocText; class FooterTemplateProvider : public TemplateProvider { Q_OBJECT public: FooterTemplateProvider( QWidget* ); public slots: void slotNewTemplate() override; void slotEditTemplate() override; void slotDeleteTemplate() override; void slotTemplateToDocument() override; void slotInsertTemplateToDocument() override; signals: void newFooterText( const DocText& ); void updateFooterText( const DocText& ); void footerTextToDocument(const DocText&, bool replace); void deleteFooterText( const DocText& ); }; #endif kraft-1.1/src/format.cpp000066400000000000000000000046431450127457600152670ustar00rootroot00000000000000/*************************************************************************** Simple format functions for double, date etc. ------------------- begin : March 2020 copyright : (C) 2020 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include "format.h" namespace Format { QString localeDoubleToString(double val, const QLocale& loc) { int prec = 0; const QString num = QString::number(val); if( num.contains( QChar('.') ) ) { // there is a decimal point // calculate the precision prec = num.length() - (1+num.lastIndexOf( QChar('.') ) ); if (prec > 3 ) prec = 3; // lets dont go wild } const QString re = loc.toString(val, 'f', prec); return re; } QString toDateString( const QDate& date, const QString& format ) { if (format == Format::DateFormatIso) { return date.toString(Qt::ISODate); } if (format == DateFormatShort || format.isEmpty()) { return date.toString(Qt::DefaultLocaleShortDate); } if (format == DateFormatLong) { return date.toString(Qt::DefaultLocaleLongDate); } if (format == DateFormatRFC) { return date.toString(Qt::RFC2822Date); } if (format == DateFormatGerman) { return date.toString("dd.MM.yyyy"); } return date.toString(format); // good luck! } QString toDateTimeString(const QDateTime& dt, const QString &format) { const QString dateStr = QString("%1, %2:%3").arg(toDateString(dt.date(), format)) .arg(dt.time().hour(), 2, 10, QLatin1Char('0')) .arg(dt.time().minute(), 2, 10, QLatin1Char('0')); return dateStr; } } kraft-1.1/src/format.h000066400000000000000000000043451450127457600147330ustar00rootroot00000000000000/*************************************************************************** Simple format functions for double, date etc. ------------------- begin : March 2020 copyright : (C) 2020 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef FORMAT_H #define FORMAT_H #include class QString; namespace Format { /** * @brief localeDoubleToString - convert a double into a string locale aware. * @param val - the value * @param loc - a locale, if skipped, the default locale is used. * @return the string * * The additional cleverness is that the returned string has the right * precision, ie. it returns "2" for val = 2.00 but "2.23" if val is 2.23. */ QString localeDoubleToString(double val, const QLocale& loc = QLocale()); const QString DateFormatIso = QStringLiteral("ISO"); const QString DateFormatShort = QStringLiteral("Short"); const QString DateFormatLong = QStringLiteral("Long"); const QString DateFormatRFC = QStringLiteral("RFC"); const QString DateFormatGerman = QStringLiteral("German"); /** * @brief toDateString - format date to a given format * @param date - the QDate * @param format - A name of a format (read from settings) or format string * @return the string containing the date. */ QString toDateString(const QDate& date, const QString &format); QString toDateTimeString(const QDateTime& dt, const QString &format); } #endif // FORMAT_H kraft-1.1/src/geld.cpp000066400000000000000000000050741450127457600147110ustar00rootroot00000000000000/*************************************************************************** geld - A class that represents money and supports calculation ------------------- begin : 2004-16-08 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt // include files for KDE #include #include "geld.h" #include "defaultprovider.h" Geld::Geld( ) { m_cent = 0; } Geld::Geld( long l ) { m_cent = l; } Geld::Geld( double g ) { m_cent = qRound(100*g); } Geld& Geld::operator=(const long l) { m_cent = l; return *this; } Geld& Geld::operator=(const double d) { m_cent = qRound( 100.0 * d ); return *this; } Geld& Geld::operator+=(const Geld& g) { m_cent += g.m_cent; return *this; } Geld Geld::operator/(const double divisor) const { // FIXME Geld g( this->m_cent / divisor / 100 ); return g; } Geld Geld::percent( double p ) { Geld g( this->m_cent * p / 100 /100 ); return g; } Geld Geld::operator*(const long mult) const { // FIXME Geld g( this->m_cent * mult / 100); return g; } Geld Geld::operator*(const double mult) const { Geld g(double(this->m_cent) * mult / 100); return g; } bool Geld::operator!=(Geld g) { return g.m_cent != m_cent; } QString Geld::toNumberString() const { double g = m_cent/100.0; return QString::number(g, 'f', 2); } QString Geld::toLocaleString() const { return DefaultProvider::self()->locale()->toCurrencyString(m_cent/100.0); } QString Geld::toHtmlString() const { QString re = toLocaleString(); re.replace( " ", " " ); if ( m_cent < 0 ) { re = QString( "%1" ).arg( re ); } return re; } double Geld::toDouble() const { return m_cent/100.0; } long Geld::toLong() { return m_cent; } Geld::~Geld( ) { } /* END */ kraft-1.1/src/geld.h000066400000000000000000000032651450127457600143560ustar00rootroot00000000000000 /*************************************************************************** geld - ------------------- begin : 2004-16-08 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _GELD_H #define _GELD_H #include "kraftcat_export.h" #include #include class KRAFTCAT_EXPORT Geld { public: Geld(); Geld(long); Geld(double); ~Geld(); Geld& operator=(const long); Geld& operator=(const double); Geld operator/(const double) const; Geld operator*(const long) const; Geld operator*(const double) const; Geld& operator+=(const Geld&); bool operator!=(Geld); Geld percent( double ); QString toLocaleString() const; QString toNumberString() const; QString toHtmlString() const; double toDouble() const; // toLong returns the amount in cents! long toLong(); private: long m_cent; }; #endif /* END */ kraft-1.1/src/grantleetemplate.cpp000066400000000000000000000066331450127457600173350ustar00rootroot00000000000000/*************************************************************************** GrantleeTemplate.cpp - fill a template with text tags ------------------- begin : March 2020 copyright : (C) 2020 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "grantleetemplate.h" #include #include #include #include #include #include #include #include // make this class a QObject to parent the created QObjects in addToMappingHash() // to it. That way, the allocated objects are automatically freed by the Qt mechanism GrantleeFileTemplate::GrantleeFileTemplate( const QString& file) : QObject(), _tmplFileName(file) { } void GrantleeFileTemplate::addToMappingHash( const QString& prefix, const QVariantHash& hash) { QObject *obj; if (prefix.isNull()) { return; } if (_objs.contains(prefix)) { obj = _objs[prefix]; } else { // make the created objects a child of the _p QObject obj = new QObject(this); _objs[prefix] = obj; } QHash::const_iterator i = hash.constBegin(); while (i != hash.constEnd()) { const auto key = i.key(); const auto val = i.value(); obj->setProperty(key.toLocal8Bit().data(), val); i++; } } void GrantleeFileTemplate::addToObjMapping(const QString& key, QObject *obj) { _objs.insert(key, obj); } QString GrantleeFileTemplate::render(bool &ok) const { QScopedPointer engine(new Grantlee::Engine()); QFileInfo fi(_tmplFileName); ok = true; // assume all goes well. auto loader = QSharedPointer::create(); loader->setTemplateDirs( {fi.absolutePath()} ); engine->addTemplateLoader( loader ); QString output; auto t = engine->loadByName(fi.fileName()); if (t->error() != Grantlee::Error::NoError) { ok = false; output = t->errorString(); qDebug() << "Grantlee template load failed:" << output; } if (ok) { Grantlee::Context c; QHash::const_iterator i = _objs.constBegin(); while (i != _objs.constEnd()) { const QString k = i.key(); QObject *obj = i.value(); c.insert(k, obj); ++i; } output = t->render(&c); if (t->error() != Grantlee::Error::NoError) { ok = false; // Rendering error. output = t->errorString(); qDebug() << "Grantlee template err:" << output; } } return output; } kraft-1.1/src/grantleetemplate.h000066400000000000000000000031221450127457600167700ustar00rootroot00000000000000/*************************************************************************** GrantleeTemplate.cpp - fill a template with text tags ------------------- begin : March 2020 copyright : (C) 2020 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef GRANTLEETEMPLATE_H #define GRANTLEETEMPLATE_H #include #include #include #include "texttemplateinterface.h" #include #include class GrantleeFileTemplate : public QObject { Q_OBJECT public: GrantleeFileTemplate( const QString& file); void addToObjMapping(const QString& key, QObject *obj); void addToMappingHash( const QString& prefix, const QVariantHash& hash); QString render(bool &ok) const; private: const QString& _tmplFileName; QHash _objs; }; #endif kraft-1.1/src/headertemplateprovider.cpp000066400000000000000000000056761450127457600205450ustar00rootroot00000000000000/*************************************************************************** headertemplateprovider - template provider classes for header data like addresses or texts ------------------- begin : 2007-05-02 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include "headertemplateprovider.h" #include "texteditdialog.h" #include "doctext.h" #include "defaultprovider.h" HeaderTemplateProvider::HeaderTemplateProvider( QWidget *parent ) :TemplateProvider( parent ) { } void HeaderTemplateProvider::slotNewTemplate() { // qDebug () << "SlotNewTemplate called!"; TextEditDialog dia( mParent, KraftDoc::Header ); DocText dt; dt.setTextType( KraftDoc::Header ); dt.setDocType( mDocType ); dia.setDocText( dt ); if ( dia.exec() ) { // qDebug () << "Successfully edited texts"; DocText dt = dia.docText(); /* save to database */ dbID newId = DefaultProvider::self()->saveDocumentText( dt ); dt.setDbId( newId ); emit newHeaderText( dt ); } } void HeaderTemplateProvider::slotEditTemplate() { // qDebug () << "SlotEditTemplate called!"; TextEditDialog dia( mParent, KraftDoc::Header ); /* mCurrentText is set through the slot slotSetCurrentDocText */ DocText dt = currentText(); if ( dt.type() == KraftDoc::Unknown ) { dt.setTextType( KraftDoc::Header ); dt.setDocType( mDocType ); } dia.setDocText( dt ); if ( dia.exec() ) { // qDebug () << "Successfully edited texts"; DocText dt = dia.docText(); /* write back the listview item stored in the input text */ dt.setListViewItem( currentText().listViewItem() ); /* save to database */ DefaultProvider::self()->saveDocumentText( dt ); emit updateHeaderText( dt ); } } void HeaderTemplateProvider::slotDeleteTemplate() { DefaultProvider::self()->deleteDocumentText( currentText() ); emit deleteHeaderText( currentText() ); } void HeaderTemplateProvider::slotTemplateToDocument() { // qDebug () << "Moving template to document"; emit headerTextToDocument(currentText(), true); } void HeaderTemplateProvider::slotInsertTemplateToDocument() { emit headerTextToDocument(currentText(), false); } kraft-1.1/src/headertemplateprovider.h000066400000000000000000000033471450127457600202030ustar00rootroot00000000000000/*************************************************************************** headertemplateprovider - template provider classes for header data like addresses or texts ------------------- begin : 2007-05-02 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef HEADERTEMPLATEPROVIDER_H #define HEADERTEMPLATEPROVIDER_H #include "templateprovider.h" #include "doctext.h" class QWidget; class HeaderTemplateProvider : public TemplateProvider { Q_OBJECT public: HeaderTemplateProvider( QWidget* ); public slots: void slotNewTemplate() override; void slotEditTemplate() override; void slotDeleteTemplate() override; void slotTemplateToDocument() override; void slotInsertTemplateToDocument() override; signals: void newHeaderText( const DocText& ); void updateHeaderText( const DocText& ); void headerTextToDocument(const DocText&, bool replace); void deleteHeaderText( const DocText& ); private: }; #endif kraft-1.1/src/htmlview.cpp000066400000000000000000000113101450127457600156230ustar00rootroot00000000000000/*************************************************************************** htmlview.cpp - show a html page ------------------- begin : Aug 2006 copyright : (C) 2006 Klaas Freitag (C) 2006 Cornelius Schumacher ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "htmlview.h" #include #include #include #include #include "defaultprovider.h" HtmlView::HtmlView( QWidget *parent ) : QTextBrowser( parent ), mZoomStep( 10 ) { this->setReadOnly(true); this->setOpenLinks(false); // get only the signal below this->setTextInteractionFlags(Qt::NoTextInteraction | Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard); connect (this, SIGNAL(anchorClicked(QUrl)), this, SIGNAL(openUrl(QUrl))); } void HtmlView::setTitle( const QString &title ) { mTitle = title; } void HtmlView::setStylesheetFile( const QString &style ) { const QString file = QString("styles/%1").arg(style); const QString stylesheetFile = DefaultProvider::self()->locateFile(file); if( QFile::exists(stylesheetFile) ) { qDebug () << "Found this stylefile: " << stylesheetFile; mStyles = readStyles(stylesheetFile); } else { qDebug() << "Unable to find stylesheet file "<< style; mStyles.clear(); } } void HtmlView::zoomIn() { // setZoomFactor( zoomFactor() + mZoomStep ); updateZoomActions(); } void HtmlView::zoomOut() { // setZoomFactor( zoomFactor() - mZoomStep ); updateZoomActions(); } void HtmlView::updateZoomActions() { // mZoomInAction->setEnabled( zoomFactor() + mZoomStep <= 300 ); // mZoomOutAction->setEnabled( zoomFactor() - mZoomStep > 100 ); // Prefs::self()->setZoomFactor( zoomFactor() ); } QString HtmlView::topFrame( ) const { QStringList stringList; stringList << QLatin1String(""); stringList << QLatin1String(""); if(!mTitle.isEmpty()) { stringList << QString("%1").arg( mTitle ); } stringList << QLatin1String(""); return stringList.join(QChar('\n')); } QString HtmlView::readStyles(const QString& styleFile) const { QFile file(styleFile); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QString styles; QFileInfo fi(styleFile); const QString base = fi.path()+"/"; QTextStream textStream(&file); while( !textStream.atEnd() ) { QString line = textStream.readLine().trimmed(); if( line.startsWith("background-image:url(") ) { QString relative = line.remove(0, 21); // remove background... relative.prepend(base); line = QString( "background-image:url(%1").arg(relative); } line.append('\n'); styles.append(line); } // qDebug() << "+++++++++++++++++++++++++++++++++++++++++++++" << styles; return styles; } return QString(); } QString HtmlView::bottomFrame() const { const QString t("\n" ""); return t; } void HtmlView::displayContent( const QString& content ) { // on empty content just clear and leave. if( content.isEmpty() ) { this->clear(); return; } const QString out = topFrame() + content + bottomFrame(); const QString s = mStyles; #ifdef QT_DEBUG // this file gets written and removed immediately, so if it should be kept, // set the autoDelete to false QTemporaryFile tempFile("/tmp/kraft_XXXXXX"); // tempFile.setAutoRemove(false); if (tempFile.open()) { const QString fName = tempFile.fileName(); qDebug() << "########## HtmlView output written to" << fName; QTextStream outStream(&tempFile); outStream << s; outStream << "##############"; outStream << out; tempFile.close(); } #endif this->document()->setDefaultStyleSheet(s); setHtml(out); } kraft-1.1/src/htmlview.h000066400000000000000000000035201450127457600152740ustar00rootroot00000000000000 /*************************************************************************** htmlview.h - show a html page ------------------- begin : Aug 2006 copyright : (C) 2006 Klaas Freitag (C) 2006 Cornelius Schumacher ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef HTMLVIEW_H #define HTMLVIEW_H #include #include class QUrl; class HtmlView : public QTextBrowser { Q_OBJECT public: HtmlView( QWidget *parent = 0); QString title() const { return mTitle; } public slots: void setTitle( const QString & ); void setStylesheetFile( const QString & ); void displayContent( const QString& ); void zoomIn(); void zoomOut(); protected: void updateZoomActions(); signals: void openUrl( const QUrl& ); private: QString topFrame() const; QString bottomFrame() const; QString readStyles(const QString &styleFile) const; QString mTitle; QString mInternalUrl; QString mStyles; QAction *mZoomInAction; QAction *mZoomOutAction; int mZoomStep; }; #endif kraft-1.1/src/identity.ui000066400000000000000000000067001450127457600154570ustar00rootroot00000000000000 manualOwnIdentity 0 0 586 428 Form Name: Organization: Street: Post Code: City: Phone: Fax: Mobile Phone: EMail: Website: kraft-1.1/src/importfilter.cpp000066400000000000000000000211011450127457600165030ustar00rootroot00000000000000/*************************************************************************** importfilter.cpp - Import positions into Kraft documents ------------------- begin : Oct 2008 copyright : (C) 2008 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for QT #include #include #include #include #include #include #include #include #include "importfilter.h" #include "unitmanager.h" #include "defaultprovider.h" ImportFilter::ImportFilter() : mStrict( true ) { } bool ImportFilter::readDefinition( const QString& name ) { QString defFile = name; if ( ! name.startsWith( "/" ) ) { QString defFileName = QString( name ).toLower(); QString findFile = kdeStdDirPath() + defFileName; // qDebug () << "KDE StdDir Path: " << findFile; defFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, findFile); if ( defFile.isEmpty() ) { mError = i18n( "Unable to find filter called %1", name ); return false; } } // qDebug () << "Reading definition file " << defFile; QFile f( defFile ); if ( !f.open( QIODevice::ReadOnly ) ) { mError = i18n( "Could not open the definition file!" ); return false; } QTextStream t( &f ); t.setCodec("UTF-8"); while ( !t.atEnd() ) { mDefinition << t.readLine(); } f.close(); return true; } bool ImportFilter::parse() { return true; } bool ImportFilter::recode( const QString& file, const QString& outfile ) { if ( mEncoding.isEmpty() ) return true; QString cmd = DefaultProvider::self()->iconvTool(); if ( QFile::exists( cmd ) ) { QStringList args = QStringList() << "-f" << mEncoding << "-t" << "utf-8" << "-o" << outfile << file; int result = QProcess::execute( cmd, args ); Q_UNUSED(result); // qDebug () << "Recode finished with exit code " << result; return true; } else { // qDebug () << "Recode-tool does not exist!"; } return false; } // ########################################################################### DocPositionImportFilter::DocPositionImportFilter() :ImportFilter( ) { } QString DocPositionImportFilter::kdeStdDirPath() const { QString re = QString::fromLatin1( "kraft/importfilter/positions/" ); return re; } #define FILTER_TAG( x, y ) x bool DocPositionImportFilter::parseDefinition() { bool ret = true; for ( QStringList::Iterator it = mDefinition.begin(); it != mDefinition.end(); ++it ) { QString l = ( *it ).trimmed(); if ( l.isEmpty() || l.startsWith( "#" ) ) { // continue - whitespace.... } else if ( l.startsWith( FILTER_TAG( "amount:", "amount of the item" ), Qt::CaseInsensitive ) ) { mAmount = ( l.right( l.length()-7 ) ).trimmed(); } else if ( l.startsWith( FILTER_TAG( "text:", "The item text" ), Qt::CaseInsensitive ) ) { mText = ( l.right( l.length()-5 ) ).trimmed(); mText.replace( "
            ", QChar( 0x0A ) ); } else if ( l.startsWith( FILTER_TAG( "unit:", "The item unit" ), Qt::CaseInsensitive ) ) { mUnit = ( l.right( l.length()-5 ) ).trimmed(); } else if ( l.startsWith( FILTER_TAG( "unit_price:", "unit price" ), Qt::CaseInsensitive ) ) { mUnitPrice = ( l.right( l.length()-11 ) ).trimmed(); } else if ( l.startsWith( FILTER_TAG( "name:", "The name of the filter" ), Qt::CaseInsensitive ) ) { mName = ( l.right( l.length()-5 ) ).trimmed(); } else if ( l.startsWith( FILTER_TAG( "description:", "The filter description" ), Qt::CaseInsensitive ) ) { mDescription = ( l.right( l.length()-12 ) ).trimmed(); } else if ( l.startsWith( FILTER_TAG("encoding:", "The encoding of the source file" ), Qt::CaseInsensitive ) ) { mEncoding = ( l.right( l.length()-9 ) ).trimmed(); } else if ( l.startsWith( FILTER_TAG( "separator:", "The separator used in the source file" ), Qt::CaseInsensitive ) ) { // qDebug () << "Separator found: " << l.right( l.length()-10 ); mSeparator = ( l.right( l.length()-10 ) ).trimmed(); } else if ( l.startsWith( FILTER_TAG( "tags:", "Comma separated list of tags for one item" ), Qt::CaseInsensitive ) ) { mTags = ( l.right( l.length()-5 ) ).trimmed(); } else { // qDebug () << "WRN: Unknown filter tag found: " << l; if ( mError.isEmpty() ) mError = i18n( "Unknown tags: " ); mError.append( l ); ret = false; } } if ( mSeparator.isEmpty() ) { mSeparator = QString::fromLatin1( ";" ); } return ret; } void DocPositionImportFilter::debugDefinition() { // qDebug () << "Amount: " << mAmount; // qDebug () << "Unit: " << mUnit; // qDebug () << "UnitPrice: " << mUnitPrice; // qDebug () << "Text: " << mText; // qDebug () << "Separator: <" << mSeparator << ">"; } DocPositionList DocPositionImportFilter::import( const QUrl &inFile ) { DocPositionList list; bool copied = false; if( !inFile.isLocalFile() ) return list; QString file( inFile.toLocalFile() ); // in case we have to recode, the source file needs to be copied. bool ok = true; if ( !mEncoding.isEmpty() ) { file += ".tmp"; copied = true; // qDebug () << "Encoding file to " << file; ok = recode( inFile.toLocalFile(), file ); if ( !ok ) { // qDebug () << "Recoding failed!"; mError = i18n( "Could not recode input file!" ); } } QFile f( file ); if ( ! f.exists() ) { // qDebug () << "File " << file << " could not be found!"; mError = i18n( "Unable to open temp file " ) + file; ok = false; } if ( ok ) { if ( !f.open( QIODevice::ReadOnly ) ) { mError = i18n( "Could not open the import source file!" ); ok = false; } } if ( ok ) { QTextStream t( &f ); t.setCodec("UTF-8"); int cnt = 0; while ( !t.atEnd() ) { cnt++; QString l = t.readLine().trimmed(); // qDebug () << "Importing line " << l; if ( !( l.isEmpty() || l.startsWith( "#" ) ) ) { bool ok; DocPosition dp = importDocPosition( l, ok ); if ( ok ) list.append( new DocPosition( dp ) ); } } f.close(); } if ( copied ) { QFile::remove( file ); } return list; } // creates a DocPosition from one line of the imported file DocPosition DocPositionImportFilter::importDocPosition( const QString& l, bool& ok ) { QStringList parts = l.split( mSeparator, QString::KeepEmptyParts ); // qDebug () << "Importing raw line " << l; QString h; ok = true; DocPosition pos; // the text (mandatory) QString t = replaceCOL( parts, mText ); pos.setText( t ); QString unit = replaceCOL( parts, mUnit ); int unitId = UnitManager::self()->getUnitIDSingular( unit ); if ( unitId > -1 ) { pos.setUnit( UnitManager::self()->getUnit( unitId ) ); } else { pos.setUnit(Einheit( unit )); } // Amount. h = replaceCOL( parts, mAmount ); bool convOk = true; double a = h.toDouble( &convOk ); if ( convOk ) { pos.setAmount( a ); } else { // qDebug () << "WRN: Unable to convert amount to double: " << h; if ( mStrict ) ok = false; } // Unit Price h = replaceCOL( parts, mUnitPrice ); a = h.toDouble( &convOk ); if ( convOk ) { pos.setUnitPrice( Geld( a ) ); } else { // qDebug () << "WRN: Unable to convert unit price to double: " << h; if ( mStrict ) ok = false; } if ( !mTags.isEmpty() ) { QStringList tags = mTags.split(QRegExp( "\\s*,\\s*" )); for ( QStringList::Iterator it = tags.begin(); it != tags.end(); ++it ) { QString t = ( *it ).trimmed(); pos.setTag( t ); } } return pos; } QString DocPositionImportFilter::replaceCOL( const QStringList& cols, const QString& in ) { QString re( in ); for ( int i = 0; i < cols.size(); i++ ) { QString replacer = QString( "COL(%1)" ).arg( i+1 ); QString col = cols[i].trimmed(); re.replace( replacer, col, Qt::CaseInsensitive ); } // qDebug() << "replaced line: " << re; return re; } kraft-1.1/src/importfilter.h000066400000000000000000000043771450127457600161700ustar00rootroot00000000000000/*************************************************************************** importfilter.cpp - Import positions into Kraft documents ------------------- begin : Oct 2008 copyright : (C) 2008 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for QT #ifndef _IMPORTFILTER_H #define _IMPORTFILTER_H #include #include #include "docposition.h" class ImportFilter { public: ImportFilter(); virtual ~ImportFilter() { } virtual bool parse(); virtual QString kdeStdDirPath() const = 0; bool readDefinition( const QString& ); QString error() { return mError; } void setStrict( bool _strict ) { mStrict = _strict; } bool strict() { return mStrict; } QString name() { return mName; } QString description() { return mDescription; } protected: bool recode( const QString&, const QString& ); QString mName; QString mDescription; QString mEncoding; QString mError; QString mFilename; QString mSeparator; QString mTags; QStringList mDefinition; bool mStrict; }; class DocPositionImportFilter : public ImportFilter { public: DocPositionImportFilter( ); virtual ~DocPositionImportFilter( ) {} virtual QString kdeStdDirPath() const; bool parseDefinition(); DocPositionList import( const QUrl& ); void debugDefinition(); private: DocPosition importDocPosition( const QString&, bool& ); QString replaceCOL( const QStringList&, const QString& ); QString mAmount; QString mText; QString mUnit; QString mUnitPrice; }; #endif kraft-1.1/src/importitemdialog.cpp000066400000000000000000000141101450127457600173360ustar00rootroot00000000000000/*************************************************************************** importitemdialog.h - small dialog to import items into the document ------------------- begin : Nov 2008 copyright : (C) 2008 Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "importitemdialog.h" // include files for Qt #include #include #include #include #include #include #include #include #include #include #include #include "importfilter.h" #include "defaultprovider.h" #include "kraftsettings.h" #include "tagman.h" ImportItemDialog::ImportItemDialog( QWidget *parent ) : QDialog( parent ) { QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); setObjectName( "IMPORTITEMDIALOG" ); setModal( true ); setWindowTitle( i18n( "Import Items From File" ) ); QWidget *w = new QWidget(this); mBaseWidget = new Ui::importToDocBase; mBaseWidget->setupUi(w); mainLayout->addWidget(w); // Fill the tags list group = new QButtonGroup(this); group->setExclusive(false); QStringList tags = TagTemplateMan::self()->allTagTemplates(); int c = 0; QVBoxLayout *checkboxLayout = new QVBoxLayout; for ( QStringList::Iterator it = tags.begin(); it != tags.end(); ++it ) { QCheckBox *cb = new QCheckBox( *it ); group->addButton(cb, c); checkboxLayout->addWidget(cb); QString desc = TagTemplateMan::self()->getTagTemplate( *it ).description(); cb->setToolTip( desc ); mTagMap[c] = *it; c++; } checkboxLayout->addStretch(2); mBaseWidget->mTagGroup->setLayout(checkboxLayout); connect( mBaseWidget->mSchemaCombo, SIGNAL( activated( const QString& ) ), SLOT( slotSchemaChanged( const QString& ) ) ); QString selectName = readFilterSpecs(); if ( ! KraftSettings::self()->importItemsSchemaName().isEmpty() ) { selectName = KraftSettings::self()->importItemsSchemaName(); } mBaseWidget->mSchemaCombo->setCurrentIndex(mBaseWidget->mSchemaCombo->findText( selectName )); slotSchemaChanged( selectName ); if ( ! KraftSettings::self()->importItemsFileName().isEmpty() ) { mBaseWidget->mFileNameEdit->setText( KraftSettings::self()->importItemsFileName() ); } QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(buttonBox); } ImportItemDialog::~ImportItemDialog() { } QComboBox *ImportItemDialog::getPositionCombo() { return mBaseWidget->dmPositionCombo; } void ImportItemDialog::setPositionList( DocPositionList list, int intendedPos ) { if ( ! getPositionCombo() ) { qCritical() << "Can not get a ptr to the position combo"; return; } QStringList strList; strList << i18n( "the Header of the Document" ); DocPositionListIterator it( list ); while( it.hasNext() ) { DocPositionBase *dpb = it.next(); DocPosition *dp = static_cast( dpb ); QString h = QString( "%1. %2" ).arg( list.posNumber( dp ) ).arg( dp->text() ); if ( h.length() > 50 ) { h = h.left( 50 ); h += i18n( "..." ); } strList.append( h ); } getPositionCombo()->insertItems(-1, strList ); getPositionCombo()->setCurrentIndex( intendedPos ); } QString ImportItemDialog::readFilterSpecs() { QString filter = QString::fromLatin1( "kraft/importfilter/positions/*.ftr" ); QStringList filters = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, filter); QStringList combo; QString firstFilter; for ( QStringList::Iterator it = filters.begin(); it != filters.end(); ++it ) { // qDebug () << " -> Import filter file " << *it; DocPositionImportFilter filter; filter.readDefinition( *it ); filter.parseDefinition(); combo << filter.name(); if( firstFilter.isEmpty() ) firstFilter = filter.name(); mFilterMap[filter.name()] = filter; } mBaseWidget->mSchemaCombo->insertItems(-1, combo ); return firstFilter; } void ImportItemDialog::slotSchemaChanged( const QString& name ) { QString desc = mFilterMap[name].description(); mBaseWidget->mSchemaInfo->setText( desc ); } DocPositionList ImportItemDialog::positionList() { DocPositionList list; QUrl url = QUrl::fromLocalFile(mBaseWidget->mFileNameEdit->text()); if ( ! url.isEmpty() ) { DocPositionImportFilter filter = mFilterMap[mBaseWidget->mSchemaCombo->currentText()]; list = filter.import( url ); // get the tags QStringList tags; QMap::Iterator it; for ( it = mTagMap.begin(); it != mTagMap.end(); ++it ) { QCheckBox *b = static_cast( group->button( it.key() ) ); if ( b->isChecked() ) tags.append( it.value() ); } if ( tags.size() > 0 ) { DocPositionListIterator posIt( list ); while( posIt.hasNext() ) { DocPositionBase *dp = posIt.next(); for ( QStringList::Iterator it = tags.begin(); it != tags.end(); ++it ) { dp->setTag( *it ); } } } } return list; } /* END */ kraft-1.1/src/importitemdialog.h000066400000000000000000000035301450127457600170070ustar00rootroot00000000000000/*************************************************************************** importitemdialog.h - small dialog to import items into the document ------------------- begin : Nov 2008 copyright : (C) 2008 Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef IMPORTITEMDIALOG_H #define IMPORTITEMDIALOG_H #include #include #include #include #include "ui_importtodocbase.h" #include "templtopositiondialogbase.h" #include "docposition.h" #include "importfilter.h" class importToDocBase; class DocPositionList; class ImportItemDialog: public QDialog { Q_OBJECT public: ImportItemDialog( QWidget* ); ~ImportItemDialog(); void setPositionList( DocPositionList, int ); DocPositionList positionList(); QComboBox *getPositionCombo(); signals: void positionImported( const DocPosition& ); protected slots: void slotSchemaChanged( const QString& ); protected: QString readFilterSpecs(); private: Ui::importToDocBase *mBaseWidget; QButtonGroup *group; QMap mFilterMap; QMap mTagMap; }; #endif kraft-1.1/src/importtodocbase.ui000066400000000000000000000113501450127457600170210ustar00rootroot00000000000000 importToDocBase 0 0 524 309 0 0 18 75 true Import Document Items Qt::PlainText false Import information Select a &File to import from: false FixMe! Import &Schema: false mSchemaCombo 0 66 this is interesting information about the selected schema Qt::RichText Qt::AlignTop true 5 Insert all Items &after false dmPositionCombo Tags kraft-1.1/src/impviewwidgets.cpp000066400000000000000000000037471450127457600170520ustar00rootroot00000000000000/*************************************************************************** impviewwidgets.cpp - Improved view widgets ------------------- begin : Sun Nov 29 2009 copyright : (C) 2009 by Klaas Freitag and Thomas Richard email : freitag@kde.org, thomas.richard@proan.be ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include "impviewwidgets.h" ImpTreeView::ImpTreeView(QWidget *parent ) : QTreeView(parent) {} void ImpTreeView::setModel ( QAbstractItemModel * model ) { connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), this, SLOT(headerDataChanged(Qt::Orientation,int,int))); QTreeView::setModel(model); } void ImpTreeView::headerDataChanged(Qt::Orientation orientation, int first, int last) { if(orientation == Qt::Vertical) { for(int i = first; i <= last; ++i) { QVariant sign = model()->headerData(i, orientation); if (sign == QString ("!")) setRowHidden(i, QModelIndex(), true); else setRowHidden(i, QModelIndex(), false); } } } void ImpTreeView::unhideRows() { for(int i = 0; i < model()->rowCount(); ++i) setRowHidden(i, QModelIndex(), false); } kraft-1.1/src/impviewwidgets.h000066400000000000000000000026521450127457600165110ustar00rootroot00000000000000/*************************************************************************** impviewwidgets.h - Improved view widgets ------------------- begin : Sun Nov 29 2009 copyright : (C) 2009 by Klaas Freitag and Thomas Richard email : freitag@kde.org, thomas.richard@proan.be ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef IMPVIEWWIDGETS_H #define IMPVIEWWIDGETS_H #include class QWidget; class QAbstractItemModel; class ImpTreeView : public QTreeView { Q_OBJECT public: ImpTreeView(QWidget *parent = 0); void setModel ( QAbstractItemModel * model ); void unhideRows(); private slots: void headerDataChanged(Qt::Orientation orientation, int first, int last); }; #endif kraft-1.1/src/inserttempldialog.cpp000066400000000000000000000154511450127457600175240ustar00rootroot00000000000000/*************************************************************************** inserttemplatedialog.cpp - small dialog to insert templates into documents ------------------- begin : Sep 2006 copyright : (C) 2006 Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "inserttempldialog.h" // include files for Qt #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_inserttmplbase.h" #include "templtopositiondialogbase.h" #include "katalog.h" #include "einheit.h" #include "unitmanager.h" #include "defaultprovider.h" #include "kraftsettings.h" #include "tagman.h" InsertTemplDialog::InsertTemplDialog( QWidget *parent ) : TemplToPositionDialogBase( parent ) { QWidget *w = new QWidget( this ); mBaseWidget = new Ui::insertTmplBase; mBaseWidget->setupUi( w ); mBaseWidget->dmUnitCombo->insertItems( -1, UnitManager::self()->allUnits() ); mBaseWidget->mPriceVal->setSuffix( DefaultProvider::self()->currencySymbol() ); mBaseWidget->mPriceVal->setMinimum( 0 ); mBaseWidget->mPriceVal->setMaximum( 100000 ); mBaseWidget->mPriceVal->setDecimals( 2 ); mBaseWidget->dmAmount->setDecimals( 2 ); mBaseWidget->dmAmount->setRange( 0, 100000 ); mBaseWidget->dmAmount->setSingleStep( 1 ); // mBaseWidget->dmAmount->setSteps( 1, 10 ); // hide the chapter combo by default mBaseWidget->mKeepGroup->hide(); // Fill the tags list QGroupBox *group = mBaseWidget->mTagGroup; QVBoxLayout *groupLay = new QVBoxLayout; group->setLayout( groupLay ); QStringList tags = TagTemplateMan::self()->allTagTemplates(); int cnt = 0; for ( QStringList::Iterator it = tags.begin(); it != tags.end(); ++it ) { QCheckBox *cb = new QCheckBox( *it ); QString desc = TagTemplateMan::self()->getTagTemplate( *it ).description(); // QToolTip::add( cb, desc ); groupLay->insertWidget( cnt++, cb ); mTagMap[cb] = *it; } groupLay->addStretch(); QVBoxLayout *lay = new QVBoxLayout(this); lay->setMargin(0); lay->addWidget(w); setLayout(lay); connect(mBaseWidget->mButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(mBaseWidget->mButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } void InsertTemplDialog::setDocPosition(DocPosition *dp, bool isNew , bool showPrices) { if ( dp ) { mParkPosition = *dp; mBaseWidget->dmTextEdit->setPlainText( prepareText(mParkPosition.text()) ); mBaseWidget->dmAmount->setValue( mParkPosition.amount() ); mBaseWidget->dmUnitCombo->setCurrentIndex(mBaseWidget->dmUnitCombo->findText( mParkPosition.unit().einheit( 1.0 ))); mBaseWidget->mPriceVal->setValue( mParkPosition.unitPrice().toDouble() ); if ( mParkPosition.text().isEmpty() ) { mBaseWidget->dmHeaderText->setText( i18n( "Create a new Item" ) ); } else { mBaseWidget->dmHeaderText->setText( i18n( "Create a new Item from Template" ) ); } if ( isNew ) { mBaseWidget->dmTextEdit->setFocus(); } else { mBaseWidget->dmAmount->setFocus(); } mBaseWidget->mPriceVal->setVisible(showPrices); mBaseWidget->priceBoxTextLabel->setVisible(showPrices); } } #define QL1(x) QLatin1String(x) QString InsertTemplDialog::prepareText( const QString& input ) { QString in(input); QLocale *locale = DefaultProvider::self()->locale(); QString dateStr = locale->toString( QDate::currentDate() ); in.replace(QL1("{{DATE}}"), dateStr, Qt::CaseInsensitive); QString timeStr = locale->toString(QTime::currentTime()); in.replace(QL1("{{TIME}}"), timeStr, Qt::CaseInsensitive); if( in.contains(QL1("{{USERNAME}}"))) { struct passwd *pw; uid_t uid; uid = geteuid (); pw = getpwuid (uid); if (pw) { in.replace(QL1("{{USERNAME}}"), QString::fromUtf8(pw->pw_gecos), Qt::CaseInsensitive); } } return in; } QComboBox *InsertTemplDialog::getPositionCombo() { return mBaseWidget->dmPositionCombo; } DocPosition InsertTemplDialog::docPosition() { mParkPosition.setText( mBaseWidget->dmTextEdit->toPlainText() ); mParkPosition.setAmount( mBaseWidget->dmAmount->value() ); mParkPosition.setUnitPrice( Geld( mBaseWidget->mPriceVal->value() ) ); int uid = UnitManager::self()->getUnitIDSingular( mBaseWidget->dmUnitCombo->currentText() ); mParkPosition.setUnit( UnitManager::self()->getUnit( uid ) ); // mParkPosition.setPosition( itemPos ); QMapIterator i(mTagMap); while (i.hasNext()) { i.next(); if( i.key()->isChecked() ) { mParkPosition.setTag( i.value() ); } } // qDebug () << "in the dialog: " << mParkPosition.tags(); return mParkPosition; } InsertTemplDialog::~InsertTemplDialog() { QString c = mBaseWidget->mComboChapter->currentText(); if ( ! c.isEmpty() ) { KraftSettings::self()->setInsertTemplChapterName( c ); KraftSettings::self()->save(); } } void InsertTemplDialog::setCatalogChapters( const QList& chapters, const QString& selectedChap) { if ( chapters.count() > 0 ) { QStringList chapterNames; for( CatalogChapter chapter: chapters ) { if (!chapter.name().isEmpty()) chapterNames.append( chapter.name() ); } mBaseWidget->mKeepGroup->show(); mBaseWidget->mComboChapter->insertItems( -1, chapterNames ); QString selChap { selectedChap }; if (!selectedChap.isEmpty()) { mBaseWidget->mKeepGroup->setChecked(true); } else { selChap = KraftSettings::self()->insertTemplChapterName(); } if (!selChap.isEmpty() && chapterNames.contains(selChap)) mBaseWidget->mComboChapter->setCurrentIndex(mBaseWidget->mComboChapter->findText(selChap)); } } // return only a chapter if the checkbox is checked. QString InsertTemplDialog::chapter() const { QString re; if ( mBaseWidget->mKeepGroup->isChecked() ) re = mBaseWidget->mComboChapter->currentText(); return re; } /* END */ kraft-1.1/src/inserttempldialog.h000066400000000000000000000034431450127457600171670ustar00rootroot00000000000000/*************************************************************************** inserttemplatedialog.h - small dialog to insert templates into documents ------------------- begin : Sep 2006 copyright : (C) 2006 Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef INSERTTEMPLDIALOG_H #define INSERTTEMPLDIALOG_H #include #include #include "docposition.h" #include "templtopositiondialogbase.h" #include "ui_inserttmplbase.h" class QCheckBox; class InsertTemplDialog: public TemplToPositionDialogBase { Q_OBJECT public: InsertTemplDialog( QWidget* ); ~InsertTemplDialog(); void setDocPosition( DocPosition*, bool, bool ) override; DocPosition docPosition() override; void setCatalogChapters( const QList&, const QString& selectedChap) override; QString chapter() const override; protected: QComboBox *getPositionCombo() override; private: QString prepareText( const QString& input ); Ui::insertTmplBase *mBaseWidget; DocPosition mParkPosition; QMap mTagMap; }; #endif kraft-1.1/src/inserttmplbase.ui000066400000000000000000000152611450127457600166640ustar00rootroot00000000000000 insertTmplBase 0 0 584 492 0 0 18 75 true Create Item from Template Qt::PlainText false New Item Text &insert false dmAmount 999999.989999999990687 à false 999999.989999999990687 Qt::Horizontal QSizePolicy::Expanding 70 20 &after item false dmPositionCombo Qt::Horizontal QSizePolicy::Preferred 21 20 Keep this item as template for future documents true false 0 0 save in &chapter false mComboChapter Qt::Horizontal QSizePolicy::Preferred 159 20 Tags QDialogButtonBox::Cancel|QDialogButtonBox::Ok kraft-1.1/src/itemtagdialog.cpp000066400000000000000000000115471450127457600166120ustar00rootroot00000000000000/*************************************************************************** postiontagdialog.h - Edit tags of positions ------------------- begin : Aug 2008 copyright : (C) 2008 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "itemtagdialog.h" #include "defaultprovider.h" #include "tagman.h" class TagDelegate : public QItemDelegate { public: TagDelegate( QObject *parent = 0 ); void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const; }; TagDelegate::TagDelegate( QObject *parent ) :QItemDelegate( parent ) { } void TagDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const { //If we're in the color column if(index.column() == 1) { QColor c( index.model()->data(index, Qt::DisplayRole).toString() ); QBrush b( c ); int x = option.rect.left(); int y = option.rect.top(); int height = option.rect.height(); int width = option.rect.width(); qDrawShadeRect( painter, x+5, y+4, width-10, height-8, c, false, 1, 0, &b ); } else { QItemDelegate::paint(painter, option, index); } } // ################################################################################ ItemTagDialog::ItemTagDialog( QWidget *parent ) : QDialog( parent ) { setObjectName( "ITEM_TAG_DIALOG" ); setModal( true ); setWindowTitle( i18n("Edit Item Tags" ) ); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); setMinimumWidth ( 375 ); mainLayout->addWidget( new QLabel( QString::fromLatin1( "

            " ) + i18n( "Item Tags" ) + QString::fromLatin1( "

            " ), this ) ); mainLayout->addWidget( new QLabel( i18n( "Select all tags for the item should be tagged with." ), this) ); mListView = new QTreeWidget( this ); mListView->setAlternatingRowColors( true ); mListView->setItemDelegate(new TagDelegate()); mListView->setContentsMargins ( 3, 3, 3, 3 ); QPalette palette; palette.setColor(QPalette::AlternateBase, QColor( "#dffdd0" )); mListView->setPalette(palette); mListView->setHeaderHidden(true); mListView->setRootIsDecorated( false ); mListView->setColumnCount( 3 ); QStringList headers; headers << i18n( "Tag" ); headers << i18n( "Color" ); headers << i18n( "Description" ); mListView->setHeaderLabels( headers ); mListView->setSelectionMode( QAbstractItemView::NoSelection ); mListView->setColumnWidth(1, 50); mainLayout->addWidget(mListView); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(buttonBox); } ItemTagDialog::~ItemTagDialog() { } void ItemTagDialog::setPositionTags( const QStringList& checkedTags ) { QStringList allTags = TagTemplateMan::self()->allTagTemplates(); foreach( QString string, allTags ) { TagTemplate templ = TagTemplateMan::self()->getTagTemplate( string ); QStringList contents; contents << templ.name(); contents << templ.color().name(); contents << templ.description(); QTreeWidgetItem *item = new QTreeWidgetItem( mListView, contents ); if(checkedTags.contains(templ.name())) item->setCheckState( 0, Qt::Checked ); else item->setCheckState( 0, Qt::Unchecked ); } } QStringList ItemTagDialog::getSelectedTags() { QStringList re; QTreeWidgetItem *item = mListView->topLevelItem( 0 ); while ( item ) { if( item->checkState( 0 ) == Qt::Checked ) { re << item->text( 0 ); } item = mListView->itemBelow( item ); } return re; } kraft-1.1/src/itemtagdialog.h000066400000000000000000000025751450127457600162600ustar00rootroot00000000000000/*************************************************************************** postiontagdialog.h - Edit tags of positions ------------------- begin : Aug 2008 copyright : (C) 2008 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef ITEMTAGDIALOG_H #define ITEMTAGDIALOG_H #include #include class QWidget; class QStringList; class QTreeWidget; class QTreeWidgetItem; class ItemTagDialog: public QDialog { Q_OBJECT public: ItemTagDialog( QWidget* ); virtual ~ItemTagDialog( ); void setPositionTags( const QStringList& checkedTags); QStringList getSelectedTags(); private: QTreeWidget* mListView; QMap mItemMap; }; #endif kraft-1.1/src/katalog.cpp000066400000000000000000000154171450127457600154220ustar00rootroot00000000000000/*************************************************************************** katalog.cpp - Abstrakte Katalogklasse ------------------- begin : Son Feb 8 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include "floskeltemplate.h" #include "dbids.h" #include "katalog.h" #include "kraftdb.h" #include "unitmanager.h" #include "timecalcpart.h" #include "fixcalcpart.h" #include "materialcalcpart.h" #include "defaultprovider.h" #include /** * constructor of a katalog, which is only a list of Floskel templates. * A name must be given, which is displayed for the root element in the * */ Katalog::Katalog(const QString& name): m_name(name), m_setID(-1), m_readOnly( false ), mChapterListNeedsRefresh( true ) { init(); } Katalog::Katalog(): m_setID(-1), m_readOnly( false ), mChapterListNeedsRefresh( true ) { init(); } void Katalog::init() { // FIXME: Catalogs could have their own locale in the future mLocale = DefaultProvider::self()->locale(); } Katalog::~Katalog() { } /** * virtuell load method for catalogs. */ int Katalog::load() { // CREATE TABLE CatalogSet( // catalogSetID INTEGER PRIMARY KEY ASC autoincrement, // name VARCHAR(255), // description VARCHAR(255), // catalogType VARCHAR(64), // sortKey INT NOT NULL // ); // QSqlQuery q; q.prepare("SELECT catalogSetID, description FROM CatalogSet WHERE name = :name"); q.bindValue(":name", m_name); q.exec(); if( q.next() ) { m_setID = q.value(0).toInt(); m_description = q.value(1).toString(); // qDebug () << "Setting catalogSetID=" << m_setID << " from name " << m_name; } return 0; } QList Katalog::getKatalogChapters( bool freshup ) { if( mChapters.empty() || freshup || mChapterListNeedsRefresh ) { mChapters.clear(); // CREATE TABLE CatalogChapters( // chapterID INTEGER PRIMARY KEY ASC autoincrement, // catalogSetID INT NOT NULL, // chapter VARCHAR(255), // sortKey INT NOT NULL // ); QSqlQuery q; q.prepare("SELECT chapterID, chapter, parentChapter, description FROM CatalogChapters WHERE " "catalogSetId = :catalogSetId ORDER BY parentChapter, sortKey"); q.bindValue(":catalogSetId", m_setID); q.exec(); // qDebug () << "Selecting chapters for catalog no " << QString::number( m_setID ); while ( q.next() ) { int chapID = q.value(0).toInt(); QString chapterName = q.value(1).toString(); int parentChapter = q.value(2).toInt(); QString desc = q.value(3).toString(); // qDebug () << "Adding catalog chapter " << chapterName << " with ID " << chapID; CatalogChapter c( chapID, m_setID, chapterName, parentChapter, desc ); mChapters.append( c ); } mChapterListNeedsRefresh = false; } return mChapters; } QString Katalog::chapterName(const dbID& id) { foreach( CatalogChapter chapter, mChapters ) { if( chapter.id() == id ) { return chapter.name(); } } return i18n("not found"); } dbID Katalog::chapterID( const QString& name ) { foreach( CatalogChapter chapter, mChapters ) { if( chapter.name() == name ) { return chapter.id(); } } return dbID(); } QString Katalog::getName() const { return m_name; } void Katalog::setName( const QString& n ) { m_name = n; } // Needs reimplementation in the inherited catalogs KatalogType Katalog::type() { return UnspecCatalog; } void Katalog::refreshChapterList() { mChapterListNeedsRefresh = true; } void Katalog::setChapterSortKey( const QString& chap, int key ) { // qDebug () << "Set chapter sortKey for " << chap << " to " << key; QSqlQuery q; q.prepare("UPDATE CatalogChapters SET sortKey = :sortKey WHERE catalogSetID = :catalogSetID AND chapter = :chapter"); q.bindValue(":catalogSetID", m_setID); q.bindValue(":chapter", chap); q.bindValue(":sortKey", key); q.exec(); } int Katalog::chapterSortKey( const QString& chap ) { int key = -1; QSqlQuery q; q.prepare("SELECT sortKey FROM CatalogChapters WHERE chapter = :chapter"); q.bindValue(":chapter", chap); q.exec(); if(q.next()) { key = q.value(0).toInt(); } return key; } QPair Katalog::usageCount(int id) { QSqlQuery q; q.prepare("SELECT usageCount, lastUsed FROM catItemUsage WHERE catId=:catId AND itemId=:itemId"); q.bindValue(":catId", this->id().toInt()); q.bindValue(":itemId", id); q.exec(); int cnt {0}; QDateTime lu; if (q.next()) { cnt = q.value(0).toInt(); lu = q.value(1).toDateTime(); } return QPair (cnt, lu) ; } QPair Katalog::recordUsage(int id) { QSqlQuery q; const QDateTime dt { QDateTime::currentDateTime() }; const QString ts { dt.toString("yyyy-MM-ddThh:mm:ss") }; int catId = this->id().toInt(); int usage = usageCount(id).first; if (usage == 0) { q.prepare("INSERT INTO catItemUsage (catId, itemId, usageCount, lastUsed) VALUES (:catId, :itemId, :usage, :timeStamp)"); } else { q.prepare("UPDATE catItemUsage SET usageCount=:usage, lastUsed=:timeStamp WHERE catId=:catId AND itemId=:itemId"); } usage += 1; q.bindValue(":usage", usage); q.bindValue(":catId", catId); q.bindValue(":itemId", id); q.bindValue(":timeStamp", ts); if (!q.exec()) qDebug() << q.executedQuery() << q.lastError(); return QPair(usage, dt); } void Katalog::deleteUsageRecord(int id) { QSqlQuery q; q.prepare("DELETE FROM catItemUsage WHERE catId=:catId AND itemId=:itemId"); q.bindValue(":catId", this->id().toInt()); q.bindValue(":itemId", id); q.exec(); if (!q.exec()) qDebug() << q.executedQuery() << q.lastError(); } QDomDocument Katalog::toXML() { return QDomDocument(); } void Katalog::writeXMLFile() { } dbID Katalog::id() { return dbID( m_setID ); } kraft-1.1/src/katalog.h000066400000000000000000000061721450127457600150650ustar00rootroot00000000000000/*************************************************************************** katalog.h - ------------------- begin : Son Feb 8 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KATALOG_H #define KATALOG_H #include #include #include "floskeltemplate.h" #include "catalogchapter.h" #include "dbids.h" /** *@author Klaas Freitag */ typedef enum {UnspecCatalog, MaterialCatalog, TemplateCatalog, PlantCatalog } KatalogType; class QDomDocument; class KRAFTCAT_EXPORT Katalog { public: Katalog(); Katalog(const QString& ); virtual ~Katalog(); virtual int load(); /** * reload the item with the given id or the entire catalog in case * the id is not valid. */ virtual void reload( dbID ) = 0; virtual void setName( const QString& ); virtual QString getName( ) const; /** find the ID for the corresponding chapter */ virtual dbID chapterID(const QString&); /** get a list of all existing chapters of this catalog */ virtual QList getKatalogChapters( bool freshup = false ); /** get the chapter name for the given ID */ virtual QString chapterName(const dbID&); /** set the sortkey for a chapter. Note: The organisation of the sortkeys * between the different chapters is up to the caller of this method. */ virtual void setChapterSortKey( const QString&, int ); virtual int chapterSortKey( const QString& ); /** * returns the KatalogType. */ virtual KatalogType type(); /** get the amount of entries in a chapter or the entire catalog */ virtual int getEntriesPerChapter( const CatalogChapter& ) = 0; bool isReadOnly() { return m_readOnly; } void setReadOnly( bool state ) { m_readOnly = state; } void refreshChapterList(); virtual QDomDocument toXML(); virtual void writeXMLFile(); virtual QPair usageCount(int id); virtual QPair recordUsage(int id); dbID id(); QLocale *locale() { return mLocale; } protected: void deleteUsageRecord(int id); QList mChapters; QString m_name; QString m_description; int m_setID; bool m_readOnly; bool mChapterListNeedsRefresh; QLocale *mLocale; private: void init(); }; #endif kraft-1.1/src/kataloglistview.cpp000066400000000000000000000476711450127457600172200ustar00rootroot00000000000000/*************************************************************************** kataloglistview.cpp - ------------------- begin : Son Feb 8 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include "kraftglobals.h" #include "katalog.h" #include "katalogman.h" #include "kataloglistview.h" #include "defaultprovider.h" #include "materialcalcpart.h" #include "stockmaterial.h" #include "templkatalog.h" #include "timecalcpart.h" #include "dbids.h" #include "catalogchapter.h" #include "addeditchapterdialog.h" KatalogListView::KatalogListView( QWidget *parent ) : QTreeWidget(parent), mCheckboxes( false ), m_root(0), mMenu(0), _query(nullptr) { setSelectionMode(QAbstractItemView::SingleSelection ); setAlternatingRowColors( true ); //Initialize common style options QPalette palette; palette.setColor( QPalette::AlternateBase, QColor("#e0fdd1") ); setPalette( palette ); setRootIsDecorated(false); setAnimated(true); // header()->setResizeMode(QHeaderView::ResizeToContents); // custom style const QString style = DefaultProvider::self()->getStyleSheet( "templcatalog"); setStyleSheet( style ); // Drag and Drop for normal mode, is changed in setSelectFromMode setSelectionMode( QAbstractItemView::SingleSelection ); setDragDropMode( QAbstractItemView::InternalMove ); setDragEnabled( true ); setAcceptDrops( true ); // currently only internal moves setDropIndicatorShown( true ); // setSorting(-1); mMenu = new QMenu( this ); mChapterFont = font(); mChapterFont.setBold( true ); connect( this, SIGNAL(itemActivated( QTreeWidgetItem*,int )), this, SLOT( slotItemEntered( QTreeWidgetItem*, int ))); } KatalogListView::~KatalogListView() { } QMenu *KatalogListView::contextMenu() { return mMenu; } void KatalogListView::addCatalogDisplay( const QString& name) { m_catalogName = name; } void KatalogListView::contextMenuEvent( QContextMenuEvent * event ) { mMenu->popup( event->globalPos() ); } Katalog* KatalogListView::catalog() { return KatalogMan::self()->getKatalog( m_catalogName ); } void KatalogListView::setSelectFromMode() { setSelectionMode( QAbstractItemView::SingleSelection /* NoSelection */ ); // FIXME: Allow multiple selections later setDragDropMode( QAbstractItemView::NoDragDrop ); setDragEnabled( false ); setAcceptDrops( false ); // currently only internal moves setDropIndicatorShown( false ); setCheckboxes( true ); } void KatalogListView::setupChapters() { Katalog *cat = catalog(); if( ! cat ) return; if( m_root ) { delete m_root; mChapterDict.clear(); } // qDebug () << "Creating root item!"; QStringList list; list << cat->getName(); m_root = new QTreeWidgetItem( this, list ); Qt::ItemFlags flags = m_root->flags(); flags = flags & ~Qt::ItemIsDragEnabled; m_root->setFlags(flags); m_root->setIcon( 0, DefaultProvider::self()->icon("kraft-simple")); m_root->setExpanded(true); m_root->setFont( 0, mChapterFont ); m_root->setToolTip( 0, QString() ); repaint(); const QList chapters = cat->getKatalogChapters( true ); // qDebug () << "Have count of chapters: " << chapters.size(); QList strayCats; foreach( CatalogChapter chapter, chapters ) { QTreeWidgetItem *item = tryAddingCatalogChapter( chapter ); if( ! item ) { strayCats.append( chapter ); } else { // qDebug () << "Creating katalog chapter item for " << chapter.name(); } } int oldStrayCatCount = strayCats.count() + 1; // to survive the first while condition while( strayCats.count() && strayCats.count() < oldStrayCatCount ) { QList newStrayCats; oldStrayCatCount = strayCats.count(); // loop as long as the overall number of straycats goes down in every round foreach( CatalogChapter chapter, strayCats ) { QTreeWidgetItem *katItem = tryAddingCatalogChapter( chapter ); if( katItem ) { // qDebug () << "Successfully added catalog chapter from strayCats"; } else { newStrayCats.append( chapter ); // qDebug () << "Failed to add a catalog chapter from stryCats"; } } strayCats = newStrayCats; } } QTreeWidgetItem *KatalogListView::tryAddingCatalogChapter( const CatalogChapter& chapter ) { int parentChapter = chapter.parentId().toInt(); int id = chapter.id().toInt(); QTreeWidgetItem *katItem = 0; if( parentChapter == 0 ) { katItem = new QTreeWidgetItem( m_root, QStringList( chapter.name() ) ); } else { if( mChapterDict.contains( parentChapter ) ) { katItem = new QTreeWidgetItem( mChapterDict[parentChapter], QStringList( chapter.name() ) ); katItem->setToolTip( 0, chapter.description() ); } } if( katItem ) { mChapterDict.insert( id, katItem ); katItem->setToolTip( 0, chapter.description() ); // katItem->setIcon( 0, chapter.icon() ); katItem->setFont( 0, mChapterFont ); // Store the parent-ID in the item data m_dataDict[katItem] = new CatalogChapter( chapter ); if ( mOpenChapters.contains( chapter.name() ) ) { katItem->setExpanded( true ); } } return katItem; } CatalogTemplateList KatalogListView::selectedTemplates() { CatalogTemplateList templates; if( mCheckboxes ) { // checkbox mode // add the checkboxed items. QTreeWidgetItemIterator it( this, QTreeWidgetItemIterator::Checked ); while (*it) { QTreeWidgetItem *item = *it; if( ! (isChapter( item ) || isRoot(item )) ) { // a template, not a chapter. void *data = itemData( item ); if( data ) templates.append( static_cast( data )); } item->setCheckState( 0, Qt::Unchecked ); ++it; } } // if no items were added yet, lets go for the selected ones. if( ! mCheckboxes || templates.isEmpty() ) { QList items = selectedItems(); foreach( QTreeWidgetItem* item, items ) { if( isChapter(item) && !isRoot(item) ) { // for chapters, the children are lined up. int kidCnt = item->childCount(); for( int i=0; i < kidCnt; i++ ) { QTreeWidgetItem *kid = item->child(i); if( kid && !isChapter(kid) ) { // only add normal templates. void *data = itemData(kid); if( data ) templates.append( static_cast(data)); } } } if( !(isChapter(item) || isRoot(item))) { void *data = itemData( item ); if( data ) templates.append( static_cast(data) ); } } } return templates; } QString KatalogListView::selectedCatalogChapter() { QList items = selectedItems(); QString chap; if (items.size() == 1) { QTreeWidgetItem *item = items.first(); if (!isChapter(item) && !isRoot(item)) { item = item->parent(); } if (isChapter(item)) { chap = static_cast(itemData(item))->name(); } } return chap; } void* KatalogListView::itemData( QTreeWidgetItem *item ) { if ( item && m_dataDict.contains( item ) ) { return m_dataDict[item]; } return 0; } void* KatalogListView::currentItemData() { return itemData( currentItem() ); } void KatalogListView::removeTemplateItem( QTreeWidgetItem *item ) { if (isChapter(item)) { QHashIterator it( mChapterDict ); while( it.hasNext() ) { it.next(); if ( it.value() == item ) { mChapterDict.remove(it.key()); break; } } } else { m_dataDict.remove( item ); } QTreeWidgetItem* parent = item->parent(); delete item; updateSort(parent); } bool KatalogListView::isChapter( QTreeWidgetItem *item ) { QHashIterator it( mChapterDict ); while( it.hasNext() ) { it.next(); if ( it.value() == item ) return true; } return false; } bool KatalogListView::isRoot( QTreeWidgetItem *item ) { return (item == m_root ); } void KatalogListView::setCheckboxes( bool cb ) { mCheckboxes = cb; } void KatalogListView::slotFreshupItem( QTreeWidgetItem*, void *, bool ) { } void KatalogListView::slotEditCurrentChapter() { QTreeWidgetItem *item = currentItem(); if( ! isChapter( item )) { // qDebug () << "Can only edit chapters!"; return; } CatalogChapter *chap = static_cast( itemData( item ) ); AddEditChapterDialog dia( this ); dia.setEditChapter( *chap ); if( dia.exec() ) { QString name = dia.name(); QString desc = dia.description(); if( name != chap->name() || desc != chap->description() ) { chap->setName( name ); chap->setDescription( desc ); chap->saveNameAndDesc(); item->setText( 0, name); item->setToolTip( 0, desc ); catalog()->refreshChapterList(); } } } void KatalogListView::slotRemoveCurrentChapter() { QTreeWidgetItem *item = currentItem(); if( ! isChapter( item )) { // qDebug () << "Can only remove chapters here!"; } if( item->childCount() > 0 ) { QMessageBox msgBox; msgBox.setText(i18n( "A catalog chapter can not be deleted as long it has children." )); msgBox.setInformativeText(i18n("Chapter can not be deleted")); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.exec(); return; } else { CatalogChapter *chap = static_cast( itemData( item ) ); if( chap ) { int id = chap->id().toInt(); if( chap->removeFromDB() ) { delete item; mChapterDict.remove(id); delete chap; } } } } void KatalogListView::slotCreateNewChapter() { QTreeWidgetItem *parentItem = currentItem(); if( ! (isChapter( parentItem ) || isRoot( parentItem ) ) ) { // qDebug () << "Not an chapter item selected, returning"; return; } AddEditChapterDialog dia( this ); dbID parentId = 0; if( ! isRoot( parentItem ) ) { CatalogChapter *parentChapter = static_cast(currentItemData()); dia.setParentChapter( *parentChapter ); parentId = parentChapter->id(); } if( dia.exec() ) { QString name = dia.name(); QString desc = dia.description(); CatalogChapter c; c.setName( name ); c.setDescription( desc ); c.setCatalogSetId( catalog()->id() ); c.setParentId( parentId ); c.save(); catalog()->refreshChapterList(); QTreeWidgetItem *newItem = tryAddingCatalogChapter( c ); if( newItem ) { this->scrollToItem( newItem ); this->setCurrentItem( newItem ); } updateSort(parentItem); } } void KatalogListView::dropEvent( QDropEvent *event ) { if (event->source() == this && (event->dropAction() == Qt::MoveAction || dragDropMode() == QAbstractItemView::InternalMove)) { QModelIndex dropParentIndex; int col = -1; int row = -1; QModelIndex dropIndx = indexAt( event->pos() ); QTreeWidgetItem *droppedOnItem = itemFromIndex( dropIndx ); if( ! droppedOnItem ) { event->ignore(); return; } const QString dropRowText = droppedOnItem->text(0); row = dropIndx.row(); col = dropIndx.column(); dropParentIndex = dropIndx.parent(); DropIndicatorPosition dropIndiPos = this->dropIndicatorPosition(); QList indexes; { QList idxs = selectedIndexes(); // selectedIndexes() contains ALL indexes, also for columns. This is only about rows, // thus the indexes are filtered for row changes. int r {-1}; for (auto indx : idxs) { if (r != indx.row()) { indexes.append(QPersistentModelIndex(indx)); r = indx.row(); } } } // FIXME: Why is this? if (row == -1 || indexes.contains(dropParentIndex)) return; // When removing items the drop location could shift QPersistentModelIndex dropRow = model()->index(row, col, dropParentIndex); // Remove the items QList taken; for (int i = indexes.count() - 1; i >= 0; --i) { QTreeWidgetItem *movedItem = itemFromIndex(indexes.at(i)); if (!movedItem || !movedItem->parent()) { // would be root -> should never happen FIXME taken.append(takeTopLevelItem(indexes.at(i).row())); } else { int r0 = indexes.at(i).row(); taken.append(movedItem->parent()->takeChild(r0)); } } // insert them back in at their new positions for (int i = 0; i < indexes.count(); ++i) { // Either at a specific point or appended int r = 0; bool droppedInto {false}; if (dropIndiPos == QAbstractItemView::AboveItem) { r = dropRow.row(); if (r < 0) r = 0; } else if (dropIndiPos == QAbstractItemView::BelowItem) { r = dropRow.row()+1; } else { droppedInto = true; } dbID newParentId; QTreeWidgetItem *parent {nullptr}; // The item was dropped on a chapter item or root. That causes a change of the // parent chapter. if( isChapter( droppedOnItem )|| isRoot( droppedOnItem )) { if (droppedInto) { parent = droppedOnItem; } else { // The item was just "resorted", that just changes the sortIndicator. if (isRoot(droppedOnItem)) { parent = m_root; } else { parent = droppedOnItem->parent(); } } // the parent id has to be updated for all inserted items CatalogChapter *parentChap = static_cast(itemData(parent)); if( parentChap ) { newParentId = parentChap->id(); } else { newParentId = 0; } } else { // the item was dropped on another item. Still the parent might have changed. CatalogTemplate *tmpl = static_cast(itemData(droppedOnItem)); newParentId = tmpl->chapterId(); parent = droppedOnItem->parent(); } if( parent ) { QTreeWidgetItem *movedItem = taken.takeFirst(); if( newParentId.isOk() ) { if( isChapter( movedItem ) ) { if (movedItem->parent() != droppedOnItem->parent()) { CatalogChapter* chapDrop = static_cast(itemData(movedItem)); chapDrop->reparent( newParentId ); } } else if( isRoot( movedItem )) { // it must not happen that root is moved. Q_ASSERT(false); if (movedItem->parent() != droppedOnItem->parent()) { CatalogChapter* chapDrop = static_cast(itemData(movedItem)); chapDrop->reparent( 0 ); } } else { // ordinary template, set a new parent chapter CatalogTemplate *tmpl = static_cast(itemData(movedItem)); if( tmpl && tmpl->chapterId() != newParentId ) { tmpl->setChapterId( newParentId, true ); } } } parent->insertChild( qMin(r, parent->childCount()), movedItem ); updateSort(parent); } event->accept(); // Don't want QAbstractItemView to delete it because it was "moved" we already did it event->setDropAction(Qt::IgnoreAction); } } QTreeView::dropEvent(event); } void KatalogListView::endUpdateItemSequence() { _query->finish(); delete _query; _query = nullptr; } void KatalogListView::updateChapterSort(int catChapterId) { if (mChapterDict.contains(catChapterId)) { QTreeWidgetItem *item = mChapterDict[catChapterId]; updateSort(item); } } void KatalogListView::updateSort(QTreeWidgetItem *chapter) { int chapCnt{0}; int itemCnt{0}; if (chapter == nullptr) chapter = m_root; int childrenCnt = chapter->childCount(); emit sequenceUpdateMaximum(childrenCnt); QSqlQuery chapQuery; chapQuery.prepare("UPDATE CatalogChapters SET sortKey = :sk WHERE chapterID = :id"); startUpdateItemSequence(); for (int indx = 0; indx < childrenCnt; indx++) { QTreeWidgetItem *item = chapter->child(indx); emit sequenceUpdateProgress(indx); if (isChapter(item)) { CatalogChapter *chapter = static_cast(itemData(item)); if (chapter) { chapQuery.bindValue(":id", chapter->id().toInt()); chapQuery.bindValue(":sk", chapCnt++); chapQuery.exec(); } } else { updateItemSequence(item, itemCnt++); } } endUpdateItemSequence(); emit sequenceUpdateProgress(childrenCnt); } void KatalogListView::slotItemEntered( QTreeWidgetItem *item, int ) { if( !item ) return; if( isRoot( item )) { // qDebug () << "Is a root item "; } else if( isChapter(item )) { // qDebug () << "Is a chapter item "; } else { CatalogTemplate *tmpl = static_cast(itemData(item)); // qDebug () << "hoovering this template: " << tmpl; emit templateHoovered( tmpl ); } } void KatalogListView::slotRedraw() { // remember all currently open chapters QHashIterator it( mChapterDict ); while( it.hasNext() ) { it.next(); if ( it.value()->isExpanded() ) { // qDebug () << "Adding open Chapter " << it.value()->text( 0 ); mOpenChapters << it.value()->text( 0 ); } } clear(); m_root = 0; m_dataDict.clear(); mChapterDict.clear(); addCatalogDisplay( m_catalogName ); mOpenChapters.clear(); } kraft-1.1/src/kataloglistview.h000066400000000000000000000064311450127457600166520ustar00rootroot00000000000000/*************************************************************************** floskellistview.h - ------------------- begin : Son Feb 8 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KATALOGLISTVIEW_H #define KATALOGLISTVIEW_H #include #include #include #include #include #include "kraftcat_export.h" #include "catalogtemplate.h" /** *@author Klaas Freitag */ class TemplKatalog; class QPixmap; class DocPosition; class Katalog; class CatalogChapter; class KRAFTCAT_EXPORT KatalogListView : public QTreeWidget { Q_OBJECT public: KatalogListView( QWidget *parent = 0 ); ~KatalogListView(); virtual void addCatalogDisplay( const QString& ); virtual void* currentItemData(); virtual void* itemData( QTreeWidgetItem* ); CatalogTemplateList selectedTemplates(); bool isChapter(QTreeWidgetItem*); bool isRoot(QTreeWidgetItem*); QString selectedCatalogChapter(); virtual void setupChapters(); QMenu *contextMenu(); // virtual DocPosition itemToDocPosition( QListViewItem *it = 0 ) = 0; // Save the header state of the tree view virtual void saveState() = 0; void updateChapterSort(int catChapterId); signals: void templateHoovered( CatalogTemplate* ); void sequenceUpdateProgress( int ); void sequenceUpdateMaximum( int ); public slots: virtual void setCheckboxes( bool ); virtual void slotFreshupItem( QTreeWidgetItem*, void*, bool remChildren = false ); virtual void slotCreateNewChapter(); virtual void slotEditCurrentChapter(); virtual void slotRemoveCurrentChapter(); virtual void contextMenuEvent( QContextMenuEvent* ); virtual void slotRedraw(); virtual void setSelectFromMode(); virtual void removeTemplateItem( QTreeWidgetItem* ); protected slots: virtual void slotItemEntered( QTreeWidgetItem*, int); // run an update of the sort key in a chapter. void updateSort(QTreeWidgetItem *chapter); protected: virtual void startUpdateItemSequence() = 0; virtual void updateItemSequence(QTreeWidgetItem *item, int seqNo) = 0; virtual void endUpdateItemSequence(); virtual Katalog* catalog(); void dropEvent( QDropEvent* ); bool mCheckboxes; QTreeWidgetItem* tryAddingCatalogChapter( const CatalogChapter& ); QTreeWidgetItem *m_root; QHash m_dataDict; QHash mChapterDict; QString m_catalogName; QStringList mOpenChapters; QMenu *mMenu; QFont mChapterFont; QSqlQuery *_query; }; #endif kraft-1.1/src/katalogman.cpp000066400000000000000000000113401450127457600161050ustar00rootroot00000000000000/*************************************************************************** katalogman - Catalog manager ------------------- begin : 2004-12-09 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include #include "kraftdb.h" #include "katalogman.h" #include "katalog.h" #include "templkatalog.h" #include "materialkatalogview.h" Q_GLOBAL_STATIC(KatalogMan, mSelf) KatalogMan *KatalogMan::self() { return mSelf; } KatalogMan::KatalogMan( ) { } KatalogMan::~KatalogMan( ) { } QStringList KatalogMan::allKatalogNames() { QStringList list; QSqlQuery q( "SELECT name FROM CatalogSet ORDER BY sortKey, name" ); while( q.next() ) { list << q.value( 0 ).toString(); } return list; } QString KatalogMan::catalogTypeString( const QString& catName ) { QString res; if ( !catName.isEmpty() ) { QSqlQuery q; q.prepare( "SELECT catalogType FROM CatalogSet where name=:name" ); q.bindValue( ":name", catName ); if ( q.exec() && q.next() ) { res = q.value( 0 ).toString(); } } return res; } void KatalogMan::registerKatalog( Katalog *k ) { Katalog* kat = m_katalogDict[k->getName()]; if( kat ) { qWarning() << "Katalog with same name already here -> deleting!"; delete kat; } else { // not found, try to open it // qDebug () << "Katalog " << k->getName() << " registered and loading..."; m_katalogDict.insert( k->getName(), k ); k->load (); } } Katalog *KatalogMan::getKatalog(const QString& name) { Katalog* kat = m_katalogDict[name]; if( !kat ) { // qDebug () << "No katalog " << name << " found"; } else { // qDebug() << "Returning existing katalog " << name; } return kat; } // this is called after an template has been changed in the database. void KatalogMan::notifyKatalogChange( Katalog* k, dbID ) { // FIXME: More efficient catalog reloading. if ( k ) { const QString name = k->getName(); k->reload( dbID() ); QList< QPointer > views = mKatalogListViews.values(name); KatalogListView *view; QListIterator< QPointer > i( views ); while ( i.hasNext() ) { view = i.next(); if( view ) { view->slotRedraw(); } } } } void KatalogMan::registerKatalogListView( const QString& name, KatalogListView *view ) { QList< QPointer > views = mKatalogListViews.values(name); if ( ! views.contains( view ) ) { mKatalogListViews.insert(name, QPointer(view)); } } /* * currently, there is only one catalog of type Template by design, see * for example in templatesaverdb.cpp or the database design where only * one template catalog is in use. */ Katalog* KatalogMan::defaultTemplateCatalog() { QHashIterator it( m_katalogDict ); // See QDictIterator while ( it.hasNext() ) { it.next(); Katalog *k = it.value(); if ( k->type() == TemplateCatalog ) { // qDebug () << "Found default template catalog: " << k->getName(); return k; } } return 0; } KatalogMan::CatalogDetails KatalogMan::catalogDetails( const QString& catName ) { KatalogMan::CatalogDetails details; QString sql; QString catTypeString = KatalogMan::catalogTypeString( catName ); if( catTypeString == QLatin1String("MaterialCatalog") ) { sql = "SELECT count(matID), COUNT(distinct chapterID), MAX(modifyDate) FROM stockMaterial"; } else if( catTypeString == QLatin1String("TemplCatalog") ) { sql = "SELECT count(TemplID), COUNT(distinct chapterID), MAX(modifyDatum) FROM Catalog"; } QSqlQuery q; q.prepare( sql ); if ( !sql.isEmpty() && q.exec() && q.next() ) { details.countEntries = q.value( 0 ).toInt(); details.countChapters = q.value( 1 ).toInt(); details.maxModDate = q.value( 2 ).toDateTime(); } return details; } /* END */ kraft-1.1/src/katalogman.h000066400000000000000000000040321450127457600155520ustar00rootroot00000000000000/*************************************************************************** katalogman - ------------------- begin : 2004-12-09 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _KATALOGMAN_H #define _KATALOGMAN_H #include #include "katalog.h" #include "kataloglistview.h" #include "kraftcat_export.h" // include files /** * */ class QStringList; class KRAFTCAT_EXPORT KatalogMan : public QObject { public: ~KatalogMan(); static KatalogMan *self(); struct CatalogDetails { int countEntries; int countChapters; QDateTime maxModDate; }; QStringList allKatalogNames(); Katalog* getKatalog(const QString&); Katalog* defaultTemplateCatalog(); void registerKatalog( Katalog* ); QString catalogTypeString( const QString& catName ); void notifyKatalogChange( Katalog*, dbID ); CatalogDetails catalogDetails( const QString& catName ); // register a view for a catalog identified by its name. void registerKatalogListView( const QString&, KatalogListView* ); // static KatalogMan *mSelf; KatalogMan(); private: QHash m_katalogDict; QMultiMap< QString, QPointer > mKatalogListViews; }; #endif /* END */ kraft-1.1/src/katalogview.cpp000066400000000000000000000311141450127457600163050ustar00rootroot00000000000000/*************************************************************************** katalogview.cpp ------------------- begin : 2005 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include // include files for QT #include #include #include #include #include #include // application specific includes #include "katalogview.h" #include "katalog.h" #include "floskeltemplate.h" #include "kataloglistview.h" #include "flostempldialog.h" #include "templkatalog.h" #include "filterheader.h" #include "docposition.h" #include "katalogman.h" #include "defaultprovider.h" #include "format.h" #include "kraftsettings.h" #define ID_STATUS_MSG 1 KatalogView::KatalogView( QWidget* parent, const char* ) : QMainWindow(parent, nullptr), m_acEditChapter(nullptr), m_acEditItem(nullptr), m_acNewItem(nullptr), m_acDeleteItem(nullptr), m_acExport(nullptr), m_filterHead(nullptr), m_editListViewItem(nullptr), mTemplateText(nullptr), mTemplateStats(nullptr) { setObjectName( "catalogeview" ); //We don't want to delete this view when we close it! setAttribute(Qt::WA_DeleteOnClose, false); } void KatalogView::init(const QString& katName ) { m_katalogName = katName; initActions(); /////////////////////////////////////////////////////////////////// // set up a vertical layout box QWidget *w = new QWidget(this); QBoxLayout *box = new QVBoxLayout(w); // start to set up the listview createCentralWidget(box, w); KatalogListView *listview = getListView(); if( ! listview ) { // qDebug () << "ERROR: No listview created !!!"; } else { QHBoxLayout *horizLay = new QHBoxLayout; m_filterHead = new FilterHeader(w, listview); horizLay->insertWidget(0, m_filterHead, 2); horizLay->addStretch(1); box->insertLayout(0, horizLay); connect( listview, SIGNAL(currentItemChanged ( QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT(slTreeviewItemChanged( QTreeWidgetItem*, QTreeWidgetItem*)) ); connect( listview, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slEditTemplate())); connect( listview, SIGNAL(templateHoovered(CatalogTemplate*)), this, SLOT(slotShowTemplateDetails( CatalogTemplate*))); // Populate the context Menu (listview->contextMenu())->addAction( m_acEditItem ); (listview->contextMenu())->addAction( m_acNewItem ); (listview->contextMenu())->addAction( m_acDeleteItem ); (listview->contextMenu())->addSeparator(); (listview->contextMenu())->addAction( m_acAddChapter ); (listview->contextMenu())->addAction( m_acEditChapter ); (listview->contextMenu())->addAction( m_acRemChapter ); getKatalog( katName ); listview->addCatalogDisplay( katName ); } setCentralWidget(w); m_editListViewItem = nullptr; // qDebug () << "Getting katalog!" << katName; // setAutoSaveSettings( QString::fromLatin1( "CatalogWindow" ), true ); } void KatalogView::createCentralWidget(QBoxLayout *box, QWidget* ) { mTemplateText = new QLabel( "Nothing selected."); box->addWidget( mTemplateText ); QHBoxLayout *hb = new QHBoxLayout; box->addLayout( hb ); mTemplateStats = new QLabel( ); mProgress = new QProgressBar; mProgress->setVisible(false); hb->addWidget( mTemplateStats ); hb->addStretch(); hb->addWidget( mProgress ); connect( getListView(), &KatalogListView::sequenceUpdateMaximum, [=](int max) { this->mProgress->setVisible(max > 0); this->mProgress->setMaximum(max); }); connect( getListView(), &KatalogListView::sequenceUpdateProgress, this, &KatalogView::setProgressValue ); const QByteArray state = windowState(); restoreState(state); const QByteArray geo = windowGeo(); restoreGeometry(geo); } void KatalogView::setProgressValue( int val ) { if( val == mProgress->maximum() ) { QTimer::singleShot(3000, this, [this] () { this->mProgress->reset(); this->mProgress->setVisible(false); }); } if( ! mProgress || mProgress->maximum() < 10) return; mProgress->setValue( val ); } KatalogView::~KatalogView() { } Katalog* KatalogView::getKatalog( const QString& name ) { KatalogMan::self()->registerKatalogListView( name, getListView() ); return nullptr; } void KatalogView::initActions() { QIcon newIcon = DefaultProvider::self()->icon( "edit"); m_acEditChapter = new QAction(newIcon, i18n("Edit Sub chapter"), this); m_acEditChapter->setShortcut( Qt::CTRL + Qt::Key_S); m_acEditChapter->setStatusTip(i18n("Edit a catalog sub chapter")); connect(m_acEditChapter, &QAction::triggered, this, &KatalogView::slEditSubChapter); newIcon = DefaultProvider::self()->icon( "edit"); m_acAddChapter = new QAction(newIcon, i18n("Add a sub chapter"), this); m_acAddChapter->setShortcut( Qt::CTRL + Qt::Key_A); m_acAddChapter->setStatusTip(i18n("Add a sub chapter below the selected one")); connect(m_acAddChapter, &QAction::triggered, this, &KatalogView::slAddSubChapter); newIcon = DefaultProvider::self()->icon( "minus"); m_acRemChapter = new QAction(newIcon, i18n("Remove a sub chapter"), this); m_acRemChapter->setShortcut( Qt::CTRL + Qt::Key_R); m_acRemChapter->setStatusTip(i18n("Remove a sub chapter")); connect(m_acRemChapter, &QAction::triggered, this, &KatalogView::slRemoveSubChapter); newIcon = DefaultProvider::self()->icon( "edit"); m_acEditItem = new QAction(newIcon, i18n("Edit Template"), this); m_acEditItem->setShortcut( Qt::CTRL + Qt::Key_T); m_acEditItem->setStatusTip(i18n("Opens the editor window for templates to edit the selected one")); m_acEditItem->setEnabled(false); connect(m_acEditItem, &QAction::triggered, this, &KatalogView::slEditTemplate); newIcon = DefaultProvider::self()->icon( "file-plus"); m_acNewItem = new QAction(newIcon, i18n("New template"), this); m_acNewItem->setShortcut( Qt::CTRL + Qt::Key_N); m_acNewItem->setStatusTip(i18n("Opens the editor window for templates to enter a new template")); connect(m_acNewItem, &QAction::triggered, this, &KatalogView::slNewTemplate); m_acNewItem->setEnabled(true); newIcon = DefaultProvider::self()->icon( "file-export"); m_acDeleteItem = new QAction(newIcon, i18n("Delete template"), this); m_acDeleteItem->setShortcut( QKeySequence::Delete); m_acDeleteItem->setStatusTip(i18n("Deletes the template")); connect(m_acDeleteItem, &QAction::triggered, this, &KatalogView::slDeleteTemplate); m_acDeleteItem->setEnabled(true); newIcon = DefaultProvider::self()->icon( "file-export"); m_acExport = new QAction(newIcon, i18n("Export catalog"), this); m_acExport->setShortcut( Qt::Key_E); m_acExport->setStatusTip(i18n("Export the whole catalog as XML encoded file")); connect(m_acExport, &QAction::triggered, this, &KatalogView::slExport); m_acExport->setEnabled(false); newIcon = DefaultProvider::self()->icon( "transfer-in"); m_acImport = new QAction(newIcon, i18n("Import catalog"), this); m_acExport->setShortcut( Qt::Key_I); m_acExport->setStatusTip(i18n("Import a catalog from a XML file")); connect(m_acExport, &QAction::triggered, this, &KatalogView::slImport); m_acExport->setEnabled(false); QMenu *catalogMenu = menuBar()->addMenu(i18n("&Catalog")); catalogMenu->addAction(m_acAddChapter); catalogMenu->addAction(m_acEditChapter); catalogMenu->addAction(m_acRemChapter); catalogMenu->addSeparator(); catalogMenu->addAction(m_acNewItem); catalogMenu->addAction(m_acEditItem); catalogMenu->addAction(m_acDeleteItem); #ifdef HAVE_EXPORT catalogMenu->addSeparator(); catalogMenu->addAction(m_acExport); catalogMenu->addAction(m_acImport); #endif } void KatalogView::openDocumentFile(const QUrl& ) { slotStatusMsg(i18n("Opening file...")); slotStatusMsg(i18n("Ready.")); } void KatalogView::closeEvent( QCloseEvent *event ) { slotStatusMsg(i18n("Exiting...")); if( event ) event->accept(); } void KatalogView::slotSaveState() { getListView()->saveState(); // saves the header state const QByteArray state = saveState().toBase64(); saveWindowState(state); const QByteArray geo = saveGeometry().toBase64(); saveWindowGeo(geo); } void KatalogView::slotStatusMsg(const QString &text) { if( text.isEmpty() ) { statusBar()->clearMessage(); } else { statusBar()->showMessage(text, 30*1000 /* milliseconds timeout */ ); } } void KatalogView::slTreeviewItemChanged( QTreeWidgetItem *newItem, QTreeWidgetItem * /* prevItem */ ) { KatalogListView *listview = getListView(); if( !listview ) return; if( ! newItem ) return; bool itemEdit = true; bool itemNew = true; bool chapterNew = false; bool chapterEdit = false; if( listview->isRoot(newItem) ) { // we have the root item, not editable itemEdit = false; itemNew = false; chapterNew = true; } else if( listview->isChapter(newItem) ) { itemEdit = false; chapterNew = true; chapterEdit = true; } m_acEditItem->setEnabled(itemEdit); m_acDeleteItem->setEnabled(itemEdit); m_acNewItem->setEnabled( itemNew ); m_acAddChapter->setEnabled( chapterNew ); m_acEditChapter->setEnabled( chapterEdit ); m_acRemChapter->setEnabled( chapterEdit ); } void KatalogView::slExport() { slotStatusMsg(i18n("Exporting file...")); Katalog *k = getKatalog(m_katalogName); if(k) k->writeXMLFile(); slotStatusMsg(i18n("Ready.")); } void KatalogView::slImport() { slotStatusMsg(i18n("Importfile... (not yet implemented)")); } void KatalogView::slAddSubChapter() { slotStatusMsg( i18n("Creating a new sub chapter...")); KatalogListView *listview = getListView(); if( listview ) listview->slotCreateNewChapter(); slotStatusMsg( i18n("Ready.")); } void KatalogView::slEditSubChapter() { slotStatusMsg( i18n("Editing a sub chapter...")); KatalogListView *listview = getListView(); if( listview ) listview->slotEditCurrentChapter(); slotStatusMsg( i18n("Ready.")); } void KatalogView::slRemoveSubChapter() { slotStatusMsg( i18n("Removing a sub chapter...")); KatalogListView *listview = getListView(); if( listview ) listview->slotRemoveCurrentChapter(); slotStatusMsg( i18n("Ready.")); } void KatalogView::slotShowTemplateDetails( CatalogTemplate *tmpl ) { if( ! (mTemplateText && mTemplateStats) ) { // qDebug () << "Hoover-Text: No label ready."; return; } if( ! tmpl ) { mTemplateText->setText( QString() ); mTemplateStats->setText( QString() ); return; } QString t; QString flos = tmpl->getText(); QFontMetrics fm( mTemplateText->font() ); int w = mTemplateText->width() - 30; t = QString( "%1").arg( fm.elidedText(flos, Qt::ElideMiddle, w ) ); mTemplateText->setText( t ); int useCount = tmpl->useCounter(); QDateTime ed = tmpl->enterDate(); const QString enterDateStr = Format::toDateString(ed.date(), KraftSettings::self()-> dateFormat()); t = QStringLiteral("

            ") + i18n("Created at %1 ", enterDateStr); const QDateTime dt = tmpl->modifyDate(); if (dt.isValid() && ed != dt) { const QString modDateStr = Format::toDateTimeString( dt, KraftSettings::self()-> dateFormat()); t += i18n(", last modified at %1", modDateStr); } t += QStringLiteral("
            "); if (useCount > 0) { const QString useCntStr = Format::toDateTimeString(tmpl->lastUsedDate(), KraftSettings::self()-> dateFormat()); t += i18n("%1 times used, last at %2", useCount, useCntStr ); } else { // Not used yet, do not print anything. } t += QStringLiteral("

            "); // qDebug() << "Hoover-String: " << t; mTemplateStats->setText( t ); } kraft-1.1/src/katalogview.h000066400000000000000000000112241450127457600157520ustar00rootroot00000000000000/*************************************************************************** katalogview.h ------------------- begin : 2005 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KATALOGVIEW_H #define KATALOGVIEW_H #include #include #include #include "kraftcat_export.h" class KatalogListView; class Katalog; class FilterHeader; class CatalogWidget; class QBoxLayout; class QActionMenu; class DocPosition; class CalcPartList; class QTreeWidgetItem; class QLabel; class QProgressBar; class CatalogTemplate; /** * The base class for Kraft katalog view. * * @author Klaas Freitag * @version $Id$ */ class KRAFTCAT_EXPORT KatalogView : public QMainWindow { Q_OBJECT public: /** construtor of a catalog view. * Note: init must be called immediately after instanciating a inherited * class of KatalogView */ KatalogView(QWidget* parent=0, const char* name=0); virtual ~KatalogView(); /** * create a special listview for the kind of catalog. This method must * be overwritten in inherited catalog view classes. */ virtual void createCentralWidget(QBoxLayout*, QWidget*); virtual KatalogListView* getListView(){return 0;}; virtual void init( const QString& ); protected: virtual Katalog* getKatalog( const QString& ); public slots: /** clears the document in the current view to reuse it as the new document */ void openDocumentFile(const QUrl &url); /** changes the statusbar contents for the standard label permanently, used to indicate current actions. * @param text the text that is displayed in the statusbar */ void slotStatusMsg(const QString &text); virtual void slTreeviewItemChanged( QTreeWidgetItem *, QTreeWidgetItem *); void slExport(); void slImport(); // virtual void slEditChapters(); virtual void slAddSubChapter(); virtual void slEditSubChapter(); virtual void slRemoveSubChapter(); virtual void slNewTemplate() = 0; virtual void slEditTemplate() = 0; virtual void slDeleteTemplate() = 0; void slotShowTemplateDetails( CatalogTemplate*); void setProgressValue( int ); void closeEvent( QCloseEvent *event ); protected slots: void slotSaveState(); protected: /** the configuration object of the application */ QAction* m_acEditChapter; QAction* m_acAddChapter; QAction* m_acRemChapter; QAction* m_acEditItem; QAction* m_acNewItem; QAction* m_acDeleteItem; QAction* m_acExport; QAction* m_acImport; // KToggleAction* viewToolBar; // KToggleAction* viewStatusBar; QString m_katalogName; FilterHeader *m_filterHead; QTreeWidgetItem *m_editListViewItem; QLabel *mTemplateText; QLabel *mTemplateStats; QProgressBar *mProgress; // Fills the DocPosition with the data from the currently selected item in the view virtual bool currentItemToDocPosition( DocPosition& ){ return false; } /** initializes the QActions of the application */ void initActions(); /** sets up the statusbar for the main window by initialzing a statuslabel. */ /** initializes the document object of the main window that is connected to the view in initView(). * @see initView(); */ void initView(); /** Save the state of the window to the right settings value. Needs to be reimplemented in the special window implementation, * thus virtual here. */ virtual void saveWindowState( const QByteArray& arr ) = 0; virtual QByteArray windowState() = 0; /** Save the geomentry of the window to the right settings value. Needs to be reimplemented in the special window implementation, * thus virtual here. */ virtual void saveWindowGeo( const QByteArray& arr ) = 0; virtual QByteArray windowGeo() = 0; }; #endif // KATALOGVIEW_H kraft-1.1/src/katalogview.rc000066400000000000000000000013341450127457600161300ustar00rootroot00000000000000 &File &Catalog kraft-1.1/src/kraftcat_export.h000066400000000000000000000017251450127457600166420ustar00rootroot00000000000000/* This file is part of the kraft catalog library. Copyright (C) 2009 Klaas Freitag This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KRAFTCAT_EXPORT_H #define KRAFTCAT_EXPORT_H #define KRAFTCAT_EXPORT #endif kraft-1.1/src/kraftdb.cpp000066400000000000000000000465751450127457600154260ustar00rootroot00000000000000/*************************************************************************** KraftDB.cpp - ------------------- begin : Die Feb 3 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include "version.h" #include "kraftdb.h" #include "doctype.h" #include "dbids.h" #include "defaultprovider.h" #include "archiveman.h" #include "documentsaverdb.h" #include "databasesettings.h" #include "stringutil.h" Q_GLOBAL_STATIC(KraftDB, mSelf) SqlCommand::SqlCommand() { } SqlCommand::SqlCommand(const QString& cmd, const QString& msg, bool mayfail) : mSql(cmd), mMessage(msg), mMayFail(mayfail) { if( !mMessage.isEmpty() && !mMessage.endsWith(';') ) { mMessage.append(';'); } if( !mSql.isEmpty() && !mSql.endsWith(';') ) { mSql.append(';'); } } QString SqlCommand::message() { return mMessage; } QString SqlCommand::command() { return mSql; } bool SqlCommand::mayfail() { return mMayFail; } // ============================ SqlCommandList::SqlCommandList() :QList(), _number(0) { } void SqlCommandList::setNumber(int no) { _number = no; } int SqlCommandList::number() { return _number; } void SqlCommandList::setMetaAddDocTypeList( QList list ) { _docTypeMetaList = list; } QList SqlCommandList::metaAddDocTypeList() const { return _docTypeMetaList; } // ========================================================================== KraftDB::KraftDB() :QObject (), mParent(nullptr), mSuccess( true ), EuroTag( QString::fromLatin1( "%EURO" ) ), mInitDialog(nullptr), _amountOfDocs(-1), _amountOfArchs(-1), _emitDBChangeSignal(true) { // Attention: Before setup assistant rewrite, dbConnect() was called here. // Keep that in mind, maybe the auto connect to the DB now misses somewhere. // dbConnect(); connect( &_timer, &QTimer::timeout, this, &KraftDB::slotCheckDocDatabaseChanged); } bool KraftDB::dbConnect( const QString& driver, const QString& dbName, const QString& dbUser, const QString& dbHost, const QString& dbPasswd ) { mSuccess = true; mDatabaseDriver = driver; mDatabaseName = dbName; if( mDatabaseDriver.isEmpty() ) { // qDebug () << "Database Driver is not specified, check katalog settings"; mSuccess = false; return false; } else { // qDebug () << "Using database Driver " << mDatabaseDriver; } QStringList list = QSqlDatabase::drivers(); if( list.size() == 0 ) { // qDebug () << "Database Drivers could not be loaded."; mSuccess = false ; } else { if( list.indexOf( mDatabaseDriver ) == -1 ) { // qDebug () << "Database Driver " << mDatabaseDriver << " could not be loaded!"; mSuccess = false; } } if( mSuccess && m_db.isValid() ) { m_db.close(); } if( mSuccess ) { m_db = QSqlDatabase::addDatabase( mDatabaseDriver ); if ( ! m_db.isValid() || m_db.isOpenError() ) { qDebug() << "Failed to connect to the database driver: " << m_db.lastError().text(); mSuccess = false; } } if ( mSuccess ) { int re = 0; if(mDatabaseDriver == "QMYSQL") { int port = DatabaseSettings::self()->dbServerPort(); // use the default port so far // FIXME: get port from user interface // qDebug () << "Try to open MySQL database " << name; re = checkConnect( dbHost, dbName , dbUser, dbPasswd, port); } else if(mDatabaseDriver == "QSQLITE") { // SqlLite only requires a valid file name which comes in as Database Name // qDebug () << "Try to open SqLite database " << name; re = checkConnect( QString(), dbName, QString(), QString(), -1); } if ( re == 0 ) { // Database successfully opened; we can now issue SQL commands. // qDebug () << "** Database opened successfully"; } else { // qDebug () << "## Could not open database"; mSuccess = false; } } return mSuccess; } void KraftDB::enableTimerRefresh(bool runTimer) { if (mSuccess && runTimer) { _timer.start(10*1000); } else { _timer.stop(); } } KraftDB *KraftDB::self() { return mSelf; } void KraftDB::close() { QString name = m_db.connectionName(); // qDebug () << "Database connection name to close: " << name; m_db.close(); } bool KraftDB::isSqlite() { const QString dbDriver = qtDriver().toUpper(); return (dbDriver.startsWith("QSQLITE")); } int KraftDB::checkConnect( const QString& host, const QString& dbName, const QString& user, const QString& pwd, int port ) { mDatabaseName = dbName; // works for both mysql and sqlite if the filename for sqlite comes in // as parameter two if ( dbName.isEmpty() || !(m_db.isValid()) ) return false; m_db.setHostName( host ); m_db.setDatabaseName( dbName ); m_db.setUserName( user ); m_db.setPassword( pwd ); if( port > -1 ) { m_db.setPort(port); } int re = 0; m_db.setConnectOptions("MYSQL_OPT_RECONNECT=1"); m_db.open(); if ( m_db.isOpenError() ) { qDebug () << "ERR opening the db: " << m_db.lastError().text() << ", type is " << m_db.lastError().type(); re = m_db.lastError().type(); } return re; } QSqlError KraftDB::lastError() { return m_db.lastError(); } dbID KraftDB::getLastInsertID() { if(! ( m_db.isValid()) ) return 0; QSqlQuery query; if( mDatabaseDriver.toLower() == "qmysql" ) { query.prepare("SELECT LAST_INSERT_ID()"); query.exec(); } else if( mDatabaseDriver.toLower() == "qsqlite") { query.prepare( "SELECT last_insert_rowid()"); query.exec(); } else { // qDebug () << "############# FATAL ERROR: Unknown database driver " << mDatabaseDriver; } int id = -1; if( query.next() ) { id = query.value(0).toInt(); } else { // qDebug () << "############# FATAL ERROR: Query for last insert id is invalid!"; } // qDebug () << "Last Insert ID: " << id; return dbID(id); } QString KraftDB::databaseName() const { return mDatabaseName; } bool KraftDB::databaseExists() { bool re = false; if(!m_db.isOpen()) { m_db.open(); } if(m_db.isOpen()) { const QStringList t = m_db.tables(); re = t.contains( "kraftsystem"); } return re; } void KraftDB::setSchemaVersion( const QString& versionStr ) { QSqlQuery q; q.prepare( "UPDATE kraftsystem SET dbSchemaVersion=:id" ); q.bindValue(":id", versionStr ); q.exec(); } SqlCommandList KraftDB::parseCommandFile( int currentVersion ) { SqlCommandList list; const QString& file = QString("%1_dbmigrate.sql").arg(currentVersion); list = parseCommandFile(file); list.setMetaAddDocTypeList( parseMetaFile(currentVersion) ); list.setNumber(currentVersion); return list; } SqlCommandList KraftDB::parseCommandFile( const QString& file ) { QString sqlFile; QString driverPrefix{"mysql"}; // Default on mysql if( mDatabaseDriver.toLower() == "qsqlite") { driverPrefix = "sqlite3"; } // qDebug() << "XXXXXXXXXX: " << stdDirs.resourceDirs("data"); // Package or AppImage const QString fragment = QString("dbmigrate/%1/%2").arg(driverPrefix).arg(file ); sqlFile = DefaultProvider::self()->locateFile(fragment); // dbinit files: if (sqlFile.isEmpty()) { const QString envPath = QString( "dbinit/%1/%2").arg(driverPrefix).arg(file); sqlFile = DefaultProvider::self()->locateFile(envPath); } // KRAFT_HOME files: if (sqlFile.isEmpty()) { const QString envPath = QString( "database/%1/%2").arg(driverPrefix).arg(file); sqlFile = DefaultProvider::self()->locateFile(envPath); } // still KRAFT_HOME files: if (sqlFile.isEmpty()) { const QString envPath = QString( "database/%1/migration/%2").arg(driverPrefix).arg(file); sqlFile = DefaultProvider::self()->locateFile(envPath); } SqlCommandList retList; if ( ! sqlFile.isEmpty() ) { // qDebug () << "Opening migration file " << sqlFile; QFile f( sqlFile ); if ( !f.exists() ) { qDebug() << "FATAL: File" << sqlFile << "does not exist!"; } if ( !f.open( QIODevice::ReadOnly ) ) { qDebug () << "FATAL: Could not open " << sqlFile; } else { QTextStream ts( &f ); ts.setCodec("UTF-8"); QString allSql = ts.readAll(); //Not sure of this one! QStringList sqlList = allSql.split(";"); QRegExp reg( "\\s*(#|--)\\s*message:? ?(.*)\\s*\\n" ); QRegExp failreg( "\\s*(#|--)\\s*mayfail\\s*\\n" ); reg.setMinimal( true ); QListIterator it(sqlList); while( it.hasNext() ) { QString msg, command; QString sqlFragment = it.next().trimmed(); int pos = reg.indexIn( sqlFragment.toLower(), 0 ); if ( pos > -1 ) { msg = reg.cap( 2 ); // qDebug() << "SQL-Commands-Parser: Msg: >" << msg << "<"; } bool mayfail = false; pos = failreg.indexIn( sqlFragment.toLower(), 0 ); if( pos > -1 ) { mayfail = true; } bool clean = false; while( ! clean ) { if( sqlFragment.startsWith("#") || sqlFragment.startsWith("--") ) { // remove the comment line. int newLinePos = sqlFragment.indexOf('\n'); // qDebug() << "Found newline in <" << sqlFragment << ">:" << newLinePos; if(newLinePos > 0) { sqlFragment = sqlFragment.remove( 0, 1+sqlFragment.indexOf('\n') ); } else { sqlFragment = QString(); } // qDebug() << "Left over SQL Fragment:" << sqlFragment; } else { clean = true; } } if( !sqlFragment.isEmpty() ) { if( sqlFragment.startsWith( "CREATE TRIGGER", Qt::CaseInsensitive )) { // Triggers contain a ; which scares the parser. In case of triggers we pull // the next item in the list which should be the END; keyword. command = sqlFragment + ";"; if( it.hasNext()) command += it.next(); } else { // ordinary command, we take it as it is. command = sqlFragment; } if( !command.isEmpty() ) { retList.append( SqlCommand( command, msg, mayfail ) ); } } } } } else { qDebug () << "ERR: Can not find sql file " << file; } return retList; } QList KraftDB::parseMetaFile( int currentVersion ) { QString lookup= QString( "meta/%1_meta.xml").arg(currentVersion); // if KRAFT_HOME is set, the lookup path must be prepended with database const QByteArray env = qgetenv("KRAFT_HOME"); if( !env.isEmpty()) { lookup.prepend("database/"); } const QString xmlFile = DefaultProvider::self()->locateFile(lookup); if (xmlFile.isEmpty()) { // it is fine to not find the XML file return QList(); } QFile f( xmlFile ); MetaXMLParser parser; if( f.exists() ) { if ( !f.open( QIODevice::ReadOnly ) ) { qWarning() << "FATAL: Could not open " << xmlFile; } else { QTextStream ts( &f ); ts.setCodec("UTF-8"); parser.parse( &f ); } } else { qWarning() << "XML Metafile" << xmlFile << "does not exist!"; } return parser.metaDocTypeAddList(); } int KraftDB::processSqlCommands( const SqlCommandList& commands ) { int cnt = 0; // first do the doctype definitions QList newDocTypes = commands.metaAddDocTypeList(); // loop over all doctypes first, later loop again to create the followers. // The followers might reference each other and thus must exist. for( auto newDocType : newDocTypes ) { const QString name = newDocType.name(); DocType type(name, true); for( QString attr : newDocType._attribs.keys() ) { type.setAttribute(attr, newDocType._attribs[attr]); } type.save(); } // now loop again to process the followers for( auto newDocType : newDocTypes ) { const QString name = newDocType.name(); if( newDocType._follower.count() > 0 ) { DocType type(name, true); type.setAllFollowers(newDocType._follower); type.save(); } } foreach( SqlCommand cmd, commands ) { if( !cmd.message().isEmpty() ) { emit statusMessage( cmd.message() ); } if( !cmd.command().isEmpty() ) { bool res = true; QSqlQuery q; q.clear(); res = q.exec(cmd.command()) || cmd.mayfail(); if ( res ) { // qDebug () << "Successful SQL Command: " << cmd.command(); cnt ++; } else { QSqlError err = q.lastError(); res = false; qDebug () << "###### Failed SQL Command " << cmd.command() << ": " << err.text(); } q.clear(); emit processedSqlCommand( res ); } } return cnt; } int KraftDB::requiredSchemaVersion() { return Kraft::Version::dbSchemaVersion(); } int KraftDB::currentSchemaVersion() { QSqlQuery query; query.exec("SELECT dbschemaversion FROM kraftsystem"); //We'll retrieve every record int re = -1; if ( query.next() ) { re = query.value(0).toInt(); } return re; } QString KraftDB::qtDriver() { return mDatabaseDriver; } QString KraftDB::currentTimeStamp( const QDateTime& dt ) { QString dateStr; if( dt.isValid() ) { dateStr = dt.toString(Qt::ISODate); } else { dateStr = QDateTime::currentDateTime().toString(Qt::ISODate); } return dateStr; } QString KraftDB::mysqlEuroEncode( const QString& str ) const { QChar euro( 0x20ac ); QString restr( str ); return restr.replace( euro, EuroTag ); } QString KraftDB::mysqlEuroDecode( const QString& str ) const { QChar euro( 0x20ac ); QString restr( str ); return restr.replace( EuroTag, euro ); } QStringList KraftDB::wordList(const QString& selector, QMap replaceMap ) { QStringList re; QSqlQuery query; query.prepare("SELECT category, word FROM wordLists WHERE category=:cat"); query.bindValue(":cat", selector); query.exec(); while ( query.next() ) { re << StringUtil::replaceTagsInString(query.value(1).toString(), replaceMap); } re.sort(); return re; } void KraftDB::writeWordList( const QString& listName, const QStringList& list ) { // qDebug () << "Saving " << list[0] << " into list " << listName; QSqlQuery qd; qd.prepare( "DELETE FROM wordLists WHERE category=:catName" ); qd.bindValue( ":catName", listName ); qd.exec(); QSqlQuery qi; qi.prepare( "INSERT INTO wordLists (category, word) VALUES( :category, :entry )" ); qi.bindValue( ":category", listName ); for ( QStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) { qi.bindValue( ":entry", *it ); qi.exec(); } } bool KraftDB::checkTableExistsSqlite(const QString& name, const QStringList& lookupCols) { const QString query = QString("PRAGMA table_info(%1)").arg(name); QSqlQuery q(query); QStringList cols = lookupCols; q.exec(); QSqlError err = q.lastError(); if( err.isValid() ) { qDebug() << "Error: " << err.text(); } while( q.next() ) { const QString colName = q.value(1).toString(); qDebug() << "checking colum" << colName; cols.removeAll(colName); } return cols.isEmpty(); } KraftDB::~KraftDB() { } void KraftDB::slotCheckDocDatabaseChanged() { bool changed{false}; { QSqlQuery q("SELECT count(*) FROM document"); q.exec(); QSqlError err = q.lastError(); if( err.isValid() ) { qDebug() << "Error: " << err.text(); return; } if ( q.next() ) { bool ok; int cnt = q.value(0).toInt(&ok); if (_amountOfDocs != -1 && cnt != _amountOfDocs ) { qDebug() << "Docs from" << _amountOfDocs << "to" << cnt; changed = true; } _amountOfDocs = cnt; } } { QSqlQuery qArch("SELECT count(*) FROM archdoc"); qArch.exec(); QSqlError err = qArch.lastError(); if( err.isValid() ) { qDebug() << "Error: " << err.text(); return; } if ( qArch.next() ) { bool ok; int cnt = qArch.value(0).toInt(&ok); if (_amountOfArchs != -1 && cnt != _amountOfArchs) { qDebug() << "Arched docs from" << _amountOfArchs << "to" << cnt; changed = true; } _amountOfArchs = cnt; } } if (changed && _emitDBChangeSignal) emit docDatabaseChanged(); } dbID KraftDB::archiveDocument( KraftDoc *docPtr ) { dbID archID = ArchiveMan::self()->archiveDocument( docPtr ); if (archID.isOk()) { _emitDBChangeSignal = false; // block sending of the signal slotCheckDocDatabaseChanged(); _emitDBChangeSignal = true; } return archID; } void KraftDB::loadDocument(const QString& id, KraftDoc *docPtr) { DocumentSaverDB loader; loader.load(id, docPtr); } bool KraftDB::saveDocument(KraftDoc *docPtr) { bool res {false}; DocumentSaverDB saver; if (docPtr) { res = saver.saveDocument(docPtr); if (res) { _emitDBChangeSignal = false; // block sending of the signal slotCheckDocDatabaseChanged(); _emitDBChangeSignal = true; } } return res; } kraft-1.1/src/kraftdb.h000066400000000000000000000111331450127457600150510ustar00rootroot00000000000000/*************************************************************************** kraftdb.h - ------------------- begin : Die Feb 3 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRAFTDB_H #define KRAFTDB_H #include #include #include #include #include #include "metaxmlparser.h" class dbID; class DbInitDialog; class SetupAssistant; class KraftDoc; /** *@author Klaas Freitag */ class SqlCommand { public: SqlCommand(); SqlCommand( const QString&, const QString&, bool ); QString message(); QString command(); bool mayfail(); private: QString mSql; QString mMessage; bool mMayFail; }; class SqlCommandList: public QList { public: SqlCommandList(); QList metaAddDocTypeList() const; void setMetaAddDocTypeList( QList list ); void setNumber(int no); int number(); private: QList _docTypeMetaList; int _number; }; class KraftDB : public QObject { Q_OBJECT public: ~KraftDB(); static KraftDB *self(); dbID getLastInsertID(); QSqlDatabase *getDB(){ return &m_db; } QString qtDriver(); QStringList wordList( const QString&, QMap replaceMap = QMap() ); void writeWordList( const QString&, const QStringList& ); QString databaseName() const; QSqlError lastError(); bool isSqlite(); bool isOk() { return mSuccess; } bool dbConnect( const QString& driver, const QString& dbName, const QString& dbUser, const QString& dbHost, const QString& dbPasswd ); /** * check if the database is open and contains the table kraftsystem. Still * the Schema version can be invalid, check currentSchemaVersion(). */ bool databaseExists(); /* * required and current schema versions. Must be equal for a healty * Kraft database. If currentSchemaVersion is smaller than requiredSchemaVersion, * the db needs an update. */ int currentSchemaVersion(); int requiredSchemaVersion(); void setSchemaVersion( const QString& ); // database aware current time stamp QString currentTimeStamp( const QDateTime& dt = QDateTime() ); /** * Euro sign encoding to work around a problem with mysql */ QString mysqlEuroEncode( const QString& ) const; QString mysqlEuroDecode( const QString& ) const; QString replaceTagsInWord( const QString& w, QMap replaceMap ) const; // void checkDatabaseSetup( QWidget* ); SqlCommandList parseCommandFile( int currentVersion ); SqlCommandList parseCommandFile( const QString& file ); QList parseMetaFile( int currentVersion ); int processSqlCommands( const SqlCommandList& ); bool checkTableExistsSqlite(const QString& name, const QStringList& lookupCols); KraftDB(); dbID archiveDocument( KraftDoc *docPtr ); void loadDocument(const QString& id, KraftDoc *docPtr); bool saveDocument(KraftDoc *docPtr); void enableTimerRefresh(bool runTimer); private slots: void slotCheckDocDatabaseChanged(); signals: void statusMessage( const QString& ); void processedSqlCommand( bool ); void docDatabaseChanged(); private: // Private attributes void close(); int checkConnect(const QString&, const QString&, const QString&, const QString& , int port); /** The default database */ QSqlDatabase m_db; QWidget *mParent; bool mSuccess; const QString EuroTag; QString mDatabaseDriver; QString mDatabaseName; DbInitDialog *mInitDialog; SetupAssistant *mSetupAssistant; QTimer _timer; int _amountOfDocs, _amountOfArchs; // if this is set to false, the slotCheckDatabaseChanged() can be called // to update the members that hold the amount of docs, but the update signal // is not sent out. bool _emitDBChangeSignal; }; #endif kraft-1.1/src/kraftdoc.cpp000066400000000000000000000331551450127457600155740ustar00rootroot00000000000000/*************************************************************************** KraftDoc.cpp - Kraft document class ------------------- begin : Mit Dez 31 19:24:05 CET 2003 copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include // application specific includes #include "kraftsettings.h" #include "kraftdoc.h" #include "portal.h" #include "kraftview.h" #include "docposition.h" #include "documentsaverdb.h" #include "defaultprovider.h" #include "documentman.h" #include "doctype.h" #include "documentman.h" #include "kraftdb.h" #include "format.h" // FIXME: Make KraftDoc inheriting DocDigest! KraftDoc::KraftDoc(QWidget *parent) : QObject(parent), _modified(false), mIsNew(true), mDocTypeChanged(false) { } KraftDoc::~KraftDoc() { } KraftDoc& KraftDoc::operator=( KraftDoc& origDoc ) { if ( this == &origDoc ) return *this; DocPositionListIterator it( origDoc.mPositions ); while ( it.hasNext() ) { DocPosition *dp = static_cast( it.next() ); DocPosition *newPos = new DocPosition(); *newPos = *dp; newPos->setDbId( -1 ); mPositions.append( newPos ); // qDebug () << "Appending position " << dp->dbId().toString(); } _modified = origDoc._modified; mIsNew = true; mAddressUid = origDoc.mAddressUid; mProjectLabel = origDoc.mProjectLabel; mPredecessor = origDoc.mPredecessor; mPredecessorDbId = origDoc.mPredecessorDbId; mAddress = origDoc.mAddress; mPreText = origDoc.mPreText; mPostText = origDoc.mPostText; mDocType = origDoc.mDocType; mDocTypeChanged = false; mSalut = origDoc.mSalut; mGoodbye = origDoc.mGoodbye; mIdent = origDoc.mIdent; mWhiteboard = origDoc.mWhiteboard; // Two qualifiers for the locale settings. mCountry = origDoc.mCountry; mLanguage = origDoc.mLanguage; mDate = origDoc.mDate; mLastModified = origDoc.mLastModified; // setPositionList( origDoc.mPositions ); mRemovePositions = origDoc.mRemovePositions; // mDocID = origDoc.mDocID; return *this; } void KraftDoc::closeDocument() { deleteItems(); } void KraftDoc::setPredecessor( const QString& w ) { mPredecessor = w; } bool KraftDoc::openDocument(const QString& id ) { KraftDB::self()->loadDocument(id, this); mDocTypeChanged = false; _modified=false; mIsNew = false; return true; } bool KraftDoc::reloadDocument() { mPositions.clear(); mRemovePositions.clear(); return openDocument( mDocID.toString() ); } bool KraftDoc::saveDocument( ) { bool result = false; result = KraftDB::self()->saveDocument(this); if(result) { if ( isNew() ) { setLastModified( QDateTime::currentDateTime() ); } // Go through the whole document and remove the positions // that are to delete because they now were deleted in the // database. DocPositionListIterator it( mPositions ); while( it.hasNext() ) { DocPositionBase *dp = it.next(); if( dp->toDelete() ) { // qDebug () << "Removing pos " << dp->dbId().toString() << " from document object"; mPositions.removeAll( dp ); } } _modified = false; } return result; } QString KraftDoc::docIdentifier() const { const QString id = ident(); if( id.isEmpty() ) { return docType(); } return i18nc("First argument is the doctype, like Invoice, followed by the ID", "%1 (Id %2)", docType(), id ); } void KraftDoc::deleteItems() { qDeleteAll(mPositions); mPositions.clear(); } void KraftDoc::setDocType( const QString& s ) { if( s != mDocType ) { mDocType = s; mDocTypeChanged = true; } } void KraftDoc::setPositionList( DocPositionList newList, bool isNew) { mPositions.clear(); DocPositionListIterator it( newList ); while ( it.hasNext() ) { DocPositionBase *dpb = it.next(); DocPosition *dp = static_cast( dpb ); DocPosition *newDp = createPosition( dp->type() ); *newDp = *dp; if(isNew) { newDp->setDbId(-1); } } } DocPosition* KraftDoc::createPosition( DocPositionBase::PositionType t ) { DocPosition *dp = new DocPosition( t ); mPositions.append( dp ); return dp; } void KraftDoc::slotRemovePosition( int pos ) { // qDebug () << "Removing position " << pos; foreach( DocPositionBase *dp, mPositions ) { // qDebug () << "Comparing " << pos << " with " << dp->dbId().toString(); if( dp->dbId() == pos ) { if( ! mPositions.removeAll( dp ) ) { // qDebug () << "Could not remove!"; } else { // qDebug () << "Successfully removed the position " << dp; mRemovePositions.append( dp->dbId() ); // remember to delete } } } } void KraftDoc::slotMoveUpPosition( int dbid ) { // qDebug () << "Moving position " << dbid << " up"; if( mPositions.count() < 1 ) return; int curPos = -1; // Search the one to move up for( int i = 0; curPos == -1 && i < mPositions.size(); i++ ) { if( (mPositions.at(i))->dbId() == dbid ) { curPos = i; // get out of the loop } } // qDebug () << "Found: "<< curPos << ", count: " << mPositions.count(); if( curPos < mPositions.size()-1 ) { mPositions.swap( curPos, curPos+1 ); } } void KraftDoc::slotMoveDownPosition( int dbid ) { // qDebug () << "Moving position " << dbid << " down"; if( mPositions.count() < 1 ) return; int curPos = -1; // Search the one to move up for( int i = 0; curPos == -1 && i < mPositions.size(); i++ ) { if( (mPositions.at(i))->dbId() == dbid ) { curPos = i; // get out of the loop } } // qDebug () << "Found: "<< curPos << ", count: " << mPositions.count(); if( curPos > 0 ) { mPositions.swap( curPos, curPos-1 ); } } int KraftDoc::slotAppendPosition( const DocPosition& pos ) { DocPosition *dp = createPosition(); *dp = pos; // FIXME: Proper assignment operator return mPositions.count(); } Geld KraftDoc::nettoSum() const { return positions().nettoPrice(); } Geld KraftDoc::bruttoSum() const { Geld g = nettoSum(); g += vatSum(); return g; } Geld KraftDoc::fullTaxSum() const { return positions().fullTaxSum(DocumentMan::self()->tax(date())); } Geld KraftDoc::reducedTaxSum() const { return positions().reducedTaxSum(DocumentMan::self()->reducedTax(date())); } Geld KraftDoc::vatSum() const { return positions().taxSum( DocumentMan::self()->tax( date() ), DocumentMan::self()->reducedTax( date() ) ); // return Geld( nettoSum() * DocumentMan::self()->vat()/100.0 ); } QString KraftDoc::country() const { QLocale *loc = DefaultProvider::self()->locale(); return loc->countryToString(loc->country()); } QString KraftDoc::language() const { QLocale *loc = DefaultProvider::self()->locale(); return loc->languageToString(loc->language()); } QString KraftDoc::partToString( Part p ) { if ( p == Header ) return i18nc( "Document part header", "Header" ); else if ( p == Footer ) return i18nc( "Document part footer", "Footer" ); else if ( p == Positions ) return i18nc( "Document part containing the items", "Items" ); return i18n( "Unknown document part" ); } QString KraftDoc::preTextRaw() const { return mPreText; } QString KraftDoc::postTextRaw() const { return mPostText; } /** * @brief KraftDoc::resolveMacros * @param txtWithMacros - the string that might contain any macros * @param dposList - the list of document items * @return - the text with resolved macros * * The following macros are supported: * 1. SUM_PER_TAG(tag): The netto sum of all items that are tagged with the named tag * 2. IF_ANY_HAS_TAG(tag) .. END_HAS_TAG: The text between the macros only appears if * at least one of all items is tagged with the named tag * 3. ITEM_COUNT_WITH_TAG(tag): This macro is replaced with the amount of items that * are tagged with this tag * * 4. DATE_ADD_DAYS(days): Adds the amount of days to the date delivered in the call parameters */ QString KraftDoc::resolveMacros(const QString& txtWithMacros, const DocPositionList dposList, const QDate& date, double fullTax, double redTax) const { QString myStr{txtWithMacros}; QMap seenTags; QRegExp rxIf("\\s{1}IF_ANY_HAS_TAG\\(\\s*(\\w+)\\s*\\)"); QRegExp rxEndif("\\s{1}END_HAS_TAG"); QRegExp rxAmount("ITEM_COUNT_WITH_TAG\\(\\s*(\\w+)\\s*\\)"); QRegExp rxAddDate("DATE_ADD_DAYS\\(\\s*(\\-{0,1}\\d+)\\s*\\)"); // look for tag SUM_PER_TAG( HNDL ) QRegExp rx("NETTO_SUM_PER_TAG\\(\\s*(\\w+)\\s*\\)"); QRegExp rxBrutto("BRUTTO_SUM_PER_TAG\\(\\s*(\\w+)\\s*\\)"); QRegExp rxVat("VAT_SUM_PER_TAG\\(\\s*(\\w+)\\s*\\)"); int pos{0}; QMap bruttoSums; QMap vatSums; Geld nettoSum; while ((pos = rx.indexIn(myStr, pos)) != -1) { const QString lookupTag = rx.cap(1); bruttoSums[lookupTag] = Geld(); vatSums[lookupTag] = Geld(); for (DocPositionBase *pb : dposList) { DocPosition *p = static_cast(pb); if (!p->toDelete() && p->hasTag(lookupTag)) { Geld netto = p->overallPrice(); Geld tax; if (p->taxType() == DocPositionBase::TaxType::TaxFull) tax = netto.percent(fullTax); else if (p->taxType() == DocPositionBase::TaxType::TaxReduced) tax = netto.percent(redTax); bruttoSums[lookupTag] += netto; bruttoSums[lookupTag] += tax; vatSums[lookupTag] += tax; nettoSum += netto; } } myStr.replace(pos, rx.matchedLength(), nettoSum.toLocaleString()); } // replace the Brutto- and vat tags if exist pos = 0; while ((pos = rxBrutto.indexIn(myStr, pos)) != -1) { const QString lookupTag = rxBrutto.cap(1); if (bruttoSums.contains(lookupTag)) { myStr.replace(pos, rxBrutto.matchedLength(), bruttoSums[lookupTag].toLocaleString()); } else { qDebug() << "No Brutto sums computed for" << lookupTag; } } // vat tags pos = 0; while ((pos = rxVat.indexIn(myStr, pos)) != -1) { const QString lookupTag = rxVat.cap(1); if (vatSums.contains(lookupTag)) { myStr.replace(pos, rxVat.matchedLength(), vatSums[lookupTag].toLocaleString()); } } // generate a list of all tags in any position for (DocPositionBase *pb : dposList) { DocPosition *p = static_cast(pb); if (!p->toDelete()) { const auto tags = p->tags(); for (const QString& lookupTag : tags) { if (seenTags.contains(lookupTag)) { seenTags[lookupTag] = 1+seenTags[lookupTag]; } else { seenTags[lookupTag] = 1; } } } } pos = 0; while ((pos = rxAmount.indexIn(myStr, pos)) != -1) { const QString lookupTag = rxAmount.cap(1); int amount{0}; if (seenTags.contains(lookupTag)) { amount = seenTags[lookupTag]; } myStr.replace(pos, rxAmount.matchedLength(), QString::number(amount)); } pos = 0; while ((pos = rxAddDate.indexIn(myStr, pos)) != -1) { const QString addDaysStr = rxAddDate.cap(1); qint64 addDays = addDaysStr.toInt(); QDate newDate = date.addDays(addDays); const QString newDateStr = Format::toDateString(newDate, KraftSettings::self()->dateFormat()); myStr.replace(pos, rxAddDate.matchedLength(), newDateStr); } // IF_ANY_HAS_TAG(tag) ..... END_HAS_TAG // check the IF_HAS_TAG(tag) ... END_HAS_TAG macro pos = 0; while ((pos = rxIf.indexIn(myStr, pos)) != -1) { const QString lookupTag = rxIf.cap(1); int endpos = myStr.lastIndexOf(rxEndif); if (endpos == -1) endpos = myStr.length(); if (seenTags.contains(lookupTag)) { myStr.remove(endpos, 12 /* length of END_HAS_TAG */); myStr.remove(pos, rxIf.matchedLength()); } else { // the tag was not seen, so this needs to be deleted. int len = endpos-pos+12; myStr.remove(pos, len); } } return myStr; } QString KraftDoc::preText() const { double fullTax = DocumentMan::self()->tax(date()); double redTax = DocumentMan::self()->reducedTax(date()); const QString myStr = resolveMacros(mPreText, positions(), date(), fullTax, redTax); return myStr; } QString KraftDoc::postText() const { double fullTax = DocumentMan::self()->tax(date()); double redTax = DocumentMan::self()->reducedTax(date()); const QString myStr = resolveMacros(mPostText, positions(), date(), fullTax, redTax); return myStr; } kraft-1.1/src/kraftdoc.h000066400000000000000000000170401450127457600152340ustar00rootroot00000000000000/*************************************************************************** kraftdoc.h - Kraft document class ------------------- begin : Mit Dez 31 19:24:05 CET 2003 copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRAFTDOC_H #define KRAFTDOC_H // include files for QT #include #include #include #include "docposition.h" #include "dbids.h" #include "docguardedptr.h" // forward declaration of the Kraft classes class DocumentSaverBase; class Geld; class KraftView; class KraftDoc : public QObject { Q_OBJECT Q_PROPERTY(QString docType READ docType) Q_PROPERTY(QString address READ address) Q_PROPERTY(QString clientUid READ addressUid) Q_PROPERTY(QString ident READ ident) Q_PROPERTY(QString salut READ salut) Q_PROPERTY(QString goodbye READ goodbye) Q_PROPERTY(QString preText READ preText) Q_PROPERTY(QString postText READ postText) Q_PROPERTY(QString projectLabel READ projectLabel) Q_PROPERTY(QString docIDStr READ docIdStr) Q_PROPERTY(QString docIdentifier READ docIdentifier) Q_PROPERTY(QString nettoSumStr READ nettoSumStr) Q_PROPERTY(QString bruttoSumStr READ bruttoSumStr) Q_PROPERTY(QString taxSumStr READ vatSumStr) Q_PROPERTY(QString fullTaxSumStr READ fullTaxSumStr) Q_PROPERTY(QString reducedTaxSumStr READ reducedTaxSumStr) public: enum Part { Header, Positions, Footer, Unknown }; static QString partToString( Part ); /** Constructor for the fileclass of the application */ KraftDoc(QWidget *parent = nullptr); /** Destructor for the fileclass of the application */ ~KraftDoc(); KraftDoc& operator=( KraftDoc& ); /** sets the modified flag for the document after a modifying action * on the view connected to the document.*/ void setModified(bool _m=true){ _modified=_m; } /** returns if the document is modified or not. Use this to determine * if your document needs saving by the user on closing.*/ bool isModified(){ return _modified; } /** deletes the document's contents */ void deleteItems(); /** closes the current document */ void closeDocument(); /** loads the document by filename and format and emits the updateViews() signal */ bool openDocument(const QString& ); /** fetch the document from database back */ bool reloadDocument(); /** saves the document under filename and format.*/ bool saveDocument( ); QLocale* locale(); DocPosition* createPosition( DocPositionBase::PositionType t = DocPositionBase::Position ); DocPositionList positions() const { return mPositions; } void setPositionList(DocPositionList , bool isNew = false); QDate date() const { return mDate; } void setDate( QDate d ) { mDate = d; } QDateTime lastModified() const { return mLastModified; } void setLastModified( QDateTime d ) { mLastModified = d; } QString docType() const { return mDocType; } void setDocType( const QString& s ); bool docTypeChanged() { return mDocTypeChanged; } QString addressUid() const { return mAddressUid; } void setAddressUid( const QString& id ) { mAddressUid = id; } QString address() const { return mAddress; } void setAddress( const QString& adr ) { mAddress = adr; } bool isNew() const { return mIsNew; } QString ident() const { return mIdent; } void setIdent( const QString& str ) { mIdent = str; } QString salut() const { return mSalut; } void setSalut( const QString& str ) { mSalut = str; } QString goodbye() const { return mGoodbye; } void setGoodbye( const QString& str ) { mGoodbye = str; } // take a string with macros and generate the text replacements for the macros // with the help of the position list QString resolveMacros(const QString& txtWithMacros, const DocPositionList dposList, const QDate &date, double fullTax, double redTax) const; // preText is the variant with expanded macros QString preText() const; // preTextRaw is the variant with macros not expanded QString preTextRaw() const; void setPreTextRaw( const QString& str ) { mPreText = str; } QString postText() const; // postTextRaw is the variant with macros not expanded QString postTextRaw() const; void setPostTextRaw( const QString& str ) { mPostText = str; } QString whiteboard() const { return mWhiteboard; } void setWhiteboard( const QString& w ) { mWhiteboard = w; } QString projectLabel() const { return mProjectLabel; } void setProjectLabel( const QString& w ) { mProjectLabel = w; } QString predecessor() const { return mPredecessor; } void setPredecessor( const QString& w ); QString predecessorDbId() const { return mPredecessorDbId; } void setPredecessorDbId( const QString& pId ) { mPredecessorDbId = pId; } void setDocID( dbID id ) { mDocID = id; } dbID docID() const { return mDocID; } QString docIdStr() const { return docID().toString(); } QString docIdentifier() const; DBIdList removePositionList() { return mRemovePositions; } Geld nettoSum() const; QString nettoSumStr() const { return nettoSum().toLocaleString(); } Geld bruttoSum() const; QString bruttoSumStr() const { return bruttoSum().toLocaleString(); } Geld fullTaxSum() const; QString fullTaxSumStr() const { return fullTaxSum().toLocaleString(); } Geld reducedTaxSum() const; QString reducedTaxSumStr() const { return reducedTaxSum().toLocaleString(); } Geld vatSum() const; QString vatSumStr() const { return vatSum().toLocaleString(); } QString country() const; QString language() const; public slots: /** calls redrawDocument() on all views connected to the document object and is * called by the view by which the document has been changed. * As this view normally repaints itself, it is excluded from the paintEvent. */ int slotAppendPosition( const DocPosition& ); // The following slots take get the db id as argument void slotRemovePosition( int ); void slotMoveUpPosition( int ); void slotMoveDownPosition( int ); private: /** the modified flag of the current document */ bool _modified; bool mIsNew; QString mAddressUid; QString mProjectLabel; QString mAddress; // mPreText and postText always have the raw variant without expanded macros QString mPreText; QString mPostText; QString mDocType; bool mDocTypeChanged; QString mSalut; QString mGoodbye; QString mIdent; QString mWhiteboard; QString mPredecessor; QString mPredecessorDbId; // Two qualifiers for the locale settings. QString mCountry; QString mLanguage; QDate mDate; QDateTime mLastModified; DocPositionList mPositions; DBIdList mRemovePositions; dbID mDocID; }; #endif // KraftDoc_H kraft-1.1/src/kraftdocedit.cpp000066400000000000000000000006711450127457600164370ustar00rootroot00000000000000#include "kraftdocedit.h" #include KraftDocEdit::KraftDocEdit( QWidget *parent ) : QWidget( parent ) { } void KraftDocEdit::setTitle( const QString &title ) { mTitle = title; } QString KraftDocEdit::title() const { return mTitle; } void KraftDocEdit::setColor( const QColor &color ) { mColor = color; } QColor KraftDocEdit::color() const { return mColor; } void KraftDocEdit::slotModified() { emit modified(); } kraft-1.1/src/kraftdocedit.h000066400000000000000000000006371450127457600161060ustar00rootroot00000000000000#ifndef KRAFTDOCEDIT_H #define KRAFTDOCEDIT_H #include "ui_docheader.h" class KraftDocEdit : public QWidget { Q_OBJECT public: KraftDocEdit( QWidget *parent ); void setTitle( const QString & ); QString title() const; void setColor( const QColor & ); QColor color() const; signals: void modified(); public slots: void slotModified(); private: QString mTitle; QColor mColor; }; #endif kraft-1.1/src/kraftdocfooteredit.cpp000066400000000000000000000063461450127457600176630ustar00rootroot00000000000000/*************************************************************************** kraftdocfooteredit.cpp - inherited class from designer generated class ------------------- begin : Sept. 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "kraftdocfooteredit.h" #include "kraftdb.h" #include #include #include #include #include KraftDocFooterEdit::KraftDocFooterEdit( QWidget *parent ) : KraftDocEdit( parent ), mDocFooterEdit( 0 ), mCustomGreetingIndex(-1) { QVBoxLayout *topLayout = new QVBoxLayout; Q_ASSERT( parent ); setLayout( topLayout ); mDocFooterEdit = new Ui::DocFooterEdit; QWidget *w = new QWidget; mDocFooterEdit->setupUi(w); topLayout->addWidget(w); mDocFooterEdit->m_cbGreeting->insertItems(-1, KraftDB::self()->wordList( "greeting" ) ); connect( mDocFooterEdit->m_cbGreeting, SIGNAL( activated( int ) ), SLOT( slotModified() ) ); connect( mDocFooterEdit->m_cbGreeting, SIGNAL(currentIndexChanged(int)), this, SLOT(slotGreeterIndexChanged(int))); connect( mDocFooterEdit->m_cbGreeting, SIGNAL(editTextChanged(QString)), this, SLOT(slotGreeterEditTextChanged(QString))); connect( mDocFooterEdit->m_teSummary, SIGNAL( textChanged() ), SLOT( slotModified() ) ); setTitle( i18n( "Document Footer" ) ); setColor( "#f0ff9a" ); } void KraftDocFooterEdit::slotSetGreeting( const QString& newText ) { slotGreeterEditTextChanged(newText); } QString KraftDocFooterEdit::greeting() { return mGreeting; } void KraftDocFooterEdit::slotGreeterIndexChanged(int newIndex) { mGreeting = mDocFooterEdit->m_cbGreeting->itemText(newIndex); slotModified(); } void KraftDocFooterEdit::slotGreeterEditTextChanged(const QString& newText) { QComboBox *greeterCombo = qobject_cast(mDocFooterEdit->m_cbGreeting); if( !greeterCombo ) return; // qDebug () << "II Combo box text changed to" << newText << "in" << greeterCombo; const QStringList texts = KraftDB::self()->wordList("greeting"); int indx = greeterCombo->currentIndex(); if( !texts.contains(newText)) { if( mCustomGreetingIndex == -1 ) { // no custom Entry yet greeterCombo->insertItem(0, newText); mCustomGreetingIndex = 0; } indx = mCustomGreetingIndex; } greeterCombo->setItemText(indx, newText); greeterCombo->setCurrentIndex(indx); mGreeting = newText; slotModified(); } kraft-1.1/src/kraftdocfooteredit.h000066400000000000000000000032201450127457600173140ustar00rootroot00000000000000/*************************************************************************** kraftdocfooteredit.h - inherited class from designer generated class ------------------- begin : Sept. 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRAFTDOCFOOTEREDIT_H #define KRAFTDOCFOOTEREDIT_H #include "ui_docfooter.h" #include "kraftdocedit.h" class KraftDocFooterEdit : public KraftDocEdit { Q_OBJECT public: KraftDocFooterEdit( QWidget *parent=0 ); // FIXME: Remove access to internal widgets Ui::DocFooterEdit *ui() { return mDocFooterEdit; } QString greeting(); public slots: void slotGreeterIndexChanged(int newIndex); void slotGreeterEditTextChanged(const QString& newText); void slotSetGreeting( const QString& newText ); private: Ui::DocFooterEdit *mDocFooterEdit; QString mGreeting; int mCustomGreetingIndex; }; #endif kraft-1.1/src/kraftdocheaderedit.cpp000066400000000000000000000054401450127457600176070ustar00rootroot00000000000000/*************************************************************************** kraftdocheaderview.cpp - inherited class from designer generated class ------------------- begin : Sept. 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "kraftdocheaderedit.h" #include #include #include #include #include #include "addressprovider.h" #include "defaultprovider.h" KraftDocHeaderEdit::KraftDocHeaderEdit( QWidget *parent ) : KraftDocEdit( parent ) { QVBoxLayout *topLayout = new QVBoxLayout; setLayout( topLayout ); mDocHeaderEdit = new Ui::DocHeaderEdit; QWidget *w = new QWidget; mDocHeaderEdit->setupUi( w ); topLayout->addWidget( w ); mDocHeaderEdit->mButtLang->setIcon(DefaultProvider::self()->icon("language")); connect( mDocHeaderEdit->m_cbType, SIGNAL( currentIndexChanged(int)), SLOT( slotModified() ) ); connect( mDocHeaderEdit->m_dateEdit, SIGNAL( dateChanged( QDate ) ), SLOT( slotModified() ) ); connect( mDocHeaderEdit->m_postAddressEdit, SIGNAL( textChanged() ), SLOT( slotModified() ) ); connect( mDocHeaderEdit->m_letterHead, SIGNAL( currentTextChanged(QString)), SLOT(slotModified() ) ); connect( mDocHeaderEdit->m_teEntry, SIGNAL( textChanged() ), SLOT( slotModified() ) ); connect( mDocHeaderEdit->m_whiteboardEdit, SIGNAL( textChanged() ), SLOT( slotModified() ) ); connect( mDocHeaderEdit->mProjectLabelEdit, SIGNAL( textChanged(QString) ), SLOT(slotModified() ) ); connect( mDocHeaderEdit->pb_pickAddressee, SIGNAL(clicked()), SIGNAL(pickAddressee())); setTitle( i18n( "Document Header" ) ); setColor( "#9af0ff" ); // if the Akonadi-Backend is down, just show a text QScopedPointer addressProvider; addressProvider.reset(new AddressProvider); if( !addressProvider->backendUp() ) { mDocHeaderEdit->pb_pickAddressee->hide(); mDocHeaderEdit->m_labName->setText( i18n("Manually set in address field.")); } } kraft-1.1/src/kraftdocheaderedit.h000066400000000000000000000026501450127457600172540ustar00rootroot00000000000000/*************************************************************************** kraftdocheaderview.h - inherited class from designer generated class ------------------- begin : Sept. 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRAFTDOCHEADEREDIT_H #define KRAFTDOCHEADEREDIT_H #include "ui_docheader.h" #include "kraftdocedit.h" class KraftDocHeaderEdit : public KraftDocEdit { Q_OBJECT public: KraftDocHeaderEdit( QWidget* ); // FIXME: Remove access to internal widgets Ui::DocHeaderEdit *docHeaderEdit() { return mDocHeaderEdit; } signals: void pickAddressee(); private: Ui::DocHeaderEdit *mDocHeaderEdit; }; #endif kraft-1.1/src/kraftdocpositionsedit.cpp000066400000000000000000000105021450127457600204010ustar00rootroot00000000000000/*************************************************************************** kraftdocpositionsedit.cpp - Doc item editor widget ------------------- begin : copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "kraftdocpositionsedit.h" #include #include #include #include #include #include #include #include #include #include "kraftview.h" KraftViewScroll::KraftViewScroll( QWidget *parent ): QScrollArea( parent ) { myWidget = new QWidget; myWidget->setAutoFillBackground(false); layout = new QVBoxLayout; layout->setAlignment(Qt::AlignTop); layout->setSizeConstraint( QLayout::SetMinAndMaxSize ); layout->setContentsMargins( 0,0,0,0 ); layout->setSpacing(0); myWidget->setLayout(layout); setWidget(myWidget); setWidgetResizable(true); myWidget->resize(0,0); myWidget->setMinimumHeight(0); myWidget->setMaximumHeight(0); myWidget->setContentsMargins(0, 0, 0, 0); } void KraftViewScroll::addChild( QWidget *child, int index ) { int y1 = myWidget->height(); layout->insertWidget(index, child); int y2 = y1+child->height(); myWidget->resize( child->width(), y2); myWidget->setMinimumHeight(y2); myWidget->setMaximumHeight(y2); } void KraftViewScroll::removeChild( PositionViewWidget *child ) { layout->removeWidget( child ); // from the scrollview } void KraftViewScroll::moveChild( PositionViewWidget *child, int index) { layout->removeWidget(child); layout->insertWidget(index, child); } int KraftViewScroll::indexOf(PositionViewWidget *child) { return layout->indexOf(child); } // ######################################################### KraftDocPositionsEdit::KraftDocPositionsEdit( QWidget *parent ) : KraftDocEdit( parent ) { QBoxLayout *topLayout = new QVBoxLayout(); topLayout->setMargin( 0 ); //TODO PORT QT5 topLayout->setSpacing( 0 ); // QDialog::spacingHint() ); QHBoxLayout *upperHBoxLayout = new QHBoxLayout; //upperHBoxLayout->setFrameStyle( QFrame::Box + QFrame::Sunken ); //TODO PORT QT5 upperHBoxLayout->setMargin( QDialog::marginHint()/2 ); topLayout->addLayout( upperHBoxLayout ); QPushButton *button = new QPushButton( i18n("Add Item...") ); connect( button, SIGNAL( clicked() ), SIGNAL( addPositionClicked() ) ); button->setToolTip( i18n( "Add a normal item to the document manually." ) ); upperHBoxLayout->addWidget(button); upperHBoxLayout->setSpacing( 3 ); m_discountBtn = new QPushButton( i18n("Add Discount Item") ); connect( m_discountBtn, SIGNAL( clicked() ), SIGNAL( addExtraClicked() ) ); upperHBoxLayout->addWidget(m_discountBtn); m_discountBtn->setToolTip( i18n( "Adds an item to the document that allows discounts on other items in the document" ) ); #if 0 // commented, rarely used feature. button = new QPushButton( i18n("Import Items...") ); connect( button, SIGNAL( clicked() ), SIGNAL( importItemsClicked() ) ); upperHBoxLayout->addWidget(button); button->setToolTip( i18n( "Opens a dialog where multiple items can be imported from a text file." ) ); #endif QWidget *spaceEater = new QWidget( ); spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Minimum ) ); upperHBoxLayout->addWidget(spaceEater); m_positionScroll = new KraftViewScroll( this ); topLayout->addWidget( m_positionScroll ); setTitle( i18n( "Document Items" ) ); setColor( "#9affa9" ); setLayout(topLayout); } void KraftDocPositionsEdit::setDiscountButtonVisible( bool visible ) { m_discountBtn->setVisible( visible ); } kraft-1.1/src/kraftdocpositionsedit.h000066400000000000000000000040721450127457600200530ustar00rootroot00000000000000/*************************************************************************** kraftdocpositionsedit.h - Doc item editor widget ------------------- begin : copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRAFTDOCPOSITIONSEDIT_H #define KRAFTDOCPOSITIONSEDIT_H #include "ui_docheader.h" #include "kraftdocedit.h" #include class KraftViewScroll; class PositionViewWidget; class KraftViewScroll : public QScrollArea { Q_OBJECT public: KraftViewScroll( QWidget* ); ~KraftViewScroll() { } void addChild( QWidget *child, int index ); void removeChild( PositionViewWidget *child ); void moveChild( PositionViewWidget *child, int index); int indexOf( PositionViewWidget *child); private: QWidget *myWidget; QVBoxLayout *layout; }; // ########################################################################### class KraftDocPositionsEdit : public KraftDocEdit { Q_OBJECT public: KraftDocPositionsEdit( QWidget* ); // FIXME: Remove access to internal widgets KraftViewScroll *positionScroll() { return m_positionScroll; } void setDiscountButtonVisible( bool visible ); signals: void addPositionClicked(); void addExtraClicked(); void importItemsClicked(); private: KraftViewScroll *m_positionScroll; QPushButton *m_discountBtn; }; #endif kraft-1.1/src/kraftglobals.h000066400000000000000000000026121450127457600161110ustar00rootroot00000000000000/*************************************************************************** kraftglobals.h - some global defines ------------------- begin : Don Jan 1 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRAFT_GLOBALS #define KRAFT_GLOBALS #include #include "geld.h" // schluessel um alle kalk-typen kostenPerKalcPart zurueckzugeben. #define ALL_KALKPARTS QLatin1String("all_calculation_parts") #define KALKPART_TIME QLatin1String("Time") #define KALKPART_FIX QLatin1String("Fix") #define KALKPART_MATERIAL QLatin1String("Material") // typedef long Geld; #endif kraft-1.1/src/kraftsettings.kcfg000066400000000000000000000160261450127457600170150ustar00rootroot00000000000000 true true thunderbird 10.0 trml2pdf %y%w-%i false 3 0 kraft-1.1/src/kraftsettings.kcfgc000066400000000000000000000001161450127457600171510ustar00rootroot00000000000000File=kraftsettings.kcfg ClassName=KraftSettings Singleton=true Mutators=true kraft-1.1/src/krafttemplate.cpp000066400000000000000000000001001450127457600166220ustar00rootroot00000000000000#include "krafttemplate.h" KraftTemplate::KraftTemplate() { } kraft-1.1/src/krafttemplate.h000066400000000000000000000002031450127457600162730ustar00rootroot00000000000000#ifndef KRAFTTEMPLATE_H #define KRAFTTEMPLATE_H class KraftTemplate { public: KraftTemplate(); }; #endif // KRAFTTEMPLATE_H kraft-1.1/src/kraftui.rc000066400000000000000000000015441450127457600152630ustar00rootroot00000000000000 &Document Settings Document Actions kraft-1.1/src/kraftview.cpp000066400000000000000000001402771450127457600160050ustar00rootroot00000000000000/*************************************************************************** kraftview.cpp - Interactive document view ------------------- begin : Mit Dez 31 19:24:05 CET 2003 copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // application specific includes #include "kraftdb.h" #include "kraftsettings.h" #include "kraftview.h" #include "kraftdoc.h" #include "tagman.h" #include "ui_docheader.h" #include "documentman.h" #include "docassistant.h" #include "positionviewwidget.h" #include "ui_docfooter.h" #include "docposition.h" #include "unitmanager.h" #include "docpostcard.h" #include "kataloglistview.h" #include "katalogman.h" #include "templkatalog.h" #include "templkataloglistview.h" #include "catalogselection.h" #include "kraftdocheaderedit.h" #include "kraftdocpositionsedit.h" #include "kraftdocfooteredit.h" #include "inserttempldialog.h" #include "defaultprovider.h" #include "stockmaterial.h" #include "templtopositiondialogbase.h" #include "doctype.h" #include "catalogtemplate.h" #include "importitemdialog.h" #include "addressprovider.h" #include "addressselectordialog.h" #include "format.h" #include "stringutil.h" #define NO_TAX 0 #define RED_TAX 1 #define FULL_TAX 2 #define INDI_TAX 3 KraftView::KraftView(QWidget *parent) : KraftViewBase( parent ), mHelpLabel(nullptr), mRememberAmount( -1 ), mModified( false ), mTaxBefore( -1 ), mDocPosEditorIndx( -1 ) { setWindowTitle( i18n("Document" ) ); setModal( false ); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); mDetailHeader = new QLabel; mDetailHeader->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) ); mDetailHeader->setFrameStyle( QFrame::Box + QFrame::Plain ); mDetailHeader->setLineWidth( 1 ); mDetailHeader->setAutoFillBackground(true); mAddressProvider = new AddressProvider( this ); connect( mAddressProvider, SIGNAL(lookupResult(QString,KContacts::Addressee)), this, SLOT( slotAddresseeFound(QString,KContacts::Addressee))); QPalette palette; palette.setColor(mDetailHeader->backgroundRole(), QColor( "darkBlue" )); palette.setColor(mDetailHeader->foregroundRole(), QColor( "white ")); mDetailHeader->setPalette( palette ); mDetailHeader->setTextFormat( Qt::PlainText ); mDetailHeader->setFixedHeight( 40 ); // FIXME QFont f = mDetailHeader->font(); f.setPointSize( qRound( 1.4 * f.pointSize() ) ); f.setBold( true ); mDetailHeader->setFont( f ); mainLayout->addWidget( mDetailHeader ); mCSplit = new QSplitter(this); mainLayout->addWidget( mCSplit ); mViewStack = new QStackedWidget; mCSplit->addWidget( mViewStack ); // qDebug () << "mViewSTack height is " << mViewStack->height(); mAssistant = new DocAssistant( mCSplit ); mCSplit->addWidget( mAssistant ); /* catalog template selection signal */ connect(mAssistant, &DocAssistant::templatesToDocument, this, &KraftView::slotAddItems); /* signal to toggle the visibility of the template section in the assistant */ connect(mAssistant, &DocAssistant::toggleShowTemplates, this, &KraftView::slotShowTemplates); /* signal that brings a new address to the document */ connect(mAssistant, &DocAssistant::headerTextTemplate, this, &KraftView::slotNewHeaderText); connect(mAssistant, &DocAssistant::footerTextTemplate, this, &KraftView::slotNewFooterText); connect(mAssistant, &DocAssistant::selectPage, this, &KraftView::slotSwitchToPage); mAssistant->slotSelectDocPart( KraftDoc::Header ); setupMappers(); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(buttonBox); } KraftView::~KraftView() { // qDebug () << "KRAFTVIEW going away."; } void KraftView::setupMappers() { mDeleteMapper = new QSignalMapper( this ); connect( mDeleteMapper, SIGNAL( mapped(int)), this, SLOT( slotDeletePosition( int ) ) ); mMoveUpMapper = new QSignalMapper( this ); connect( mMoveUpMapper, SIGNAL( mapped(int)), this, SLOT( slotMovePositionUp( int ) ) ); mMoveDownMapper = new QSignalMapper( this ); connect( mMoveDownMapper, SIGNAL( mapped(int)), this, SLOT( slotMovePositionDown( int ) ) ); mLockPositionMapper = new QSignalMapper( this ); connect( mLockPositionMapper, SIGNAL( mapped( int )), this, SLOT( slotLockPosition( int ) ) ); mUnlockPositionMapper = new QSignalMapper( this ); connect( mUnlockPositionMapper, SIGNAL( mapped( int )), this, SLOT( slotUnlockPosition( int ) ) ); mModifiedMapper = new QSignalMapper( this ); connect( mModifiedMapper, SIGNAL( mapped( int ) ), this, SLOT( slotPositionModified( int ) ) ); // block signals as long as the widget is built up. // unblocking happens in redrawDocument() mModifiedMapper->blockSignals(true); } void KraftView::setup( DocGuardedPtr doc ) { KraftViewBase::setup(doc); if ( KraftSettings::self()->docViewSplitter().count() == 2 ) { mCSplit->setSizes( KraftSettings::self()->docViewSplitter() ); } setupDocHeaderView(); setupItems(); setupFooter(); setWindowTitle( m_doc->docIdentifier() ); slotSwitchToPage( KraftDoc::Header ); if( doc->isNew() ) { mModified = true; } } void KraftView::slotSwitchToPage( int id ) { // check if the wanted part is already visible if ( mViewStack->currentWidget() == mViewStack->widget( id ) ) return; mViewStack->setCurrentIndex( id ); KraftDocEdit *edit = static_cast( mViewStack->currentWidget() ); mDetailHeader->setText( edit->title() ); QPalette palette; palette.setColor(mDetailHeader->backgroundRole(), edit->color()); // FIXME: color palette.setColor(mDetailHeader->foregroundRole(), QColor( "#00008b" )); mDetailHeader->setPalette( palette ); mAssistant->slotSelectDocPart( mViewStack->currentIndex() ); } void KraftView::slotShowTemplates( bool ) { } void KraftView::setupDocHeaderView() { KraftDocHeaderEdit *edit = new KraftDocHeaderEdit(this); mHeaderId = mViewStack->addWidget( edit ); // , KraftDoc::Header ); m_headerEdit = edit->docHeaderEdit(); m_headerEdit->m_cbType->clear(); // m_headerEdit->m_cbType->insertStringList( DefaultProvider::self()->docTypes() ); m_headerEdit->m_cbType->insertItems(-1, DocType::allLocalised() ); m_headerEdit->mButtLang->hide(); const QString predecessorDbId = m_doc->predecessorDbId(); bool predecIsVisible = false; if( !predecessorDbId.isEmpty() ) { DocGuardedPtr predecDoc = DocumentMan::self()->openDocument(predecessorDbId); if( predecDoc ) { const QString id = predecDoc->docIdentifier(); const QString link = QString("%2").arg(predecessorDbId).arg(id); m_headerEdit->_labFollowup->setText( i18n("Successor of %1", link)); predecIsVisible = true; connect( m_headerEdit->_labFollowup, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkClicked(QString))); delete predecDoc; } } m_headerEdit->_labFollowup->setVisible(predecIsVisible); connect( m_headerEdit->m_cbType, SIGNAL( activated( const QString& ) ), this, SLOT( slotDocTypeChanged( const QString& ) ) ); connect( m_headerEdit->mButtLang, SIGNAL( clicked() ), this, SLOT( slotLanguageSettings() ) ); connect( edit, SIGNAL( modified() ), this, SLOT( slotModifiedHeader() ) ); connect( edit, SIGNAL(pickAddressee()), this, SLOT(slotPickAddressee()) ); } void KraftView::slotLinkClicked(const QString& link) { QUrl u(link); if( u.scheme() == "doc" && u.host() == "show" ) { QUrlQuery uq(link); const QString ident = uq.queryItemValue("id"); qDebug() << "Link clicked to open document " << ident; emit openROView( ident ); } } void KraftView::setupItems() { KraftDocPositionsEdit *edit = new KraftDocPositionsEdit(this); mDocPosEditorIndx = mViewStack->addWidget( edit ); // , KraftDoc::Positions ); m_positionScroll = edit->positionScroll(); connect( edit, SIGNAL( addPositionClicked() ), SLOT( slotAddNewItem() ) ); connect( edit, SIGNAL( addExtraClicked() ), SLOT( slotAddExtraPosition() ) ); connect( edit, SIGNAL( importItemsClicked() ), SLOT( slotImportItems() ) ); } void KraftView::redrawDocument( ) { KraftDoc *doc = getDocument(); if( !doc ) { // qDebug () << "ERR: No document available in view, return!"; } else { // qDebug () << "** Starting redraw of document " << doc; } /* header: date and document type */ QDate date = doc->date(); m_headerEdit->m_dateEdit->setDate( date ); m_headerEdit->m_cbType->setCurrentIndex(m_headerEdit->m_cbType->findText( doc->docType() )); /* header: address */ mContactUid = doc->addressUid(); QString address = doc->address(); // qDebug () << "Loaded address uid from database " << mContactUid; if( ! mContactUid.isEmpty() ) { mAddressProvider->lookupAddressee( mContactUid ); } if( !address.isEmpty() ) { // custom address stored in the document. // qDebug() << "custom address came in: " << address; m_headerEdit->m_postAddressEdit->setText( address ); } if( !doc->salut().isEmpty() ) { m_headerEdit->m_letterHead->insertItem(-1, doc->salut() ); m_headerEdit->m_letterHead->setCurrentIndex(m_headerEdit->m_letterHead->findText( doc->salut() )); } /* pre- and post text */ m_headerEdit->m_teEntry->setPlainText( doc->preTextRaw() ); m_headerEdit->m_whiteboardEdit->setPlainText( doc->whiteboard() ); m_headerEdit->mProjectLabelEdit->setText( doc->projectLabel() ); m_footerEdit->ui()->m_teSummary->setPlainText( doc->postTextRaw() ); const QString goodbye = doc->goodbye(); m_footerEdit->slotSetGreeting(goodbye); mAssistant->slotSetDocType( doc->docType() ); redrawDocPositions( ); slotDocTypeChanged( doc->docType() ); refreshPostCard(); mModifiedMapper->blockSignals(false); // mModified = false; } void KraftView::slotPickAddressee() { AddressSelectorDialog dialog(this); if( dialog.exec() ) { const KContacts::Addressee contact = dialog.addressee(); slotNewAddress( contact ); } } void KraftView::slotAddresseeFound( const QString& uid, const KContacts::Addressee& contact ) { if( contact.isEmpty() ) { const QString err = mAddressProvider->errorMsg(uid); if( !err.isEmpty() ) { qDebug () << "Error while looking up address for uid" << uid << ":" << err; } } else { slotNewAddress( contact, false ); qDebug () << "No contact found for uid " << uid; } } void KraftView::slotNewAddress( const KContacts::Addressee& contact, bool interactive ) { Addressee adr( contact ); if( contact.isEmpty() ) { return; } QString newAddress = mAddressProvider->formattedAddress( contact ); const QString currAddress = m_headerEdit->m_postAddressEdit->toPlainText(); bool replace = true; m_headerEdit->m_labName->setText( contact.realName() ); if( currAddress.isEmpty() ) { replace = true; } else if( currAddress != newAddress ) { // non empty and current different from new address // need to ask first if we overwrite if( interactive ) { QMessageBox msgBox; msgBox.setText(i18n( "The address label is not empty and different from the selected one.
            " "Do you really want to replace it with the text shown below?
            %1
            ", newAddress)); msgBox.setStandardButtons(QMessageBox::Yes| QMessageBox::No); msgBox.setDefaultButton(QMessageBox::Yes); int ret = msgBox.exec(); if ( ret != QMessageBox::Yes) { replace = false; } } else { // this happens when the document is loaded and the address arrives from addressbook replace = false; } } else if( currAddress == newAddress ) { // both are equal, no action needed replace = false; } if( replace ) { mContactUid = contact.uid(); m_headerEdit->m_postAddressEdit->setText( newAddress ); // Generate the welcome m_headerEdit->m_letterHead->clear(); QStringList li = generateLetterHead(adr.familyName(), adr.givenName()); m_headerEdit->m_letterHead->insertItems(-1, li ); m_headerEdit->m_letterHead->setCurrentIndex( KraftSettings::self()->salut() ); } } void KraftView::redrawDocPositions( ) { // If there is no position yet, come up with a help message. KraftDoc *doc = getDocument(); if ( ! doc ) return; DocPositionList list = doc->positions(); if ( list.count() == 0 ) { // the doc has no positions yet. Let's show a help page if ( ! mHelpLabel ) { mHelpLabel = new QLabel(this); mHelpLabel->setTextFormat(Qt::RichText); // mHelpLabel->setMinimumHeight(400); //TODO PORT QT5 mHelpLabel->setMargin( QDialog::marginHint() ); mHelpLabel->setText( i18n( "

            The Document Items List is still empty, but Items " "can be added now.

            " "To add items to the document either " "
              " "
            • Press the 'Add item' button above.
            • " "
            • Open the template catalog by clicking on the 'show Template' " "button on the right and pick one of the available templates.
            • " "
            " ) ); mHelpLabel->setWordWrap(true); mHelpLabel->setMinimumHeight(200); m_positionScroll->addChild( mHelpLabel, 0); } return; } else { if ( mHelpLabel ) { delete mHelpLabel; mHelpLabel = nullptr; } } // qDebug () << "starting to redraw " << list.count() << " positions!"; int cnt = 0; DocPositionListIterator it( list ); while( it.hasNext() ) { DocPositionBase *dp = it.next(); PositionViewWidget *w = mPositionWidgetList.widgetFromPosition( dp ); if( !w ) { w = createPositionViewWidget( dp, cnt); w->slotAllowIndividualTax( currentTaxSetting() == DocPositionBase::TaxIndividual ); } cnt++; // qDebug () << "now position " << dp->positionNumber(); } // now go through the positionWidgetMap and check if it contains elements // that are not any longer in the list of positions QMutableListIterator it2( mPositionWidgetList ); while( it2.hasNext() ) { PositionViewWidget *w = it2.next(); if( w && (list.contains( w->position() ) == 0) ) { // qDebug () << "Removing this one: " << w; m_positionScroll->removeChild( w ); it2.remove(); // mPositionWidgetList.erase( it2 ); break; } } } void KraftView::setMappingId( QWidget *widget, int pos ) { mDeleteMapper->setMapping( widget, pos ); mMoveUpMapper->setMapping( widget, pos ); mMoveDownMapper->setMapping( widget, pos ); mLockPositionMapper->setMapping( widget, pos ); mUnlockPositionMapper->setMapping( widget, pos ); mModifiedMapper->setMapping( widget, pos ); } // // create a new position widget. // The position parameter comes in as list counter, starting at 0 PositionViewWidget *KraftView::createPositionViewWidget( DocPositionBase *dp, int pos ) { PositionViewWidget *w = new PositionViewWidget( ); int cw = m_positionScroll->width(); if ( cw < 400 ) cw = 400; w->resize( cw, w->height() ); connect( w, SIGNAL( deletePosition() ), mDeleteMapper, SLOT( map() ) ); connect( w, SIGNAL( moveUp() ), mMoveUpMapper, SLOT( map() ) ); connect( w, SIGNAL( moveDown() ), mMoveDownMapper, SLOT( map() ) ); connect( w, SIGNAL( lockPosition() ), mLockPositionMapper, SLOT( map() ) ); connect( w, SIGNAL( unlockPosition() ), mUnlockPositionMapper, SLOT( map() ) ); connect( w, SIGNAL( positionModified()), mModifiedMapper, SLOT( map() ) ); setMappingId( w, pos ); QStringList units = UnitManager::self()->allUnits(); units.sort(); w->m_cbUnit->addItems(units); if( dp->dbId().toInt() < 0 ) { w->slotSetState( PositionViewWidget::New ); } /* do resizing and add the widget to the scrollview and move it to the final place */ if ( mHelpLabel ) { mHelpLabel->hide(); } mPositionWidgetList.insert( pos, w ); m_positionScroll->addChild( w, pos ); //Set the correct indexes when the widget is not appended if(pos < mPositionWidgetList.count()) { for(int i = pos+1; i < mPositionWidgetList.count(); ++i) { mPositionWidgetList.at(i)->setOrdNumber(i+1); setMappingId(mPositionWidgetList.at(i), i); } } w->setDocPosition(dp); w->setOrdNumber( pos+1 ); w->slotSetTax( dp->taxType() ); return w; } DocPositionBase::TaxType KraftView::currentTaxSetting() { // add 1 to the currentItem since that starts with zero. int taxKind = 1+( m_footerEdit->ui()->mTaxCombo->currentIndex() ); DocPositionBase::TaxType tt = DocPositionBase::TaxInvalid; if ( taxKind == 1 ) { // No Tax at all tt = DocPositionBase::TaxNone; } else if ( taxKind == 2 ) { // Reduced tax for all items tt = DocPositionBase::TaxReduced; } else if ( taxKind == 3 ) { // Full tax for all items tt = DocPositionBase::TaxFull; } else { // individual level tt = DocPositionBase::TaxIndividual; } return tt; } void KraftView::refreshPostCard() { DocPositionList positions = currentPositionList(); KraftDoc *kraftDoc = getDocument(); if( !kraftDoc) return; if ( mAssistant->postCard() ) { QDate d = m_headerEdit->m_dateEdit->date(); const QString dStr = Format::toDateString( d, KraftSettings::self()->dateFormat() ); double fullTax = DocumentMan::self()->tax(d); double redTax = DocumentMan::self()->reducedTax(d); const QString preText = kraftDoc->resolveMacros(m_headerEdit->m_teEntry->toPlainText(), positions, d, fullTax, redTax); const QString postText = kraftDoc->resolveMacros(m_footerEdit->ui()->m_teSummary->toPlainText(), positions, d, fullTax, redTax); mAssistant->postCard()->setHeaderData( m_headerEdit->m_cbType->currentText(), dStr, m_headerEdit->m_postAddressEdit->toPlainText(), getDocument()->ident(), preText ); mAssistant->postCard()->setPositions( positions, currentTaxSetting(), DocumentMan::self()->tax( d ), DocumentMan::self()->reducedTax( d ) ); mAssistant->postCard()->setFooterData( postText, m_footerEdit->greeting() ); mAssistant->postCard()->renderDoc( mViewStack->currentIndex() ); // id( mViewStack->visibleWidget() ) ); } DocPositionListIterator it( positions ); DocPositionBase *dp; while( it.hasNext()) { dp = it.next(); if ( dp->type() == DocPositionBase::ExtraDiscount ) { PositionViewWidget *w = ( static_cast( dp ) )->associatedWidget(); if( w ) { w->slotSetOverallPrice( ( static_cast( dp ) )->overallPrice() ); } else { // qDebug () << "Warning: Position object has no associated widget!"; } } } } void KraftView::setupFooter() { m_footerEdit = new KraftDocFooterEdit(this); mViewStack->addWidget( m_footerEdit ); // KraftDoc::Footer ); // ATTENTION: If you change the following inserts, make sure to check the code // in method currentPositionList! m_footerEdit->ui()->mTaxCombo->insertItem( NO_TAX, DefaultProvider::self()->icon("circle-0"), i18n( "Display no tax at all" )); m_footerEdit->ui()->mTaxCombo->insertItem( RED_TAX, DefaultProvider::self()->icon("circle-half-2"), i18n( "Calculate reduced tax for all items" )); m_footerEdit->ui()->mTaxCombo->insertItem( FULL_TAX, DefaultProvider::self()->icon("coin"), i18n( "Calculate full tax for all items" )); m_footerEdit->ui()->mTaxCombo->insertItem( INDI_TAX, i18n( "Calculate individual tax for each item")); // set the tax type combo correctly: If all items have the same tax type, take it. // If items have different, its the individual thing. DocPositionList list = m_doc->positions(); int tt = -1; DocPositionBase *dp = nullptr; DocPositionListIterator it( list ); int taxIndex = 0; while( it.hasNext()) { dp = it.next(); if ( tt == -1 ) tt = dp->taxTypeNumeric(); // store the first entry. else { if ( tt != dp->taxTypeNumeric() ) { taxIndex = INDI_TAX; } else { // old and new taxtype are the same. } } } if ( tt == -1 ) { // means that there is no item yet, the default tax type needs to be used. int deflt = KraftSettings::self()->defaultTaxType(); if ( deflt > 0 ) { deflt -= 1; } taxIndex = deflt; } else { if ( taxIndex == 0 ) { taxIndex = tt-1; } } connect( m_footerEdit->ui()->mTaxCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(slotTaxComboChanged(int))); m_footerEdit->ui()->mTaxCombo->setCurrentIndex( taxIndex ); slotTaxComboChanged( taxIndex ); mTaxBefore = taxIndex; connect(m_footerEdit,SIGNAL(modified()),this,SLOT(slotModifiedFooter())); } void KraftView::slotTaxComboChanged(int newId) { bool allowTaxSetting = false; if( mTaxBefore == newId ) return; if( mTaxBefore == INDI_TAX ) { // we're changing away from individual settings. WARNING needed. // qDebug () << "You switch away from item individual tax settings."; if( QMessageBox::question( this, i18n("Tax Settings Overwrite"), i18n("Really overwrite all individual tax settings of the items?") ) == QMessageBox::No ) { m_footerEdit->ui()->mTaxCombo->setCurrentIndex( INDI_TAX ); return; } } DocPositionBase::TaxType tax = DocPositionBase::TaxFull; if( newId == INDI_TAX ) { allowTaxSetting = true; } else if( newId == RED_TAX ) { tax = DocPositionBase::TaxReduced; } else if( newId == NO_TAX ) { tax = DocPositionBase::TaxNone; } PositionViewWidgetListIterator it( mPositionWidgetList ); while( it.hasNext() ) { PositionViewWidget *w = it.next(); w->slotAllowIndividualTax( allowTaxSetting ); w->slotSetTax( tax ); } mTaxBefore = newId; slotModifiedFooter(); } /* This is the flow in the move up method: 0 Bla1 0 Bla1 0 Bla1 1 Bla2 <- w2 1 Bla2 -> insert at pos-1 => 1 Bla3 pos -> 2 Bla3 <- w1 2 Bla4 2 Bla2 3 Bla4 3 Bla4 */ void KraftView::slotMovePositionUp( int pos ) { PositionViewWidget *w1 = nullptr; PositionViewWidget *w2 = nullptr; // qDebug () << "Moving position up: " << pos; if( pos < 1 || pos > mPositionWidgetList.count() ) { // qDebug () << "ERR: position out of range: " << pos; return; } mPositionWidgetList.swap( pos, pos-1 ); w1 = mPositionWidgetList.at( pos-1 ); w2 = mPositionWidgetList.at( pos ); // Porting ATTENTION: check assignment of w1, w1 // qDebug () << "Found at pos " << pos << " the widgets " << w1 << " and " << w2; if( w1 && w2 ) { // qDebug () << "Setting ord number: " << pos; w1->setOrdNumber( pos ); // note: ordnumbers start with 1, thus add one w2->setOrdNumber( pos+1 ); setMappingId( w1, pos-1 ); setMappingId( w2, pos ); m_positionScroll->moveChild( w2, m_positionScroll->indexOf(w1) ); mModified = true; QTimer::singleShot( 0, this, SLOT(refreshPostCard() ) ); } else { // qDebug () << "ERR: Did not find the two corresponding widgets!"; } } /* 0 Bla1 0 Bla1 0 Bla1 pos -> 1 Bla2 <- w1 1 Bla3 1 Bla3 2 Bla3 <- w2 2 Bla4 -> insert at pos+1 => 2 Bla2 3 Bla4 3 Bla4 */ void KraftView::slotMovePositionDown( int pos ) { PositionViewWidget *w1 = nullptr; PositionViewWidget *w2 = nullptr; // qDebug () << "Moving position down: " << pos; if( pos < 0 || pos >= mPositionWidgetList.count() -1 ) { // qDebug () << "ERR: position out of range: " << pos; return; } mPositionWidgetList.swap( pos, pos+1); w1 = mPositionWidgetList.at( pos+1 ); w2 = mPositionWidgetList.at( pos ); // Porting ATTENTION: check assignment of w1, w1 if( w1 && w2 ) { w1->setOrdNumber( pos+2 ); w2->setOrdNumber( pos+1 ); setMappingId( w1, pos+1 ); setMappingId( w2, pos ); m_positionScroll->moveChild( w1, m_positionScroll->indexOf( w2 ) ); mModified = true; QTimer::singleShot( 0, this, SLOT( refreshPostCard() ) ); } else { // qDebug () << "ERR: Did not find the two corresponding widgets!"; } } void KraftView::slotDeletePosition( int pos ) { PositionViewWidget *w1 = mPositionWidgetList.at( pos ); if( w1 ) { w1->slotSetState( PositionViewWidget::Deleted ); w1->slotModified(); } } void KraftView::slotLockPosition( int pos ) { // qDebug () << "Locking Position " << pos; PositionViewWidget *w1 = mPositionWidgetList.at( pos ); if( w1 ) { w1->slotSetState( PositionViewWidget::Locked ); refreshPostCard(); } } void KraftView::slotUnlockPosition( int pos ) { // qDebug () << "Unlocking Position " << pos; PositionViewWidget *w1 = mPositionWidgetList.at( pos ); if( w1 ) { w1->slotSetState( PositionViewWidget::Active ); refreshPostCard(); } } void KraftView::slotPositionModified( int ) { // qDebug () << "Modified Position " << pos; mModified = true; QTimer::singleShot( 0, this, SLOT( refreshPostCard() ) ); } void KraftView::slotAddressFound(const QString& uid, const KContacts::Addressee& contact) { const QString currAddress = m_headerEdit->m_postAddressEdit->toPlainText(); const QString newAddress = mAddressProvider->formattedAddress(contact); bool replace = true; if( currAddress.isEmpty() ) { replace = true; } else if(currAddress != newAddress) { // non empty and current different from new address // need to ask first if we overwrite if( QMessageBox::question( this, i18n("Address Overwrite"), i18n("The address label is not empty and different from the selected one.
            " "Do you really want to replace it with the text shown below?
            %1
            ", newAddress) ) == QMessageBox::No ) { replace = false; } } else if( currAddress == newAddress ) { // both are equal, no action needed return; } if( replace ) { mContactUid = uid; m_headerEdit->m_labName->setText( contact.realName() ); m_headerEdit->m_postAddressEdit->setText( newAddress ); // Generate the welcome m_headerEdit->m_letterHead->clear(); QStringList li = generateLetterHead( contact.familyName(), contact.givenName() ); m_headerEdit->m_letterHead->insertItems(-1, li ); KraftDoc *doc = getDocument(); if( doc->isNew() ) { m_headerEdit->m_letterHead->setCurrentIndex( KraftSettings::self()->salut() ); } else { if(!doc->salut().isEmpty()) { m_headerEdit->m_letterHead->setCurrentText( doc->salut() ); } } } } void KraftView::slotDocTypeChanged( const QString& newType ) { // qDebug () << "Doc Type changed to " << newType; mAssistant->slotSetDocType( newType ); DocType docType( newType ); PositionViewWidgetListIterator it( mPositionWidgetList ); while( it.hasNext() ) { PositionViewWidget *w = it.next(); w->slotEnableKindMenu( docType.allowAlternative() ); w->slotShowPrice(docType.pricesVisible()); } mAssistant->postCard()->slotShowPrices( docType.pricesVisible() ); m_footerEdit->ui()->_taxGroup->setVisible( docType.pricesVisible() ); if( mDocPosEditorIndx > -1 ) { KraftDocPositionsEdit *w = dynamic_cast(mViewStack->widget(mDocPosEditorIndx)); if(w) { w->setDiscountButtonVisible(docType.pricesVisible()); } } } void KraftView::slotLanguageSettings() { // qDebug () << "Language Settings"; // FIXME } void KraftView::slotNewHeaderText( const DocText& dt, bool replace ) { if (replace) { m_headerEdit->m_teEntry->setPlainText( dt.text()); } else { m_headerEdit->m_teEntry->insertPlainText(dt.text()); } slotModifiedHeader(); } void KraftView::slotNewFooterText( const DocText& dt, bool replace ) { if (replace) { m_footerEdit->ui()->m_teSummary->setPlainText(dt.text()); } else { m_footerEdit->ui()->m_teSummary->insertPlainText(dt.text()); } slotModifiedFooter(); } // Add a new item. A katalog is required if user wants to store it in a // catalog immediately. FIXME - now the current active catalog in the // catalog selection is used. void KraftView::slotAddNewItem() { Katalog* kat = mAssistant->catalogSelection()->currentSelectedKat(); slotAddItem( kat, nullptr, QString() ); } void KraftView::slotAddItems( Katalog *kat, CatalogTemplateList templates, const QString& selectedChapter) { if(templates.count() == 0) { slotAddItem(kat, nullptr, selectedChapter); } else { for(CatalogTemplate *templ : templates ) { slotAddItem( kat, templ, selectedChapter ); } } } void KraftView::slotAddItem( Katalog *kat, CatalogTemplate *tmpl, const QString& selectedChapter ) { // newpos is a list position, starts counting at zero! int newpos = mPositionWidgetList.count(); // qDebug () << "Adding Position at list position " << newpos; QScopedPointer dia; DocPosition *dp = new DocPosition(); dp->setPositionNumber( newpos +1 ); bool newTemplate = false; if ( !tmpl ) { newTemplate = true; } dia.reset(new InsertTemplDialog( this )); dia->setCatalogChapters( kat->getKatalogChapters(), selectedChapter); int tmplId = 0; if ( !newTemplate ) { // it's not a new template dp->setText(tmpl->getText()); dp->setUnit(tmpl->unit()); dp->setUnitPrice(tmpl->unitPrice()); } if ( mRememberAmount > 0 ) { dp->setAmount( mRememberAmount ); } KraftDoc *doc = getDocument(); if(doc) { DocType docType = doc->docType(); dia->setDocPosition( dp, newTemplate, docType.pricesVisible() ); } DocPositionList list = currentPositionList(); dia->setPositionList( list, newpos ); QSize s = KraftSettings::self()->templateToPosDialogSize(); dia->resize( s ); int execResult = dia->exec(); if ( execResult == QDialog::Accepted ) { DocPosition diaPos = dia->docPosition(); *dp = diaPos; // set the tax settings if( currentTaxSetting() == DocPositionBase::TaxIndividual ) { // FIXME: In case a new item is added, add the default tax type. // otherwise add the tax of the template dp->setTaxType( DocPositionBase::TaxFull ); } else { dp->setTaxType( currentTaxSetting() ); } // store the initial size of the template-to-doc-pos dialogs s = dia->size(); KraftSettings::self()->setTemplateToPosDialogSize( s ); if ( kat->type() == TemplateCatalog ) { // save the template if it is has a valid chapter. // the method chapter() considers the checkbox. If it is not checked to keep the template, // an empty chapter is returned. const QString chapter = dia->chapter(); if (!chapter.isEmpty()) { int chapterId = KatalogMan::self()->defaultTemplateCatalog()->chapterID(chapter).toInt(); FloskelTemplate *flos = new FloskelTemplate( -1, dp->text(), dp->unit().id(), chapterId, 1 /* CalcKind = Manual */ ); flos->setManualPrice( dp->unitPrice() ); flos->save(); tmplId = flos->getTemplID(); // reload the entire katalog Katalog *defaultKat = KatalogMan::self()->defaultTemplateCatalog(); if( defaultKat ) { defaultKat->load(); KatalogMan::self()->notifyKatalogChange( defaultKat , dbID() ); } } else if (!newTemplate && tmpl){ tmplId = static_cast(tmpl)->getTemplID(); } } else if ( kat->type() == MaterialCatalog ) { if ( !newTemplate ) { tmplId = static_cast(tmpl)->getID(); } } } if (execResult == QDialog::Accepted) { newpos = dia->insertAfterPosition(); mRememberAmount = dp->amount(); if (tmplId > 0 && tmpl) { QPair newUsage = kat->recordUsage(tmplId); tmpl->setUseCounter(newUsage.first); tmpl->setLastUsedDate(newUsage.second); } PositionViewWidget *widget = createPositionViewWidget( dp, newpos ); widget->slotModified(); widget->slotAllowIndividualTax( currentTaxSetting() == DocPositionBase::TaxIndividual ); // Check if the new widget is supposed to display prices, based on the doc type // FIXME: Shouldn't this be done by the positionViewWidget rather than here? const QString dt = getDocument()->docType(); if( !dt.isEmpty() ) { DocType docType(dt); widget->slotShowPrice(docType.pricesVisible()); } slotFocusItem( widget, newpos ); refreshPostCard(); } } void KraftView::slotImportItems() { ImportItemDialog dia( this ); DocPositionList list = currentPositionList(); int newpos = list.count(); dia.setPositionList( list, newpos ); if ( dia.exec() ) { DocPositionList list = dia.positionList(); if ( list.count() > 0 ) { // qDebug () << "Importlist amount of entries: " << list.count(); int cnt = 0; int newpos = dia.getPositionCombo()->currentIndex(); // qDebug () << "Newpos is " << newpos; DocPositionListIterator posIt( list ); while( posIt.hasNext() ) { DocPosition *dp_old = static_cast(posIt.next()); DocPosition *dp = new DocPosition( *(dp_old) ); dp->setTaxType( currentTaxSetting() ); PositionViewWidget *widget = createPositionViewWidget( dp, newpos + cnt++ ); widget->slotSetTax( DocPositionBase::TaxFull ); // FIXME: Value from Import? widget->slotModified(); } refreshPostCard(); } } } void KraftView::slotAddExtraPosition() { // newpos is a list position, starts counting at 0 int newpos = mPositionWidgetList.count(); // qDebug () << "Adding EXTRA Position at position " << newpos; DocPosition *dp = new DocPosition( DocPosition::ExtraDiscount ); dp->setPositionNumber( newpos+1 ); dp->setText( i18n( "Discount" ) ); Einheit e = UnitManager::self()->getPauschUnit(); dp->setUnit(e); if( currentTaxSetting() == DocPositionBase::TaxIndividual ) { dp->setTaxType( DocPositionBase::TaxFull ); } else { dp->setTaxType( currentTaxSetting() ); } // qDebug () << "New Extra position is " << dp; PositionViewWidget *widget = createPositionViewWidget( dp, newpos ); // qDebug () << "PositionViewWiget doc position is: " << widget->position(); widget->slotModified(); slotFocusItem( widget, newpos ); refreshPostCard(); } DocPositionList KraftView::currentPositionList() { DocPositionList list; PositionViewWidget *widget = nullptr; int cnt = 1; PositionViewWidgetListIterator outerIt( mPositionWidgetList ); bool progress = true; while ( progress && ( list.count() != mPositionWidgetList.count() ) ) { // the loop runs until all positions have a valid price. int preListCnt = list.count(); // qDebug() << "# Pre List Count: " << preListCnt; while ( outerIt.hasNext() ) { widget = outerIt.next(); DocPositionBase *dpb = widget->position(); QMap replaceMap; if ( dpb ) { DocPosition *newDp = new DocPosition( dpb->type() ); newDp->setPositionNumber( cnt++ ); newDp->setAttributeMap( dpb->attributes() ); newDp->setDbId( dpb->dbId().toInt() ); newDp->setAssociatedWidget( widget ); bool calculatable = true; if ( dpb->type() == DocPosition::ExtraDiscount ) { double discount = widget->mDiscountPercent->value(); /* set Attributes with the discount percentage */ Attribute a( DocPosition::Discount ); a.setPersistant( true ); a.setValue( discount ); newDp->setAttribute(a); // get the required tag as String. const QString tagRequiredStr = widget->extraDiscountTagRestriction(); if ( !tagRequiredStr.isEmpty() ) { Attribute tr(DocPosition::ExtraDiscountTagRequired); tr.setPersistant( true ); // Convert the string to int and save to database const TagTemplate ttRequired = TagTemplateMan::self()->getTagTemplate(tagRequiredStr); int trId = TagTemplateMan::self()->getTagTemplate(tagRequiredStr).dbId().toInt(); tr.setValue( QVariant( trId ) ); newDp->setAttribute( tr ); } /* Calculate the current sum over all widgets */ PositionViewWidgetListIterator it( mPositionWidgetList ); PositionViewWidget *w1; Geld sum; // qDebug () << "Starting to loop over the items "; while ( calculatable && it.hasNext() ) { w1 = it.next(); if ( widget != w1 ) { // ATTENTION Porting: do not take the own value into account if ( tagRequiredStr.isEmpty() // means that all positions are to calculate || w1->tagList().contains( tagRequiredStr ) ) { // tagList() returns strings, not Ids. if ( w1->priceValid() ) { sum += w1->currentPrice(); // qDebug () << "Summing up pos with text " << w1->ordNumber() << " and price " // << w1->currentPrice().toLong(); } else { calculatable = false; // give up, we continue in outerIt // qDebug () << "We skip pos " << w1->ordNumber(); } } } else { // we can not calculate ourselves. // qDebug () << "Skipping pos " << w1->ordNumber() << " in summing up, thats me!"; } } // qDebug () << "Finished loop over items with calculatable=" << calculatable; if ( calculatable ) { sum = sum.percent( discount ); newDp->setUnitPrice( sum ); newDp->setAmount( 1.0 ); widget->setCurrentPrice( sum ); } // replace some tags in the text replaceMap["%DISCOUNT"] = DefaultProvider().self()->locale()->toString( discount ); replaceMap["%ABS_DISCOUNT"] = DefaultProvider().self()->locale()->toString( qAbs( discount ) ); } else { /* Type is ordinary position */ newDp->setUnitPrice( widget->unitPrice() ); double v = widget->m_sbAmount->value(); newDp->setAmount( v ); widget->setCurrentPrice( newDp->overallPrice() ); } if ( calculatable ) { // copy information from the widget bool deleted = widget->deleted(); newDp->setToDelete(deleted); QString t = widget->m_teFloskel->toPlainText(); if ( !replaceMap.empty() ) { t = StringUtil::replaceTagsInString(t, replaceMap); } newDp->setText( t ); QString h = widget->m_cbUnit->currentText(); int eId = UnitManager::self()->getUnitIDSingular( h ); Einheit e = UnitManager::self()->getUnit( eId ); newDp->setUnit( e ); PositionViewWidget::Kind k = widget->kind(); if ( k != PositionViewWidget::Normal ) { Attribute a( DocPosition::Kind ); a.setPersistant( true ); a.setValue( PositionViewWidget::techKindString(k) ); newDp->setAttribute( a ); } else { newDp->removeAttribute( DocPosition::Kind ); } /* set Attribute with the tags */ const QStringList tagStrings = widget->tagList(); newDp->replaceTags(tagStrings); // qDebug() << "============ " << tags.toString(); // tax settings if( currentTaxSetting() == DocPositionBase::TaxIndividual ) { newDp->setTaxType( widget->taxType() ); } else { newDp->setTaxType( currentTaxSetting() ); } list.append( newDp ); } } else { qCritical() << "Fatal: Widget without position found!"; } } // qDebug() << " Post List Count: " << list.count(); if ( preListCnt == list.count() ) { qCritical() << "No progress in widget list processing - abort!"; progress = false; } } return list; } void KraftView::slotShowCatalog( bool on ) { if ( on ) { mAssistant->slotShowCatalog(); } else { mAssistant->setFullPreview( true, KraftDoc::Positions ); } } void KraftView::slotModifiedPositions() { // As long as the modified mapper is blocked, ignore this. if( mModifiedMapper->signalsBlocked() ) { return; } qDebug () << "Position Modified"; mModified = true; } void KraftView::slotModifiedHeader() { // qDebug () << "Modified the header!"; // As long as the modified mapper is blocked, ignore this. if( mModifiedMapper->signalsBlocked() ) { return; } mModified = true; QTimer::singleShot( 0, this, SLOT( refreshPostCard() ) ); } void KraftView::slotModifiedFooter() { // qDebug () << "Modified the footer!"; // As long as the modified mapper is blocked, ignore this. if( mModifiedMapper->signalsBlocked() ) { return; } mModified = true; QTimer::singleShot( 0, this, SLOT( refreshPostCard() ) ); } QStringList KraftView::generateLetterHead( const QString& familyName, const QString& givenName ) { QStringList s; QMap m; m[ "%NAME"] = familyName; m[ "%GIVEN_NAME"] = givenName; return KraftDB::self()->wordList( "salut", m ); } void KraftView::done( int r ) { //Closed using the cancel button .. Check if we can close bool doSave = false; if (mModified) { doSave = true; if(r == 0) { QMessageBox msgBox; msgBox.setText(i18n("The document has been modified.")); msgBox.setInformativeText(i18n("Do you want to save your changes?")); msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Save); msgBox.exec(); auto res = msgBox.result(); if (res == QMessageBox::Cancel) return; if (res == QMessageBox::Discard) doSave = false; } //Closed using the OK button .. it can be closed, but data needs saved if( doSave) saveChanges(); emit viewClosed( r == 1, m_doc ); } // remember the sizes of the docassistant splitter if visible. mAssistant->saveSplitterSizes(); KraftSettings::self()->setDocViewSplitter(mCSplit->sizes()); const QByteArray geo = saveGeometry().toBase64(); KraftSettings::self()->setDocEditGeometry(geo); QDialog::done( r ); } void KraftView::saveChanges() { // qDebug () << "Saving changes!"; KraftDoc *doc = getDocument(); if( !doc ) { // qDebug () << "ERR: No document available in view, return!"; return; } // transfer all values to the document doc->setDate( m_headerEdit->m_dateEdit->date() ); doc->setAddressUid( mContactUid ); doc->setAddress( m_headerEdit->m_postAddressEdit->toPlainText() ); doc->setDocType( m_headerEdit->m_cbType->currentText() ); doc->setPreTextRaw( m_headerEdit->m_teEntry->toPlainText() ); doc->setWhiteboard( m_headerEdit->m_whiteboardEdit->toPlainText() ); doc->setProjectLabel( m_headerEdit->mProjectLabelEdit->text() ); doc->setSalut( m_headerEdit->m_letterHead->currentText() ); doc->setPostTextRaw( m_footerEdit->ui()->m_teSummary->toPlainText() ); doc->setGoodbye( m_footerEdit->greeting() ); DocPositionList list = currentPositionList(); doc->setPositionList( list ); doc->saveDocument( ); if ( doc->isNew() ) { // For new documents the user had to select a greeting and we make this // default for the future KraftSettings::self()->setGreeting( m_footerEdit->greeting() ); KraftSettings::self()->setSalut( m_headerEdit->m_letterHead->currentIndex() ); } } void KraftView::slotFocusItem( PositionViewWidget *posWidget, int pos ) { if( posWidget && pos > 0) { int y = (1+pos)*posWidget->height(); m_positionScroll->ensureVisible(0, y); } else { m_positionScroll->ensureVisible( 0, 0 ); } // setting Focus within the item. if( posWidget ) { if( posWidget->m_teFloskel->toPlainText().isEmpty() ) { posWidget->m_teFloskel->setFocus(); } else { posWidget->m_sbAmount->setFocus(); } } } void KraftView::discardChanges() { // We need to reread the document KraftDoc *doc = getDocument(); if( doc && doc->isModified() ) { // qDebug () << "Document refetch from database"; doc->reloadDocument(); } } kraft-1.1/src/kraftview.h000066400000000000000000000143371450127457600154470ustar00rootroot00000000000000/*************************************************************************** kraftview.h - view of kraft documents ------------------- begin : Mit Dez 31 19:24:05 CET 2003 copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRAFTVIEW_H #define KRAFTVIEW_H /** The KraftView class provides the view widget for the KraftApp instance. * The View instance inherits QWidget as a base class and represents * the view object of a KTMainWindow. As KraftView is part of the * docuement-view model, it needs a reference to the document object * connected with it by the KraftApp class to manipulate and display * the document structure provided by the KraftDoc class. * * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team. * @version KDevelop version 0.4 code generation */ // include files for Qt #include #include #include #include #include #include "kraftdoc.h" #include "positionviewwidget.h" #include "catalogtemplate.h" #include "ui_docheader.h" #include "ui_docfooter.h" class PositionViewWidget; class DocPosition; class DocText; class QLabel; class QWidget; class QResizeEvent; class QSignalMapper; class QStackedWidget; class QSplitter; class DocPostCard; class QTimer; class DocAssistant; class CalcPartList; class AddressProvider; class KraftDocFooterEdit; class Katalog; class KraftViewScroll; class KraftViewBase: public QDialog { Q_OBJECT public: enum Type { ReadWrite, ReadOnly }; KraftViewBase(QWidget *parent) : QDialog(parent), m_type(ReadWrite) { } virtual ~KraftViewBase() { } Type type() { return m_type; } protected: KraftDoc *getDocument() const { return m_doc; } virtual void setup( DocGuardedPtr doc ) { m_doc = doc; } DocGuardedPtr m_doc; Type m_type; protected slots: virtual void slotLinkClicked(const QString& link) = 0; signals: void viewClosed( bool, DocGuardedPtr ); void openROView( QString docId ); private: }; class KraftView : public KraftViewBase { Q_OBJECT public: /** Constructor for the main view */ KraftView(QWidget *parent); /** Destructor for the main view */ virtual ~KraftView(); /** returns a pointer to the document connected to the view instance. Mind that this method requires a KraftApp instance as a parent * widget to get to the window document pointer by calling the KraftApp::getDocument() method. * * @see KraftApp#getDocument */ typedef QMap PositionMap; DocPositionList currentPositionList(); DocPositionBase::TaxType currentTaxSetting(); void setup( DocGuardedPtr doc ); public slots: void slotAddressFound(const QString& uid, const KContacts::Addressee &contact); void slotAddresseeFound( const QString& uid, const KContacts::Addressee& contact); void redrawDocument( ); void slotModifiedPositions(); void slotModifiedHeader(); void slotModifiedFooter(); void slotAddItem( Katalog*, CatalogTemplate*, const QString& selectedChapter); void slotAddNewItem(); void slotAddItems(Katalog*, CatalogTemplateList , const QString &selectedChapter); void slotAddExtraPosition(); void slotImportItems(); void slotFocusItem( PositionViewWidget*, int ); void slotNewHeaderText(const DocText& dt , bool replace); void slotNewFooterText(const DocText& dt , bool replace); void slotSwitchToPage( int ); protected slots: // void closeEvent(QCloseEvent *event); void redrawDocPositions( ); void done( int ); void slotMovePositionUp( int ); void slotMovePositionDown( int ); void slotDeletePosition( int ); void slotUnlockPosition( int ); void slotLockPosition( int ); void slotPositionModified( int ); void refreshPostCard( ); void slotShowCatalog( bool ); void slotShowTemplates( bool ); void slotDocTypeChanged( const QString& ); void slotLanguageSettings(); void slotPickAddressee(); void slotTaxComboChanged( int ); void slotNewAddress( const KContacts::Addressee& contact, bool interactive = true ); void slotLinkClicked(const QString& link); signals: void selectPage( int ); void positionSelected( Katalog*, void* ); private: void setupDocHeaderView(); void setupItems(); void setupFooter(); void setupTextsView(); void setMappingId( QWidget *, int ); void setupMappers(); void saveChanges(); void discardChanges(); PositionViewWidget *createPositionViewWidget( DocPositionBase*, int ); QStringList generateLetterHead(const QString &familyName , const QString &givenName); KraftViewScroll *m_positionScroll; Ui::DocHeaderEdit *m_headerEdit; // Ui::DocFooterEdit *m_footerEdit; KraftDocFooterEdit *m_footerEdit; PositionViewWidgetList mPositionWidgetList; QString mContactUid; QSignalMapper *mDeleteMapper; QSignalMapper *mMoveUpMapper; QSignalMapper *mMoveDownMapper; QSignalMapper *mUnlockPositionMapper; QSignalMapper *mLockPositionMapper; QSignalMapper *mModifiedMapper; AddressProvider *mAddressProvider; QLabel *mDetailHeader; QSplitter *mCSplit; QPushButton *mCatalogToggle; QLabel *mHelpLabel; QWidget *mSumSpacer; QStackedWidget *mViewStack; int mHeaderId; DocAssistant *mAssistant; double mRememberAmount; QMap mCalculationsMap; bool mModified; int mTaxBefore; int mDocPosEditorIndx; }; #endif // KRAFTVIEW_H kraft-1.1/src/kraftview_ro.cpp000066400000000000000000000230401450127457600164710ustar00rootroot00000000000000/*************************************************************************** kraftview.cpp - ------------------- begin : Mit Dez 31 19:24:05 CET 2003 copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include #include #include #include #include #include #include #include #include #include // application specific includes #include "kraftsettings.h" #include "kraftview_ro.h" #include "kraftdoc.h" #include "ui_docheader.h" #include "positionviewwidget.h" #include "ui_docfooter.h" #include "docposition.h" #include "defaultprovider.h" #include "doctype.h" #include "format.h" #include "htmlview.h" #include "texttemplate.h" #include "documentman.h" #include #include #include // ######################################################### KraftViewRO::KraftViewRO(QWidget *parent, const char *name) : KraftViewBase( parent ) { setObjectName( name ); setModal( false ); setWindowTitle( i18n("Document" ) ); QWidget *mainWidget = new QWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(mainWidget); m_type = ReadOnly; mHtmlView = new HtmlView( this ); mainLayout->addWidget(mHtmlView); mHtmlView->setStylesheetFile( "docoverview_ro.css" ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(buttonBox); } KraftViewRO::~KraftViewRO() { } #define QL1(X) QStringLiteral(X) QString KraftViewRO::htmlify( const QString& str ) const { const QStringList li = str.toHtmlEscaped().split( "\n" ); return QL1("

            ") + li.join( "

            " ) + QL1("

            "); } #define DOC_RO_TAG(X) QLatin1String(X) void KraftViewRO::setup( DocGuardedPtr doc ) { KraftViewBase::setup( doc ); if ( !doc ) return; QLocale *locale = DefaultProvider::self()->locale(); // do stuff like open a template and render values into it. QString tmplFile = DefaultProvider::self()->locateFile( "views/kraftdoc_ro.thtml" ); if( tmplFile.isEmpty() ) { // qDebug () << "Could not find template to render ro view of document."; return; } else { qDebug() << "Template file: " << tmplFile; } TextTemplate tmpl; tmpl.setTemplateFileName(tmplFile); if( !tmpl.isOk() ) { return; } tmpl.setValue( DOC_RO_TAG( "HEADLINE" ), doc->docType() + " " + doc->ident() ); tmpl.setValue( DOC_RO_TAG( "DATE" ), Format::toDateString(doc->date(), KraftSettings::self()->dateFormat())); tmpl.setValue( DOC_RO_TAG( "DOC_TYPE" ), doc->docType() ); QString address = doc->address(); address.replace( '\n', "
            " ); tmpl.setValue( DOC_RO_TAG( "ADDRESS" ), address ); tmpl.setValue( DOC_RO_TAG( "DOCNO" ), doc->ident() ); tmpl.setValue( DOC_RO_TAG( "PRETEXT" ), htmlify(doc->preText()) ); tmpl.setValue( DOC_RO_TAG( "POSTTEXT" ), htmlify(doc->postText()) ); tmpl.setValue( DOC_RO_TAG( "SALUT" ), doc->salut() ); tmpl.setValue( DOC_RO_TAG( "GOODBYE" ), doc->goodbye() ); DocPositionList positions = doc->positions(); // check the tax settings: If all items have the same settings, its not individual. bool individualTax = false; int ttype = -1; foreach( DocPositionBase *dp, positions ) { if( ttype == -1 ) { ttype = dp->taxType(); } else { if( ttype != dp->taxType() ) { // different from previous one? individualTax = true; break; } } } int pos = 1; int taxFreeCnt = 0; int reducedTaxCnt = 0; int fullTaxCnt = 0; QString docType = doc->docType(); DocType dt(docType); foreach( DocPositionBase *dpb, positions ) { DocPosition *dp = static_cast(dpb); tmpl.createDictionary( "ITEMS" ); tmpl.setValue( "ITEMS", "NUMBER", QString::number( pos++ ) ); tmpl.setValue( "ITEMS", "TEXT", htmlify(dp->text() )); tmpl.setValue( "ITEMS", "AMOUNT", locale->toString( dp->amount() ) ); tmpl.setValue( "ITEMS", "UNIT", dp->unit().einheit( dp->amount() ) ); double singlePrice = dp->unitPrice().toDouble(); if( dt.pricesVisible() ) { tmpl.createSubDictionary("ITEMS", "PRICE_DISPLAY"); tmpl.setValue( "PRICE_DISPLAY", "SINGLE_PRICE", locale->toCurrencyString( singlePrice ) ); QString style( "positive" ); if ( singlePrice < 0 ) { style = "negative"; } tmpl.setValue( "PRICE_DISPLAY", "PRICE_STYLE", style ); tmpl.setValue( "PRICE_DISPLAY", "PRICE", locale->toCurrencyString( dp->overallPrice().toDouble() ) ); QString taxType; if( individualTax ) { if( dp->taxType() == 1 ) { taxFreeCnt++; taxType = "TAX_FREE"; } else if( dp->taxType() == 2 ) { taxType = "REDUCED_TAX"; reducedTaxCnt++; } else { // ATTENTION: Default for all non known tax types is full tax. fullTaxCnt++; taxType = "FULL_TAX"; } } tmpl.createSubDictionary("PRICE_DISPLAY", taxType); } } if( dt.pricesVisible()) { tmpl.createDictionary("DISPLAY_SUM_BLOCK"); tmpl.setValue( "DISPLAY_SUM_BLOCK", DOC_RO_TAG( "TAXLABEL" ), i18n( "VAT" ) ); tmpl.setValue( "DISPLAY_SUM_BLOCK", DOC_RO_TAG( "REDUCED_TAXLABEL" ), i18n( "Reduced TAX" ) ); tmpl.setValue( "DISPLAY_SUM_BLOCK", DOC_RO_TAG( "NETTOSUM" ), locale->toCurrencyString( doc->nettoSum().toDouble() ) ); tmpl.setValue( "DISPLAY_SUM_BLOCK", DOC_RO_TAG( "BRUTTOSUM" ), locale->toCurrencyString( doc->bruttoSum().toDouble() ) ); if( individualTax ) { tmpl.createSubDictionary( "DISPLAY_SUM_BLOCK", "TAX_FREE_ITEMS" ); tmpl.setValue( "TAX_FREE_ITEMS", "COUNT", QString::number( taxFreeCnt )); tmpl.createSubDictionary( "DISPLAY_SUM_BLOCK", "REDUCED_TAX_ITEMS" ); tmpl.setValue( "REDUCED_TAX_ITEMS", "COUNT", QString::number( reducedTaxCnt )); tmpl.setValue( "REDUCED_TAX_ITEMS", "TAX", locale->toString( DocumentMan::self()->reducedTax( doc->date() ))); tmpl.createSubDictionary( "DISPLAY_SUM_BLOCK", "FULL_TAX_ITEMS" ); tmpl.setValue( "FULL_TAX_ITEMS", "COUNT", QString::number( fullTaxCnt )); tmpl.setValue( "FULL_TAX_ITEMS", "TAX", locale->toString( DocumentMan::self()->tax( doc->date() )) ); } double redTax = DocumentMan::self()->reducedTax( doc->date() ); double fullTax = DocumentMan::self()->tax( doc->date() ); QString h; if ( positions.reducedTaxSum( redTax ).toLong() > 0 ) { tmpl.createSubDictionary( "DISPLAY_SUM_BLOCK", "SECTION_REDUCED_TAX" ); tmpl.setValue( "SECTION_REDUCED_TAX", DOC_RO_TAG( "REDUCED_TAX_SUM" ), positions.reducedTaxSum( redTax ).toLocaleString() ); h.setNum( redTax, 'f', 1 ); tmpl.setValue( "SECTION_REDUCED_TAX", DOC_RO_TAG( "REDUCED_TAX" ), h ); tmpl.setValue( "SECTION_REDUCED_TAX", DOC_RO_TAG( "REDUCED_TAX_LABEL" ), i18n( "reduced VAT" ) ); } if ( positions.fullTaxSum( fullTax ).toLong() > 0 ) { tmpl.createSubDictionary( "DISPLAY_SUM_BLOCK", "SECTION_FULL_TAX" ); tmpl.setValue( "SECTION_FULL_TAX", DOC_RO_TAG( "FULL_TAX_SUM" ), positions.fullTaxSum( fullTax ).toLocaleString() ); h.setNum( fullTax, 'f', 1 ); tmpl.setValue( "SECTION_FULL_TAX", DOC_RO_TAG( "FULL_TAX" ), h ); tmpl.setValue( "SECTION_FULL_TAX", DOC_RO_TAG( "FULL_TAX_LABEL" ), i18n( "VAT" ) ); } tmpl.setValue( "DISPLAY_SUM_BLOCK", DOC_RO_TAG( "TAXSUM" ), locale->toCurrencyString( doc->vatSum().toDouble() ) ); } // Visible sum block setWindowTitle( m_doc->docIdentifier() ); mHtmlView->setTitle( doc->docIdentifier() ); const QString html = tmpl.expand(); mHtmlView->displayContent(html); } void KraftViewRO::slotLinkClicked(const QString& link) { Q_UNUSED(link) // nothing we do here yet } void KraftViewRO::done( int r ) { // qDebug () << "View closed with ret value " << r; KraftDoc *doc = getDocument(); if( !doc ) { // qDebug () << "ERR: No document available in view, return!"; return; } emit viewClosed( true, m_doc ); KraftViewBase::done(r); } kraft-1.1/src/kraftview_ro.h000066400000000000000000000046211450127457600161420ustar00rootroot00000000000000/*************************************************************************** kraftview.h - view of kraft documents ------------------- begin : Mit Dez 31 19:24:05 CET 2003 copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRAFTVIEW_RO_H #define KRAFTVIEW_RO_H // include files for Qt #include #include #include #include #include #include #include "kraftdoc.h" /** The KraftViewRO class provides the read only view widget for Kraft documents. * The View instance inherits QWidget as a base class and represents * the view object of a KTMainWindow. As KraftView is part of the * docuement-view model, it needs a reference to the document object * connected with it by the KraftApp class to manipulate and display * the document structure provided by the KraftDoc class. * * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team. * @version KDevelop version 0.4 code generation */ #include "positionviewwidget.h" #include "catalogtemplate.h" #include "kraftview.h" class Katalog; class HtmlView; class KraftViewRO : public KraftViewBase { public: /** Constructor for the main view */ KraftViewRO(QWidget *parent, const char *name=0); /** Destructor for the main view */ virtual ~KraftViewRO(); void setup( DocGuardedPtr doc ); QString htmlify( const QString& str ) const; protected slots: void done( int ); void slotLinkClicked(const QString& link); signals: void positionSelected( Katalog*, void* ); private: HtmlView *mHtmlView; }; #endif // KRAFTVIEW_RO_H kraft-1.1/src/main.cpp000066400000000000000000000053141450127457600147170ustar00rootroot00000000000000/*************************************************************************** main.cpp - ------------------- begin : Mit Dez 31 19:24:05 CET 2003 copyright : (C) 2003 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "version.h" #include "portal.h" #include "defaultprovider.h" #include "archdocposition.h" int main(int argc, char *argv[]) { Q_INIT_RESOURCE(kraft); const QByteArray domain {"kraft"}; qRegisterMetaType("ArchDocPositionList"); QApplication app(argc, argv); app.setWindowIcon(QIcon(":/kraft/custom-icons/kraft-simple.svg")); app.setApplicationName("kraft"); app.setApplicationDisplayName("Kraft"); app.setApplicationVersion(QString("version %1").arg(Kraft::Version::number())); const QString path = QCoreApplication::applicationDirPath()+ QStringLiteral("/../share/locale"); qDebug() << "Setting additional Locale path:" << path; KLocalizedString::setApplicationDomain(domain.data()); KLocalizedString::addDomainLocaleDir(domain, path); QCommandLineParser parser; parser.addVersionOption(); parser.addHelpOption(); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("d"), i18n("Open document with arch doc number "), QLatin1String("number"))); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("r"), i18n("Open Kraft in read only mode - document changes prohibited") )); parser.process(app); // Register the supported options QScopedPointer kraftPortal; kraftPortal.reset( new Portal( nullptr, &parser, "kraft main window" )); kraftPortal->show(); return app.exec(); } kraft-1.1/src/matcalcdialog.cpp000066400000000000000000000035601450127457600165600ustar00rootroot00000000000000/*************************************************************************** matcalcdialog - ------------------- begin : 2005-03-00 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include #include "matcalcdialog.h" #include "materialcalcpart.h" #include "stockmaterial.h" MatCalcDialog::MatCalcDialog( MaterialCalcPart *mc, QWidget *parent ) : CalcDialogBase( parent ), _matWidget(new Ui::calcdetailMat), m_mc(mc) { _matWidget->setupUi(_centralWidget); _matWidget->m_inpMenge->setValue(mc->getCalcAmount()); init(mc->getCalcAmount()); } void MatCalcDialog::init(double amount) { Einheit e = m_mc->getMaterial()->unit(); _matWidget->matLabel->setText( m_mc->getMaterial()->getText()); _matWidget->einheitLabel->setText( e.einheit(amount) ); } void MatCalcDialog::accept() { double val = _matWidget->m_inpMenge->value(); m_mc->setCalcAmount(val); emit( matCalcPartChanged(m_mc)); CalcDialogBase::accept(); } MatCalcDialog::~MatCalcDialog( ) { } /* END */ kraft-1.1/src/matcalcdialog.h000066400000000000000000000030401450127457600162160ustar00rootroot00000000000000/*************************************************************************** matcalcdialog - ------------------- begin : 2005-03-00 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _MATCALCDIALOG_H #define _MATCALCDIALOG_H // include files #include #include "ui_matpartui.h" #include "calcdialogbase.h" class StockMaterial; class MaterialCalcPart; /** * */ class MatCalcDialog : public CalcDialogBase { Q_OBJECT public: MatCalcDialog(MaterialCalcPart *mc, QWidget *parent=0); virtual ~MatCalcDialog(); protected slots: void accept(); signals: void matCalcPartChanged(MaterialCalcPart *mc); private: void init(double); Ui::calcdetailMat *_matWidget; MaterialCalcPart *m_mc; }; #endif /* END */ kraft-1.1/src/materialcalcpart.cpp000066400000000000000000000055171450127457600173100ustar00rootroot00000000000000/*************************************************************************** materialcalcpart - ------------------- begin : 2004-09-05 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include // include files for KDE #include #include "materialcalcpart.h" #include "materialkatalogview.h" #include "katalogman.h" #include "stockmaterial.h" #include "unitmanager.h" #include "matkatalog.h" MaterialCalcPart::MaterialCalcPart() : CalcPart(), m_calcID( 0 ) { } MaterialCalcPart::MaterialCalcPart( long mCalcID, long matID, int percent, double amount ) : CalcPart( percent), m_calcID( mCalcID ), m_calcAmount(amount), m_mat(nullptr) { getMatFromID(matID); // overwrites m_mat if( m_mat ) { setName(m_mat->getText()); } } MaterialCalcPart::MaterialCalcPart(long matID, int percent, double amount) : CalcPart( percent), m_calcID(0), m_calcAmount(amount) { getMatFromID(matID); if( m_mat ) { setName(m_mat->getText()); } } MaterialCalcPart::~MaterialCalcPart( ) { // do not delete m_mat because it comes straight from stockmaterialman } void MaterialCalcPart::getMatFromID(long matID) { MatKatalog *k = static_cast(KatalogMan::self()->getKatalog( MaterialKatalogView::MaterialCatalogName )); if( !k ) { k = new MatKatalog( MaterialKatalogView::MaterialCatalogName ); if( k ) { KatalogMan::self()->registerKatalog(k); } } if( k ) { m_mat = k->materialFromId(matID); } } QString MaterialCalcPart::getType() const { return KALKPART_MATERIAL; } Geld MaterialCalcPart::basisKosten() { Geld g; if( m_mat ) { g = m_mat->unitPrice() * m_calcAmount; } return g; } StockMaterial * MaterialCalcPart::getMaterial() { return m_mat; } bool MaterialCalcPart::setCalcAmount( double newAmount ) { // Check for a change first if( qAbs(newAmount - m_calcAmount) > 0.00001 ) { m_calcAmount = newAmount; setDirty(true); } return isDirty(); } /* END */ kraft-1.1/src/materialcalcpart.h000066400000000000000000000033621450127457600167510ustar00rootroot00000000000000/*************************************************************************** materialcalcpart - ------------------- begin : 2004-09-05 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _MATERIALCALCPART_H #define _MATERIALCALCPART_H // include files #include #include "calcpart.h" /** * */ class StockMaterial; class StockMaterialList; class QString; class QVariant; class MaterialCalcPart : public CalcPart { public: MaterialCalcPart(); MaterialCalcPart( long mCalcID, long matID, int procent, double amount ); MaterialCalcPart( long matID, int procent, double amount ); ~MaterialCalcPart(); virtual Geld basisKosten(); QString getType() const; StockMaterial* getMaterial(); bool setCalcAmount( double newAmount ); double getCalcAmount(){return m_calcAmount;}; protected: void getMatFromID(long matID); private: long m_calcID; double m_calcAmount; StockMaterial *m_mat; }; #endif /* END */ kraft-1.1/src/materialdialog.ui000066400000000000000000000173201450127457600166040ustar00rootroot00000000000000 MaterialDialogBase 0 0 562 313 Edit Material true Qt::Horizontal QSizePolicy::Expanding 65 16 0 0 Store in C&hapter Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false mCbChapter Material Qt::Horizontal QSizePolicy::Expanding 50 16 Pac&kaged: false mDiPerPack 99999.000000000000000 1.000000000000000 1.000000000000000 3 per P&ackage false mCbUnit Prices Qt::Horizontal QSizePolicy::Expanding 240 11 = Price of &Sale: false mInSalePrice 999999.000000000000000 1.000000000000000 0 999999.000000000000000 1.000000000000000 0 pl&us false mInSaleAdd % 999.000000000000000 1 &Purchase Price: false mInPurchasePrice mEditMaterial mDiPerPack mCbUnit mInPurchasePrice mInSaleAdd mInSalePrice mCbChapter kraft-1.1/src/materialkataloglistview.cpp000066400000000000000000000123211450127457600207170ustar00rootroot00000000000000/*************************************************************************** materialkataloglistview - template katalog listview. ------------------- begin : 2005-07-26 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include "matkatalog.h" #include "stockmaterial.h" #include "materialkataloglistview.h" #include "katalogman.h" #include "docposition.h" #include "kataloglistview.h" #include "kraftsettings.h" #include "format.h" MaterialKatalogListView::MaterialKatalogListView(QWidget *parent ) : KatalogListView( parent ) { setColumnCount( 6 ); QStringList headers; headers << i18n("Material"); headers << i18n("Pack"); headers << i18n("Unit"); headers << i18n("Purchase"); headers << i18n("Sale"); headers << i18n("Last Modified"); setHeaderLabels( headers ); QByteArray headerState = QByteArray::fromBase64( KraftSettings::self()->materialCatViewHeader().toLatin1() ); header()->restoreState(headerState); contextMenu()->setTitle(i18n("Material Catalog")); } MaterialKatalogListView::~MaterialKatalogListView() { } void MaterialKatalogListView::addCatalogDisplay( const QString& katName ) { KatalogListView::addCatalogDisplay(katName); Katalog *k = KatalogMan::self()->getKatalog( katName ); MatKatalog *catalog = static_cast( k ); if( ! catalog ) { // qDebug () << "No catalog in listview available!"; return; } // qDebug () << "setting up meterial chapters --------*********************************+++!"; setupChapters(); // lambda expression to be DRY auto insertRecords = [&]( int chapterId) { StockMaterialList records = catalog->getRecordList(chapterId); QTreeWidgetItem *chapterItem = m_root; if (mChapterDict.contains(chapterId)) chapterItem = mChapterDict[chapterId]; for( StockMaterial *mat: records) { addMaterialToView( chapterItem, mat ); } }; for( int chapterId : mChapterDict.keys()) { insertRecords(chapterId); } // append the stray cats insertRecords(0); } QTreeWidgetItem* MaterialKatalogListView::addMaterialToView( QTreeWidgetItem *parent, StockMaterial *mat ) { if ( !mat ) return 0; if ( !parent ) parent = m_root; QTreeWidgetItem *recItem = new QTreeWidgetItem( parent ); if ( mCheckboxes ) { recItem->setCheckState(0, Qt::Unchecked); } //recItem->setFlags( flags ); recItem->setText( 0, mat->getText() ); // recItem->setMultiLinesEnabled( true ); FIXME slFreshupItem( recItem, mat, catalog()->locale() ); m_dataDict.insert( recItem, mat ); return recItem; } void MaterialKatalogListView::slFreshupItem(QTreeWidgetItem *item, void* templ, QLocale *loc) { Q_UNUSED(loc) StockMaterial *mat = static_cast( templ ); if ( item && mat ) { Einheit e = mat->unit(); // qDebug () << "Setting material name " << e.einheitSingular(); item->setText( 0, mat->getText() ); item->setText( 1, QString::number( mat->getAmountPerPack() ) ); item->setText( 2, e.einheit( mat->getAmountPerPack() ) ); item->setText( 3, mat->purchPrice().toLocaleString() ); item->setText( 4, mat->salesPrice().toLocaleString() ); item->setText( 5, Format::toDateTimeString( mat->modifyDate(), KraftSettings::self()->dateFormat())); } else { // qDebug () << "Unable to freshup item - data invalid"; } } DocPosition MaterialKatalogListView::itemToDocPosition( QTreeWidgetItem *item ) { DocPosition pos; if ( ! item ) { item = currentItem(); } if ( ! item ) return pos; // FIXME StockMaterial *mat = static_cast( m_dataDict[item] ); if ( mat ) { pos.setText( mat->getText() ); pos.setUnit( mat->unit() ); pos.setUnitPrice( mat->salesPrice() ); } return pos; } void MaterialKatalogListView::saveState() { QByteArray state = this->header()->saveState(); KraftSettings::self()->setMaterialCatViewHeader(state.toBase64()); } void MaterialKatalogListView::startUpdateItemSequence() { _query = new QSqlQuery; _query->prepare("UPDATE stockMaterial SET sortKey = :sk WHERE matID=:id"); } void MaterialKatalogListView::updateItemSequence(QTreeWidgetItem *item, int seqNo) { StockMaterial *mat = static_cast( m_dataDict[item] ); if ( mat ) { int id = mat->getID(); _query->bindValue(":id", id); _query->bindValue(":sk", seqNo); _query->exec(); } } kraft-1.1/src/materialkataloglistview.h000066400000000000000000000034601450127457600203700ustar00rootroot00000000000000/*************************************************************************** materialkataloglistview - material katalog listview. ------------------- begin : 2006-11-30 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef MATERIALKATALOGLISTVIEW_H #define MATERIALKATALOGLISTVIEW_H #include #include class QTreeWidgetItem; class StockMaterial; class QLocale; /** A listview that presents the contents of the Bruns Catalog @author Klaas Freitag */ class MaterialKatalogListView : public KatalogListView { public: MaterialKatalogListView(QWidget *parent=0 ); ~MaterialKatalogListView(); void addCatalogDisplay( const QString& katName ); DocPosition itemToDocPosition( QTreeWidgetItem *it = 0 ); QTreeWidgetItem* addMaterialToView( QTreeWidgetItem*, StockMaterial* ); void saveState(); public slots: void slFreshupItem( QTreeWidgetItem *, void*, QLocale* = 0 ); protected: void startUpdateItemSequence(); void updateItemSequence(QTreeWidgetItem *item, int seqNo); }; #endif kraft-1.1/src/materialkatalogview.cpp000066400000000000000000000167631450127457600200410ustar00rootroot00000000000000/*************************************************************************** materialkatalogview.cpp ------------------- begin : 2005-07-26 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include "katalogman.h" #include "materialkatalogview.h" #include "materialkataloglistview.h" #include "stockmaterial.h" #include "matkatalog.h" #include "materialtempldialog.h" #include "kraftsettings.h" const QString MaterialKatalogView::MaterialCatalogName( "Material" ); MaterialKatalogView::MaterialKatalogView() : KatalogView(), m_materialListView(nullptr), m_details(nullptr) { } MaterialKatalogView::~MaterialKatalogView() { slotSaveState(); } void MaterialKatalogView::createCentralWidget( QBoxLayout *box, QWidget *w ) { m_materialListView = new MaterialKatalogListView( w ); box->addWidget( m_materialListView ); KatalogView::createCentralWidget( box, w ); } Katalog* MaterialKatalogView::getKatalog( const QString& name ) { // qDebug () << "GetKatalog of material!"; Katalog *k = KatalogMan::self()->getKatalog( name ); if( ! k ) { k = new MatKatalog( name ); KatalogMan::self()->registerKatalog( k ); } return k; } void MaterialKatalogView::slEditTemplate() { MaterialKatalogListView *listview = static_cast(getListView()); if( listview ) { QTreeWidgetItem *item = listview->currentItem(); if( listview->isChapter(item) ) { // check if the chapter is empty. If so, switch to slNewTempalte() // if there others, open the chapter. if( !listview->isRoot( item ) && item->childCount() == 0 ) { slNewTemplate(); } else { // do nothing. } } else { // qDebug () << "Editing the material"; if( listview ) { StockMaterial *currTempl = static_cast ( listview->currentItemData() ); if( currTempl ) { QTreeWidgetItem *item = static_cast(listview->currentItem()); openDialog( item, currTempl, false ); } } } } } void MaterialKatalogView::slNewTemplate() { KatalogListView *listview = getListView(); if( !listview ) return; MaterialKatalogListView *matListView = static_cast(listview); StockMaterial *newMat = new StockMaterial(); newMat->setText( i18n( "" ) ); QTreeWidgetItem *parentItem = static_cast( listview->currentItem() ); if ( parentItem ) { if ( ! ( matListView->isRoot( parentItem ) || matListView->isChapter( parentItem ) ) ) { parentItem = static_cast(parentItem->parent()); } } if( parentItem && listview->isChapter( parentItem )) { // try to find out which catalog is open/current CatalogChapter *chap = static_cast(listview->itemData( parentItem )); newMat->setChapter( chap->id().toInt() ); } mNewItem = matListView->addMaterialToView( parentItem, newMat ); openDialog( mNewItem, newMat, true ); } void MaterialKatalogView::slDeleteTemplate() { // qDebug () << "delete template hit"; MaterialKatalogListView* listview = static_cast(getListView()); if( listview ) { StockMaterial *currTempl = static_cast (listview->currentItemData()); if( currTempl ) { int id = currTempl->getID(); QMessageBox msgBox; msgBox.setText(i18n( "Do you really want to delete the template from the catalog?")); msgBox.setStandardButtons(QMessageBox::Yes| QMessageBox::No); msgBox.setDefaultButton(QMessageBox::Yes); int ret = msgBox.exec(); if ( ret == QMessageBox::Yes) { // qDebug () << "Delete item with id " << id; MatKatalog *k = static_cast( getKatalog( m_katalogName ) ); if( k ) { k->deleteMaterial( id ); listview->removeTemplateItem( listview->currentItem()); } } } } } void MaterialKatalogView::openDialog( QTreeWidgetItem *listitem, StockMaterial *tmpl, bool isNew ) { mDialog = new MaterialTemplDialog( this ); mNewItem = listitem; KatalogListView *listview = getListView(); if( !listview ) return; if (listview->currentItem()) listview->currentItem()->setSelected(false); listitem->setSelected( true ); // listitem->ensureItemVisible( true ); connect( mDialog, SIGNAL( editAccepted( StockMaterial* ) ), this, SLOT( slotEditOk( StockMaterial* ) ) ); connect( mDialog, SIGNAL( editRejected( ) ), this, SLOT( slotEditRejected() ) ); mDialog->setMaterial( tmpl, MaterialCatalogName, isNew ); mDialog->show(); } void MaterialKatalogView::slotEditRejected() { if ( mNewItem ) { delete mNewItem; mNewItem = nullptr; } } void MaterialKatalogView::slotEditOk( StockMaterial *mat ) { KatalogListView *listview = getListView(); if( !listview ) return; MaterialKatalogListView *templListView = static_cast(listview); // qDebug () << "****** slotEditOk for Material"; if( mDialog ) { MatKatalog *k = static_cast( getKatalog( MaterialCatalogName ) ); if ( mDialog->templateIsNew() ) { QLocale *locale = nullptr; if ( k ) { k->addNewMaterial( mat ); locale = k->locale(); } if( mNewItem ) { mNewItem->setSelected( true ); templListView->slFreshupItem( mNewItem, mat, locale ); // templListView->ensureItemVisible( mNewItem ); } listview->updateChapterSort(mat->chapter()); } } mNewItem = nullptr; } void MaterialKatalogView::saveWindowState( const QByteArray& arr ) { KraftSettings::self()->setMaterialCatViewState(arr); KraftSettings::self()->save(); } QByteArray MaterialKatalogView::windowState() { const QByteArray re = QByteArray::fromBase64( KraftSettings::self()->materialCatViewState().toLatin1() ); return re; } void MaterialKatalogView::saveWindowGeo( const QByteArray& arr ) { KraftSettings::self()->setMaterialCatViewGeo(arr); KraftSettings::self()->save(); } QByteArray MaterialKatalogView::windowGeo() { const QByteArray re = QByteArray::fromBase64( KraftSettings::self()->materialCatViewGeo().toLatin1() ); return re; } kraft-1.1/src/materialkatalogview.h000066400000000000000000000041771450127457600175020ustar00rootroot00000000000000/*************************************************************************** materialkatalogview.h ------------------- begin : 2006-11-30 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef MATERIALKATALOGVIEW_H #define MATERIALKATALOGVIEW_H #include #include "materialkataloglistview.h" class QBoxLayout; class QTreeWidgetItem; class BrunsKatalogListView; class QLabel; class MaterialTemplDialog; /** @author Klaas Freitag */ class MaterialKatalogView : public KatalogView { Q_OBJECT public: MaterialKatalogView(); ~MaterialKatalogView(); void createCentralWidget(QBoxLayout*, QWidget *w); KatalogListView* getListView() { return m_materialListView; } static const QString MaterialCatalogName; protected slots: void slNewTemplate(); void slEditTemplate(); void slDeleteTemplate(); void openDialog( QTreeWidgetItem *, StockMaterial *, bool ); void slotEditRejected(); void slotEditOk( StockMaterial * ); protected: Katalog* getKatalog( const QString& ); void saveWindowState( const QByteArray& arr ); QByteArray windowState(); void saveWindowGeo( const QByteArray& arr ); QByteArray windowGeo(); MaterialKatalogListView *m_materialListView; QLabel *m_detailLabel; QTreeWidget *m_details; MaterialTemplDialog *mDialog; QTreeWidgetItem *mNewItem; }; #endif kraft-1.1/src/materialsaverbase.cpp000066400000000000000000000022471450127457600174670ustar00rootroot00000000000000/*************************************************************************** templatesaverbase - ------------------- begin : 2005-20-01 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt // include files for KDE #include "materialsaverbase.h" MaterialSaverBase::MaterialSaverBase( ) :QObject() { } MaterialSaverBase::~MaterialSaverBase( ) { } /* END */ kraft-1.1/src/materialsaverbase.h000066400000000000000000000025761450127457600171410ustar00rootroot00000000000000/*************************************************************************** materialsaverbase - Base class of a material saver ------------------- begin : 2006-12-07 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _MATERIALSAVERBASE_H #define _MATERIALSAVERBASE_H // include files #include /** * */ class StockMaterial; class MaterialSaverBase : public QObject { Q_OBJECT public: MaterialSaverBase(); ~MaterialSaverBase(); virtual bool saveTemplate( StockMaterial* ) = 0; virtual void saveTemplateChapter( StockMaterial* ) = 0; }; #endif /* END */ kraft-1.1/src/materialsaverdb.cpp000066400000000000000000000077711450127457600171510ustar00rootroot00000000000000/*************************************************************************** materialsaverdb - ------------------- begin : 2006-12-07 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include #include #include #include "kraftdb.h" #include "kraftglobals.h" #include "dbids.h" #include "materialsaverdb.h" #include "stockmaterial.h" MaterialSaverDB::MaterialSaverDB( ) : MaterialSaverBase() { } Q_GLOBAL_STATIC(MaterialSaverDB, mSelf) MaterialSaverBase *MaterialSaverDB::self() { return mSelf; } bool MaterialSaverDB::saveTemplate( StockMaterial *mat ) { bool res = true; // Transaktion ? QSqlTableModel model; model.setTable("stockMaterial"); QString templID = QString::number( mat->getID() ); model.setFilter( "matID=" + templID ); model.select(); QSqlRecord buffer = model.record(); if( model.rowCount() > 0) { // qDebug () << "Updating material " << mat->getID(); // mach update buffer = model.record(0); fillMaterialBuffer( buffer, mat, false ); model.setRecord(0, buffer); model.submitAll(); } else { // insert // qDebug () << "Creating new material database entry"; fillMaterialBuffer( buffer, mat, true ); model.insertRecord(-1, buffer); model.submitAll(); /* Jetzt die neue Template-ID selecten */ dbID id = KraftDB::self()->getLastInsertID(); // qDebug () << "New Database ID=" << id.toInt(); if( id.isOk() ) { mat->setID( id.toInt() ); templID = id.toString(); } else { // qDebug () << "ERROR: Kann AUTOINC nicht ermitteln"; res = false; } } return res; } void MaterialSaverDB::fillMaterialBuffer( QSqlRecord &rec, StockMaterial *mat, bool isNew ) { Q_ASSERT(mat->chapter() != 0); if( ! ( mat ) ) return; rec.setValue( "chapterID", mat->chapter() ); rec.setValue( "material", mat->getText() ); rec.setValue( "unitID", mat->unit().id() ); rec.setValue( "perPack", mat->getAmountPerPack() ); rec.setValue( "priceIn", mat->purchPrice().toDouble() ); rec.setValue( "priceOut", mat->salesPrice().toDouble() ); QString dtString = KraftDB::self()->currentTimeStamp(); if( isNew ) { rec.setValue( "enterDate", dtString); } rec.setValue("modifyDate", dtString ); } void MaterialSaverDB::saveTemplateChapter( StockMaterial* tmpl ) { if( ! tmpl ) { // qDebug () << "Parameter error, zero material!"; return; } dbID id = tmpl->getID(); dbID chapId = tmpl->chapterId(); QSqlTableModel model; model.setTable("stockMaterial"); QString templID = id.toString(); model.setFilter( "matID=" + templID ); model.select(); QSqlRecord buffer = model.record(); if( model.rowCount() > 0) { // qDebug () << "Updating material chapter " << templID; buffer = model.record(0); buffer.setValue( "chapterID", chapId.toString() ); model.setRecord(0, buffer); model.submitAll(); } else { // qDebug () << "Could not update material chapter, not found with id " << templID; } } kraft-1.1/src/materialsaverdb.h000066400000000000000000000027071450127457600166100ustar00rootroot00000000000000/*************************************************************************** materialsaverdb - ------------------- begin : 2006-12-07 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _MATERIALSAVERDB_H #define _MATERIALSAVERDB_H // include files #include "materialsaverbase.h" /** * */ class QSqlRecord; class StockMaterial; class MaterialSaverDB : public MaterialSaverBase { public: static MaterialSaverBase* self(); MaterialSaverDB(); private: virtual bool saveTemplate( StockMaterial* ); virtual void fillMaterialBuffer( QSqlRecord &, StockMaterial* , bool ); virtual void saveTemplateChapter( StockMaterial* ); }; #endif /* END */ kraft-1.1/src/materialselectdialog.cpp000066400000000000000000000055461450127457600201600ustar00rootroot00000000000000/*************************************************************************** materialselectdialog - select material for inserting into template ------------------- begin : 2006-12-17 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include "materialkatalogview.h" #include "materialselectdialog.h" #include "materialkataloglistview.h" #include "katalogman.h" #include "matkatalog.h" #include "katalog.h" #include "filterheader.h" MaterialSelectDialog::MaterialSelectDialog( QWidget *parent) : CalcDialogBase( parent ) { setWindowTitle( i18n("Add Material to Calculation" ) ); QVBoxLayout *mainLayout = new QVBoxLayout; _centralWidget->setLayout(mainLayout); QLabel *label = new QLabel( i18n( "

            Add Material to Calculation

            " )); mainLayout->addWidget(label); mKatalogListView = new MaterialKatalogListView; FilterHeader *filter = new FilterHeader(this, mKatalogListView); mainLayout->addWidget(filter); mainLayout->addWidget(mKatalogListView); mKatalogListView->setCheckboxes( true ); Katalog *kat = KatalogMan::self()->getKatalog( MaterialKatalogView::MaterialCatalogName ); if ( ! kat ) { kat = new MatKatalog( MaterialKatalogView::MaterialCatalogName ); KatalogMan::self()->registerKatalog( kat ); } mKatalogListView->addCatalogDisplay( MaterialKatalogView::MaterialCatalogName ); } MaterialSelectDialog::~MaterialSelectDialog() { } void MaterialSelectDialog::accept() { // qDebug () << "++ Material selected!"; QTreeWidgetItemIterator it( mKatalogListView, QTreeWidgetItemIterator::Checked ); while (*it) { // qDebug () << "T: " << (*it)->text( 0 ); QTreeWidgetItem *item = *it; if( !( mKatalogListView->isChapter( item ) || mKatalogListView->isRoot( item ))) { StockMaterial *mat = static_cast( mKatalogListView->itemData( item ) ); if ( mat ) { emit materialSelected( mat->getID(), 1 ); } } ++it; } QDialog::accept(); } kraft-1.1/src/materialselectdialog.h000066400000000000000000000032421450127457600176140ustar00rootroot00000000000000/*************************************************************************** materialselectdialog - select material for inserting into template ------------------- begin : 2006-12-17 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _MATERIALSELECTDIALOG_H #define _MATERIALSELECTDIALOG_H #include "calcdialogbase.h" class MaterialKatalogListView; /* ******************************************************************************** * Editor that shows the MaterialKatalogListView * ********************************************************************************/ class MaterialSelectDialog : public CalcDialogBase { Q_OBJECT public: MaterialSelectDialog(QWidget * parent = 0); ~MaterialSelectDialog(); public slots: protected slots: void accept(); signals: void materialSelected( int, double ); private: MaterialKatalogListView *mKatalogListView; }; #endif /* END */ kraft-1.1/src/materialtempldialog.cpp000066400000000000000000000162521450127457600200160ustar00rootroot00000000000000/*************************************************************************** materialtempldialog - dialog to edit material templates ------------------- begin : 2006-12-03 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include // include files for KDE #include #include #include #include #include #include "materialtempldialog.h" #include "katalogman.h" #include "unitmanager.h" #include "geld.h" #include "kraftsettings.h" #include "defaultprovider.h" MaterialTemplDialog::MaterialTemplDialog( QWidget *parent, bool modal ) : QDialog( parent ), Ui::MaterialDialogBase(), Eta( 0.00000000001 ) { /* connect a value Changed signal of the manual price field */ QWidget *w = new QWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(w); setupUi( w ); setModal( modal ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(buttonBox); buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); const QString currSymbol = DefaultProvider::self()->locale()->currencySymbol(); mInPurchasePrice->setPrefix( currSymbol + " " ); mInPurchasePrice->setMinimum( -999999.99 ); mInPurchasePrice->setMaximum( 999999.99 ); mInPurchasePrice->setDecimals( 2 ); mInSalePrice->setPrefix( currSymbol + " " ); mInSalePrice->setMinimum( -999999.99 ); mInSalePrice->setMaximum( 999999.99 ); mInSalePrice->setDecimals( 2 ); double m = KraftSettings::self()->materialAddOnPercent(); mInSaleAdd->setValue(m); mInSaleAdd->setMinimum(-99.0); mInSaleAdd->setMaximum(999.0); connect( mInSalePrice, SIGNAL( valueChanged( double ) ), SLOT( slSalePriceChanged( double ) ) ); connect( mInPurchasePrice, SIGNAL( valueChanged( double ) ), SLOT( slPurchPriceChanged( double ) ) ); connect( mInSaleAdd, SIGNAL( valueChanged( double ) ), SLOT( slSaleAddChanged( double ) ) ); } void MaterialTemplDialog::slSalePriceChanged( double sale ) { // change the percent val double purch = mInPurchasePrice->value(); double m = mInSaleAdd->value(); if ( m > Eta && purch < Eta ) { // recalc the purchase price purch = sale/( 1+ m / 100.0 ); } else if ( purch > Eta ) { // recalc the add-percentage m = 100 * ( ( sale-purch ) / purch ); } setPriceCalc( purch, m, sale ); } void MaterialTemplDialog::slPurchPriceChanged( double purch ) { // change the percent val double sale = mInSalePrice->value(); double m = mInSaleAdd->value(); if ( m > Eta ) { sale = ( 1+m/100 )*purch; } setPriceCalc( purch, m, sale ); } void MaterialTemplDialog::slSaleAddChanged( double m ) { // change the Sales Price double sale = mInSalePrice->value(); double purch = mInPurchasePrice->value(); if (purch < Eta && sale > Eta ) { // calc the purchase price purch = sale/( 1+ m/100 ); } else { sale = ( 1+ m/100.0 ) * purch; } setPriceCalc( purch, m, sale ); } void MaterialTemplDialog::setPriceCalc( double purch, double addPercent, double sale ) { mInPurchasePrice->blockSignals(true); mInSalePrice->blockSignals(true); mInSaleAdd->blockSignals(true); mInPurchasePrice->setValue( purch ); mInSalePrice->setValue( sale ); mInSaleAdd->setValue( addPercent ); mInPurchasePrice->blockSignals(false); mInSalePrice->blockSignals(false); mInSaleAdd->blockSignals(false); } void MaterialTemplDialog::setMaterial( StockMaterial *t, const QString& katalogname, bool newTempl ) { if( ! t ) return; mSaveMaterial = t; m_templateIsNew = newTempl; m_katalog = KatalogMan::self()->getKatalog(katalogname); if( m_katalog == 0 ) { // qDebug () << "ERR: Floskel Dialog called without valid Katalog!"; return; } // chapter settings QStringList chapterNames; foreach( CatalogChapter chap, m_katalog->getKatalogChapters() ) { chapterNames.append( chap.name() ); } mCbChapter->insertItems(-1, chapterNames ); mChapId = t->chapter(); QString chap = m_katalog->chapterName(dbID( mChapId )); mCbChapter->setCurrentIndex(mCbChapter->findText( chap )); mCbChapter->setEnabled( false ); // unit settings mCbUnit->insertItems(-1, UnitManager::self()->allUnits() ); Einheit e = t->unit(); mCbUnit->setCurrentIndex(mCbUnit->findText( e.einheitSingular() )); // text mEditMaterial->setPlainText( t->getText() ); double priceIn = t->purchPrice().toDouble(); double priceOut = t->salesPrice().toDouble(); mInPurchasePrice->setValue( priceIn ); mInSalePrice->setValue( priceOut ); mDiPerPack->setValue( t->getAmountPerPack() ); // user experience mEditMaterial->setFocus(); mEditMaterial->selectAll(); // percent add on sale price double percent = 10.0; if( priceIn > Eta ) { double diff = priceOut - priceIn; percent = diff / priceIn * 100.0; } mInSaleAdd->setValue( percent ); } MaterialTemplDialog::~MaterialTemplDialog( ) { } void MaterialTemplDialog::accept() { // qDebug () << "*** Saving finished "; const QString newMat = mEditMaterial->toPlainText(); if ( newMat.isEmpty() ) { // qDebug () << "We do not want to store empty materials"; } else { mSaveMaterial->setText( mEditMaterial->toPlainText() ); mSaveMaterial->setAmountPerPack( mDiPerPack->value() ); const QString str = mCbUnit->currentText(); int u = UnitManager::self()->getUnitIDSingular( str ); // qDebug () << "Setting unit id " << u; mSaveMaterial->setUnitId( u ); // chapId = 0; // FIXME: get a chapter catalog Id of hirarchical mSaveMaterial->setChapter( mChapId ); double db = mInPurchasePrice->value(); mSaveMaterial->setPurchPrice( Geld( db ) ); db = mInSalePrice->value(); mSaveMaterial->setSalesPrice( Geld( db ) ); mSaveMaterial->save(); emit editAccepted( mSaveMaterial ); KatalogMan::self()->notifyKatalogChange( m_katalog, mSaveMaterial->getID() ); } QDialog::accept(); } void MaterialTemplDialog::reject() { if ( m_templateIsNew ) { // remove the listview item if it was created newly emit editRejected(); } QDialog::reject(); } kraft-1.1/src/materialtempldialog.h000066400000000000000000000037201450127457600174570ustar00rootroot00000000000000/*************************************************************************** materialtempldialog - ------------------- begin : 2006-12-04 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _MATERIALTEMPLDIALOG_H #define _MATERIALTEMPLDIALOG_H // include files #include "kraftglobals.h" #include "ui_materialdialog.h" #include "stockmaterial.h" /** * */ class Katalog; class MaterialTemplDialog : public QDialog, protected Ui::MaterialDialogBase { Q_OBJECT public: MaterialTemplDialog( QWidget *parent=0, bool modal=false ); ~MaterialTemplDialog(); void setMaterial( StockMaterial* t, const QString&, bool ); bool templateIsNew() { return m_templateIsNew; }; signals: void editAccepted( StockMaterial* ); void editRejected(); void chapterChanged(int); public slots: protected slots: virtual void accept(); virtual void reject(); void slSalePriceChanged( double ); void slPurchPriceChanged( double ); void slSaleAddChanged( double ); private: void setPriceCalc( double, double, double ); StockMaterial *mSaveMaterial; bool m_templateIsNew; Katalog *m_katalog; const double Eta; int mChapId; }; #endif /* END */ kraft-1.1/src/matkatalog.cpp000066400000000000000000000072051450127457600161200ustar00rootroot00000000000000/*************************************************************************** matkatalog - the material catalog ------------------- begin : 2004-19-10 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include // include files for KDE #include #include "matkatalog.h" #include "kraftdb.h" MatKatalog::MatKatalog( const QString& name) : Katalog(name) { } MatKatalog::MatKatalog() : Katalog( QLatin1String( "Material" )) { } void MatKatalog::reload( dbID ) { mAllMaterial.clear(); load(); } int MatKatalog::load() { Katalog::load(); int cnt = 0; QSqlQuery q(QLatin1String("SELECT matID, chapterID, material, unitID, perPack, priceIn, " "priceOut, modifyDate, enterDate FROM stockMaterial ORDER BY chapterID, sortKey")); q.exec(); while ( q.next() ) { cnt++; int id = q.value( 0 ).toInt(); int chapterID = q.value( 1 ).toInt(); const QString material = q.value( 2 ).toString(); int unitID = q.value( 3 ).toInt(); double pPack = q.value( 4 ).toDouble(); double priceIn = q.value( 5 ).toDouble(); double priceOut = q.value(6 ).toDouble(); QDateTime lastMod = q.value( 7 ).toDateTime(); QDateTime entered = q.value( 8 ).toDateTime(); StockMaterial *mat = new StockMaterial( id, chapterID, material, unitID, pPack, Geld( priceIn ), Geld( priceOut ) ); mat->setEnterDate(entered); mat->setModifyDate(lastMod); auto usage = usageCount(id); mat->setLastUsedDate(usage.second); mat->setUseCounter(usage.first); mAllMaterial.append( mat ); } return cnt; } void MatKatalog::deleteMaterial( int id ) { StockMaterialListIterator it( mAllMaterial ); int cnt = 0; // qDebug () << "Deleting material id=" << id; while( it.hasNext() ) { StockMaterial *mat = it.next(); if( mat->getID() == id ) { break; } cnt++; } if( cnt < mAllMaterial.count() ) { mAllMaterial.removeAt( cnt ); } // remove from database. QSqlQuery q; q.prepare( QLatin1String("DELETE FROM stockMaterial WHERE matID=:Id")); q.bindValue( ":Id", id ); q.exec(); deleteUsageRecord(id); // qDebug () << "SQL Delete Success: " << q.lastError().text(); } StockMaterialList MatKatalog::getRecordList( int chapterId ) { StockMaterialList list; for (StockMaterial *mat: mAllMaterial) { if ( mat->chapter() == chapterId ) { list.append( mat ); } } return list; } StockMaterial* MatKatalog::materialFromId( long id ) { StockMaterialListIterator it( mAllMaterial ); while( it.hasNext() ) { StockMaterial *mat = it.next(); if ( mat->getID() == id ) { return mat; } } return nullptr; } void MatKatalog::addNewMaterial( StockMaterial *mat ) { mAllMaterial.append( mat ); } MatKatalog::~MatKatalog( ) { } /* END */ kraft-1.1/src/matkatalog.h000066400000000000000000000032361450127457600155650ustar00rootroot00000000000000/*************************************************************************** matkatalog - Materialkatalogklasse ------------------- begin : 2004-19-10 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _MATKATALOG_H #define _MATKATALOG_H // include files #include #include "stockmaterial.h" #include "katalog.h" /** * */ class MatKatalog : public Katalog { public: MatKatalog( const QString& name ); MatKatalog(); ~MatKatalog(); int getEntriesPerChapter( const CatalogChapter& ) override { return 0; } // FIXME int load() override; void reload( dbID ) override; void deleteMaterial( int ); StockMaterial *materialFromId(long id); KatalogType type() override { return MaterialCatalog; } StockMaterialList getRecordList(int chapterId); void addNewMaterial( StockMaterial* ); private: StockMaterialList mAllMaterial; }; #endif /* END */ kraft-1.1/src/matpartui.ui000066400000000000000000000076571450127457600156500ustar00rootroot00000000000000 calcdetailMat 0 0 435 228 Calculation Item Material <h1>Calculation Part 'Material'</h1> false Add Material to the template calculation. Qt::AlignVCenter true QFrame::StyledPanel QFrame::Raised 0 0 material Qt::AlignVCenter true &Amount: false m_inpMenge Price for one piece 1.000000000000000 99999.000000000000000 unit false Qt::Horizontal QSizePolicy::Expanding 61 20 QDoubleSpinBox QWidget kraft-1.1/src/matpartui.ui.h000066400000000000000000000011161450127457600160560ustar00rootroot00000000000000/**************************************************************************** ** ui.h extension file, included from the uic-generated form implementation. ** ** If you want to add, delete, or rename functions or slots, use ** Qt Designer to update this file, preserving your code. ** ** You should not define a constructor or destructor in this file. ** Instead, write your code in functions called init() and destroy(). ** These will automatically be called by the form's constructor and ** destructor. *****************************************************************************/ kraft-1.1/src/metaxmlparser.cpp000066400000000000000000000064241450127457600166620ustar00rootroot00000000000000/*************************************************************************** metaxmlparser.cpp - Parser for Meta XML files ------------------- begin : Dec 29 2018 copyright : (C) 2018 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include "metaxmlparser.h" MetaXMLParser::MetaXMLParser() { } bool MetaXMLParser::parse( QIODevice *device ) { _docTypeAddList.clear(); if (!_domDocument.setContent(device, true, &_errorString, &_errorLine, &_errorColumn)) { qDebug() << "Not able to parse XML: " << _errorString << "Line"<< _errorLine << ", Colum" << _errorColumn; return false; } QDomElement root = _domDocument.documentElement(); if( root.tagName() != "kraftmeta" ) { qDebug() << "XML file parse error: Not a kraftmeta root"; } QDomElement migrateElem = root.firstChildElement("migrate"); QDomElement addDtXml = migrateElem.firstChildElement("doctype"); while( ! addDtXml.isNull() ) { MetaDocTypeAdd docTypeAdd; QDomElement elem = addDtXml.firstChildElement("name"); if( !elem.isNull() ) { docTypeAdd.setName(elem.text()); } elem = addDtXml.firstChildElement("numbercycle"); if( !elem.isNull() ) { docTypeAdd.setNumbercycle(elem.text()); } elem = addDtXml.firstChildElement("lang"); if( !elem.isNull() ) { docTypeAdd.setLang(elem.text()); } elem = addDtXml.firstChildElement("attrib"); while( !elem.isNull() ) { const QString key = elem.firstChildElement("key").text(); const QString val = elem.firstChildElement("value").text(); if( !key.isEmpty() ) docTypeAdd._attribs.insert(key, val); elem = elem.nextSiblingElement("attrib"); } elem = addDtXml.firstChildElement("follower"); while( !elem.isNull() ) { const QString fo = elem.text(); if( !fo.isEmpty() ) docTypeAdd._follower.append(fo); elem = elem.nextSiblingElement("follower"); } // save and move on to next element. if( !docTypeAdd.name().isNull() ) { _docTypeAddList.append(docTypeAdd); } addDtXml = addDtXml.nextSiblingElement("doctype"); } return true; } QList MetaXMLParser::metaDocTypeAddList() { return _docTypeAddList; } kraft-1.1/src/metaxmlparser.h000066400000000000000000000036271450127457600163310ustar00rootroot00000000000000/*************************************************************************** metaxmlparser.cpp - Parser for Meta XML files ------------------- begin : Dec 29 2018 copyright : (C) 2018 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef METAXMLPARSER_H #define METAXMLPARSER_H #include #include #include class MetaDocTypeAdd { public: void setName( const QString& name ) { _name = name; } QString name() const { return _name; } void setNumbercycle( const QString& name ) { _numbercycle = name; } QString numbercycle() const { return _numbercycle; } void setLang( const QString& name ) { _lang = name; } QString lang() const { return _lang; } QMap _attribs; QStringList _follower; private: QString _name; QString _lang; QString _numbercycle; }; class MetaXMLParser { public: MetaXMLParser(); bool parse( QIODevice *device ); QList metaDocTypeAddList(); private: QDomDocument _domDocument; QString _errorString; int _errorLine, _errorColumn; QList _docTypeAddList; }; #endif // METAXMLPARSER_H kraft-1.1/src/models/000077500000000000000000000000001450127457600145475ustar00rootroot00000000000000kraft-1.1/src/models/datemodel.cpp000066400000000000000000000261331450127457600172160ustar00rootroot00000000000000/*************************************************************************** datemodel.cpp ------------------- copyright : (C) 2017 by Klaas Freitag email : klaas@volle-kraft-voraus.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "datemodel.h" #include "docdigest.h" #include #include #include #include class TreeItem { public: TreeItem(AbstractIndx *indx, TreeItem *parent = 0); ~TreeItem(); void appendChild(TreeItem *child); TreeItem *child(int row); int childCount() const; QVariant data(int column) const; int row() const; TreeItem *parent(); QList children() { return childItems; } AbstractIndx *payload() { return dataPtr; } private: QList childItems; AbstractIndx *dataPtr; TreeItem *parentItem; }; TreeItem::TreeItem(AbstractIndx *indx, TreeItem *parent) :dataPtr(indx), parentItem(parent) { // make sure the parents have the children registered if( parent ) { parent->appendChild(this); } } TreeItem::~TreeItem() { foreach( TreeItem *i, childItems ) { delete i; } } TreeItem* TreeItem::child(int row) { return childItems.value(row); } TreeItem* TreeItem::parent() { return parentItem; } int TreeItem::row() const { if (parentItem) return parentItem->childItems.indexOf(const_cast(this)); return 0; } int TreeItem::childCount() const { return childItems.count(); } void TreeItem::appendChild(TreeItem *child) { childItems.append(child); } /* ================================================================== */ AbstractIndx::AbstractIndx() :_type(Invalid) { } AbstractIndx::AbstractIndx(IndxType t) :_type(t) { } AbstractIndx::AbstractIndx(IndxType t, DocDigest(digest)) :_docDigest(digest), _type(t) { } AbstractIndx::IndxType AbstractIndx::type() { return _type; } DocDigest AbstractIndx::digest() const { return _docDigest; } int AbstractIndx::year() { return _docDigest.rawDate().year(); } int AbstractIndx::month() { return _docDigest.rawDate().month(); } /* ================================================================== */ class YearIndx : public AbstractIndx { public: explicit YearIndx(int year) :AbstractIndx(IndxType::YearType) { QDate d (year, 1, 1); _docDigest.setDate(d); } }; /* ================================================================== */ class MonthIndx : public AbstractIndx { public: explicit MonthIndx(int year, int month) :AbstractIndx(IndxType::MonthType) { QDate d(year, month, 1); _docDigest.setDate(d); } }; /* ================================================================== */ DateModel::DateModel(QObject *parent) :DocBaseModel(parent) { rootItem = new TreeItem(0); } QVariant DateModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); TreeItem *item = static_cast(index.internalPointer()); AbstractIndx *indx = item->payload(); #if 0 if( role == Qt::BackgroundColorRole ) { if( indx->type() == AbstractIndx::YearType ) { return QColor(0x80, 0xC8, 0xFE); } else if( indx->type() == AbstractIndx::MonthType ) { return QColor(0xBF, 0xE3, 0xFE); } return QVariant(); } #endif if( role == Qt::FontRole ) { QFont f; if( indx->type() == AbstractIndx::YearType ) { f.setPointSize(22); return f; } else if( indx->type() == AbstractIndx::MonthType ) { f.setPointSize(16); return f; } } if (role != Qt::DisplayRole) return QVariant(); int col = index.column(); if( indx->type() == AbstractIndx::YearType ) { if( col == 0 ) { return item->payload()->year(); } else if(col == Treestruct_Year) { return item->payload()->year(); } else if(col == Treestruct_Type) { return AbstractIndx::YearType; } #if 0 QList monthItems = item->children(); if( _yearExtra[col] == Sum ) { float sum = 0.0; foreach( TreeItem *month, monthItems) { foreach( TreeItem *docItem, month->children()) { sum += docItem->payload()->data(col).toFloat(); } } return sum; } else if( _monthExtra[col] == Count ) { int cnt = 0; foreach( TreeItem *month, monthItems) { cnt += month->children().count(); } return cnt; } else { return item->payload()->data(col); } #endif } if( indx->type() == AbstractIndx::MonthType ) { // there might be a special column type if( col == 0 ) { return QDate::shortMonthName(item->payload()->month()); } else if(col == Treestruct_Month) { return item->payload()->month(); } else if(col == Treestruct_Year) { return item->payload()->year(); } else if(col == Treestruct_Type) { return AbstractIndx::MonthType; } #if 0 QList childitems = item->children(); if( _monthExtra[col] == Sum ) { float sum = 0.0; foreach( TreeItem *child, childitems) { sum += child->payload()->data(col).toFloat(); } return sum; } else if( _monthExtra[col] == Count ) { return childitems.count(); } else { } #endif } if( indx->type() == AbstractIndx::DocumentType ) { DocDigest digest = item->payload()->digest(); if( index.column() == Document_Id ) { // In column zero the day has to be displayed here const QDate date = digest.rawDate(); return date.day(); } else { return columnValueFromDigest( digest, index.column() ); } } return QVariant(); } Qt::ItemFlags DateModel::flags(const QModelIndex &index) const { if (!index.isValid()) return 0; return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } QModelIndex DateModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); TreeItem *parentItem; if (!parent.isValid()) parentItem = rootItem; else parentItem = static_cast(parent.internalPointer()); TreeItem *childItem = parentItem->child(row); if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); } QModelIndex DateModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); TreeItem *childItem = static_cast(index.internalPointer()); TreeItem *parentItem = childItem->parent(); if (parentItem == rootItem) return QModelIndex(); return createIndex(parentItem->row(), 0, parentItem); } int DateModel::rowCount(const QModelIndex &parent) const { TreeItem *parentItem; if (parent.column() > 0) return 0; if (!parent.isValid()) parentItem = rootItem; else parentItem = static_cast(parent.internalPointer()); return parentItem->childCount(); } void DateModel::setMonthSumColumn( int column ) { if(column < columnCount( QModelIndex() )) { _monthExtra[column] = Sum; } } void DateModel::setMonthCountColumn( int column ) { if( column < columnCount(QModelIndex()) ) { _monthExtra[column] = Count; } } void DateModel::setYearSumColumn( int column ) { if(column < columnCount(QModelIndex())) { _yearExtra[column] = Sum; } } void DateModel::setYearCountColumn( int column ) { if( column < columnCount(QModelIndex()) ) { _yearExtra[column] = Count; } } TreeItem *DateModel::findYearItem(int year) { TreeItem *yearItem = NULL; QList yearitems = rootItem->children(); foreach( TreeItem *item, yearitems ) { AbstractIndx *indx = item->payload(); if( indx->year() == year ) { yearItem = item; break; } } return yearItem; } TreeItem *DateModel::findMonthItem(int year, int month) { TreeItem *monthItem = NULL; TreeItem *yearItem = findYearItem( year ); if( yearItem ) { QList monthItems = yearItem->children(); foreach( TreeItem *item, monthItems ) { AbstractIndx *indx = static_cast(item->payload()); if( indx->month() == month ) { monthItem = item; break; } } } return monthItem; } bool DateModel::isDocument(const QModelIndex& indx) const { bool re = false; if( indx.isValid() ) { TreeItem *item = static_cast(indx.internalPointer()); if( item ) { AbstractIndx *abstractindx = item->payload(); re = !(abstractindx->type() == AbstractIndx::YearType || abstractindx->type() == AbstractIndx::MonthType ); } } return re; } DocDigest DateModel::digest(const QModelIndex& indx) const { DocDigest dig; TreeItem *item = static_cast(indx.internalPointer()); AbstractIndx *abstractindx = item->payload(); if( abstractindx->type() == AbstractIndx::YearType || abstractindx->type() == AbstractIndx::MonthType ) { // there is no digest } else { dig = abstractindx->digest(); } return dig; } void DateModel::removeAllData() { // the destructor of the TreeItem removes the entire tree recursivly delete rootItem; rootItem = new TreeItem(0); } void DateModel::addData( const DocDigest& digest ) // DocumentIndx doc ) { int month = digest.rawDate().month(); int year = digest.rawDate().year(); TreeItem *yearItem = NULL; TreeItem *monthItem = NULL; yearItem = findYearItem( year ); if( !yearItem ) { AbstractIndx *newIndx = new YearIndx(year); yearItem = new TreeItem( newIndx, rootItem ); } // ==== monthItem = findMonthItem( year, month ); if( !monthItem ) { AbstractIndx *newIndx = new MonthIndx(year, month); monthItem = new TreeItem( newIndx, yearItem); } DocumentIndx *itemIndx = new DocumentIndx(digest); TreeItem *newItem = new TreeItem( itemIndx, monthItem ); Q_UNUSED(newItem); } kraft-1.1/src/models/datemodel.h000066400000000000000000000057061450127457600166660ustar00rootroot00000000000000/*************************************************************************** datemodel.h ------------------- copyright : (C) 2017 by Klaas Freitag email : klaas@volle-kraft-voraus.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DATEMODEL_H #define DATEMODEL_H #include #include #include #include #include #include #include "docbasemodel.h" #include "docdigest.h" class TreeItem; class AbstractIndx { public: enum IndxType { Invalid = 0, DocumentType, YearType, MonthType }; explicit AbstractIndx(); virtual ~AbstractIndx() { } explicit AbstractIndx(IndxType t); explicit AbstractIndx(IndxType t, DocDigest(digest)); virtual IndxType type(); DocDigest digest() const; int year(); int month(); protected: DocDigest _docDigest; private: IndxType _type; }; /* ================================================================== */ class DocumentIndx : public AbstractIndx { public: DocumentIndx(const DocDigest& digest) :AbstractIndx(IndxType::DocumentType, digest) { } }; /* ================================================================== */ class DateModel : public DocBaseModel { public: DateModel(QObject *parent = 0); enum CalcType { Zero = 0, Sum, Count }; TreeItem* findYearItem(int year); TreeItem* findMonthItem(int year, int month); void setMonthSumColumn( int column ); void setMonthCountColumn( int column ); void setYearSumColumn( int column ); void setYearCountColumn( int column ); QVariant data(const QModelIndex &index, int role) const; Qt::ItemFlags flags(const QModelIndex &index) const; QModelIndex index(int row, int column, const QModelIndex &parent) const; QModelIndex parent(const QModelIndex &index) const; DocDigest digest(const QModelIndex& indx) const; int rowCount(const QModelIndex &parent) const; void removeAllData(); void addData(const DocDigest& digest); bool isDocument(const QModelIndex& indx) const; private: TreeItem *rootItem; QVector _monthExtra; QVector _yearExtra; }; #endif // DATEMODEL_H kraft-1.1/src/models/docbasemodel.cpp000066400000000000000000000160441450127457600177010ustar00rootroot00000000000000/*************************************************************************** datemodel.cpp ------------------- copyright : (C) 2017 by Klaas Freitag email : klaas@volle-kraft-voraus.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "docbasemodel.h" #include "kraftdb.h" #include #include #include #include DocBaseModel::DocBaseModel(QObject *parent) :QAbstractItemModel(parent) { _headers.resize(12); _headers[ Document_Id ] = i18n("Date"); // this is only displayed by the date model _headers[ Document_Ident ] = i18n("Doc. Number"); _headers[ Document_Type ] = i18n( "Doc. Type"); _headers[ Document_Whiteboard ] = i18n( "Whiteboard" ); _headers[ Document_ClientId ] = i18n( "Client Id" ); _headers[ Document_LastModified] = i18n( "Last modified" ); _headers[ Document_CreationDateRaw] = i18n( "Creation date" ); _headers[ Document_ProjectLabel] = i18n( "Project" ); _headers[ Document_ClientAddress ] = i18n( "Client Address" ); _headers[ Document_ClientName ] = i18n( "Client" ); mAddressProvider = new AddressProvider( this ); connect( mAddressProvider, SIGNAL(lookupResult(QString,KContacts::Addressee)), this, SLOT(slotAddresseeFound(QString, KContacts::Addressee))); } QString DocBaseModel::firstLineOf( const QString& str) const { QString var; if( !str.isEmpty() ) { QStringList li = str.split(QChar('\n')); var = QString( "> %1").arg(li[0]); } return var; } QVariant DocBaseModel::columnValueFromDigest( const DocDigest& digest, int col ) const { if( col < 0 || col >= Max_Column_Marker ) return QVariant(); QVariant var; QStringList li; QString help; switch(col) { case Document_Id: case Document_Id_Raw: var = digest.id(); break; case Document_Ident: var = digest.ident(); break; case Document_Type: var = digest.type(); break; case Document_Whiteboard: help = digest.whiteboard(); li = help.split(QChar('\n')); var = li[0]; break; case Document_ClientId: var = digest.clientId(); break; case Document_LastModified: var = digest.lastModified(); break; case Document_CreationDate: var = digest.date(); break; case Document_CreationDateRaw: var = digest.rawDate(); break; case Document_ProjectLabel: var = digest.projectLabel(); break; case Document_ClientAddress: { help = firstLineOf( digest.clientAddress()); break; } case Document_ClientName: { help = digest.clientId(); AddressProvider::LookupState state = mAddressProvider->lookupAddressee(help); if( state == AddressProvider::LookupFromCache ) { KContacts::Addressee addressee = mAddressProvider->getAddresseeFromCache(help); var = addressee.assembledName(); // qDebug() << "Address from Cache: " << var.toString(); } else if( state == AddressProvider::LookupOngoing ) { var = i18n("Looking up address"); } else if( state == AddressProvider::LookupStarted ) { var = i18n("Lookup started"); } else if( state == AddressProvider::LookupNotFound || state == AddressProvider::BackendError || state == AddressProvider::ItemError ) { var = firstLineOf(digest.clientAddress()); } break; } default: break; } return var; } int DocBaseModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return Max_Column_Marker; } QVariant DocBaseModel::headerData(int section, Qt::Orientation orientation, int role) const { if( role == Qt::DisplayRole && orientation == Qt::Horizontal && section < _headers.count() ) { return _headers.at(section); } return QVariant(); } Qt::ItemFlags DocBaseModel::flags(const QModelIndex &index) const { if (!index.isValid()) return 0; return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } void DocBaseModel::resetData() { beginResetModel(); removeAllData(); loadFromTable(); endResetModel(); } void DocBaseModel::slotAddresseeFound( const QString& uid, const KContacts::Addressee& contact) { // FIXME: Update the data in the model and update the view accordingly. // Given that the view is updated so often, it does not seem to be neccessary // to do at all. Maybe later... Q_UNUSED(uid); Q_UNUSED(contact); } int DocBaseModel::loadFromTable() { int cnt = 0; QSqlQuery query; query.prepare("SELECT docID, ident, docType, docDescription, clientID, lastModified," "date, projectLabel, clientAddress " "FROM document ORDER BY date DESC"); query.exec(); /* enum Columns { Document_Id = 0, Document_Ident = 1, Document_Type = 2, Document_Whiteboard = 3, Document_ClientId = 4, Document_LastModified = 5, Document_CreationDate = 6, Document_ProjectLabel = 7, Document_ClientAddress = 8, Document_ClientName = 9, }; */ while (query.next()) { DocDigest digest(query.value(Document_Id).toInt(), query.value(Document_Type).toString(), query.value(Document_ClientId).toString()); digest.setDate( query.value( Document_CreationDate ).toDate() ); QDateTime dt = query.value(Document_LastModified).toDateTime(); if (KraftDB::self()->isSqlite()) { // The timestamps in Sqlite are in UTC dt.setTimeSpec(Qt::UTC); digest.setLastModified(dt.toLocalTime()); } else { digest.setLastModified(dt); } const QString clientAdr = query.value(Document_ClientAddress).toString(); digest.setClientAddress( clientAdr ); QString ident = query.value(Document_Ident).toString(); digest.setIdent( ident ); digest.setWhiteboard( query.value(Document_Whiteboard).toString() ); digest.setProjectLabel( query.value(Document_ProjectLabel).toString() ); const QString clientId = query.value(Document_ClientId).toString(); digest.setClientId( clientId ); this->addData( digest ); } return cnt; } kraft-1.1/src/models/docbasemodel.h000066400000000000000000000055171450127457600173510ustar00rootroot00000000000000/*************************************************************************** datemodel.h ------------------- copyright : (C) 2017 by Klaas Freitag email : klaas@volle-kraft-voraus.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DOCBASEMODEL_H #define DOCBASEMODEL_H #include #include "addressprovider.h" #include "docdigest.h" #include #include #include #include #include #include class DocBaseModel : public QAbstractItemModel { Q_OBJECT public: DocBaseModel(QObject *parent = 0); virtual ~DocBaseModel() {} enum Columns { Document_Id = 0, Document_Ident = 1, Document_Type = 2, Document_Whiteboard = 3, Document_ClientId = 4, Document_LastModified = 5, Document_CreationDate = 6, Document_ProjectLabel = 7, Document_ClientAddress = 8, Document_ClientName = 9, Document_Id_Raw = 10, Document_CreationDateRaw = 11, Treestruct_Year = 12, Treestruct_Month = 13, Treestruct_Type = 14, Max_Column_Marker = 15 // leave this as last enum }; int columnCount(const QModelIndex &parent) const; virtual QVariant data(const QModelIndex &index, int role) const = 0; Qt::ItemFlags flags(const QModelIndex &index) const; virtual int rowCount(const QModelIndex &parent) const = 0; virtual void removeAllData() = 0; virtual void addData(const DocDigest& digest) = 0; virtual DocDigest digest(const QModelIndex& indx) const = 0; virtual bool isDocument(const QModelIndex& indx) const = 0; int loadFromTable(); void resetData(); protected: QVariant columnValueFromDigest( const DocDigest& digest, int col ) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; protected slots: void slotAddresseeFound(const QString &uid, const KContacts::Addressee &contact); private: QString firstLineOf( const QString& str) const; QVector _headers; AddressProvider *mAddressProvider; }; #endif // DATEMODEL_H kraft-1.1/src/models/documentmodel.cpp000066400000000000000000000056771450127457600201310ustar00rootroot00000000000000/*************************************************************************** documentmodel - the database model for documents ------------------- begin : 2010-01-11 copyright : (C) 2010 by Thomas Richard, 2011 by Klaas Freitag email : thomas.richard@proan.be ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ //QT includes #include #include #include #include #include #include //KDE includes #include //Kraft includes #include "documentmodel.h" #include "docdigest.h" #include "docbasemodel.h" #include "defaultprovider.h" DocumentModel::DocumentModel(QObject *parent) : DocBaseModel(parent) { } DocumentModel::~DocumentModel() { } int DocumentModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return _digests.count(); } void DocumentModel::removeAllData() { _digests.clear(); } void DocumentModel::addData( const DocDigest& digest ) { _digests.append(digest); } QModelIndex DocumentModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); return createIndex(row, column); } QModelIndex DocumentModel::parent(const QModelIndex &index) const { Q_UNUSED(index); return QModelIndex(); } bool DocumentModel::isDocument(const QModelIndex& indx) const { Q_UNUSED(indx); return indx.isValid(); } QVariant DocumentModel::data(const QModelIndex &idx, int role) const { if( !idx.isValid() ) return QVariant(); int row = idx.row(); if( row < 0 || row >= _digests.count() ) { return QVariant(); } const DocDigest digest = _digests.at(row); if(role == Qt::DisplayRole) { return columnValueFromDigest( digest, idx.column() ); } else if( role == Qt::SizeHintRole ) { QFont f = data(idx, Qt::FontRole).value(); QFontMetrics fm(f); int h = fm.height(); return QSize( 0, h + 4 ); } return QVariant(); } DocDigest DocumentModel::digest( const QModelIndex& index ) const { int row = index.row(); DocDigest digest; if( row > -1 && row < _digests.count() ) { digest = _digests.at(index.row()); } return digest; } kraft-1.1/src/models/documentmodel.h000066400000000000000000000040621450127457600175610ustar00rootroot00000000000000/*************************************************************************** documentmodel - the database model for documents ------------------- begin : 2010-01-11 copyright : Copyright 2010 by Thomas Richard, 2011 by Klaas Freitag email : thomas.richard@proan.be ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DOCUMENTMODEL_H #define DOCUMENTMODEL_H #include "docbasemodel.h" #include class DocDigest; class AddressProvider; class DocumentModel : public DocBaseModel { Q_OBJECT public: DocumentModel(QObject *parent = 0); ~DocumentModel(); QVariant data(const QModelIndex &idx, int role) const; // QVariant headerData( int, Qt::Orientation, int role = Qt::DisplayRole ) const; QModelIndex index(int row, int column, const QModelIndex &parent) const; QModelIndex parent(const QModelIndex &index) const; int rowCount(const QModelIndex &parent) const; // int columnCount(const QModelIndex &parent = QModelIndex()) const; DocDigest digest( const QModelIndex& ) const; void setQueryAgain(); void removeAllData(); void addData( const DocDigest& ); bool isDocument(const QModelIndex& indx) const; // protected slots: // void slotAddresseeFound( const QString&, const KContacts::Addressee& ); protected: private: DocDigestList _digests; }; #endif kraft-1.1/src/models/documentproxymodels.cpp000066400000000000000000000124301450127457600213770ustar00rootroot00000000000000/*************************************************************************** latestdocmodel - the latest documents model ------------------- begin : 2010-01-11 copyright : (C) 2010 by Thomas Richard email : thomas.richard@proan.be ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ //QT includes #include #include #include #include #include #include #include #include #include #include //Kraft includes #include "datemodel.h" #include "documentmodel.h" #include "defaultprovider.h" #include "docdigest.h" #include "documentproxymodels.h" DocumentFilterModel::DocumentFilterModel(int maxRows, QObject *parent) : QSortFilterProxyModel(parent), _enableTreeView(false), _treeModel(0), _tableModel(0) { m_MaxRows = maxRows; this->setFilterCaseSensitivity(Qt::CaseInsensitive); } void DocumentFilterModel::setMaxRows( int max ) { m_MaxRows = max; invalidateFilter(); // refreshes the model } void DocumentFilterModel::setEnableTreeview( bool treeview ) { _enableTreeView = treeview; DocBaseModel *model; if(_enableTreeView) { if( _treeModel.isNull() ) { _treeModel.reset(new DateModel); _treeModel->loadFromTable(); } model = _treeModel.data(); } else { if( _tableModel.isNull()) { _tableModel.reset(new DocumentModel); _tableModel->loadFromTable(); } model = _tableModel.data(); } setSourceModel(model); } bool DocumentFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); if( !index.isValid()) { return false; } bool accepted = false; // filter works on the document ID, the client name and the document type. const QRegExp filter = filterRegExp(); if( filter.pattern().isEmpty() ) { accepted = true; } else { const QModelIndex index0 = sourceModel()->index(sourceRow, DocumentModel::Document_Ident, sourceParent); const QString idStr = sourceModel()->data(index0).toString(); const QModelIndex index1 = sourceModel()->index(sourceRow, DocumentModel::Document_Type, sourceParent); const QString typeStr = sourceModel()->data(index1).toString(); const QModelIndex index2 = sourceModel()->index(sourceRow, DocumentModel::Document_ClientName, sourceParent); const QString clientNameStr = sourceModel()->data(index2).toString(); const QModelIndex index3 = sourceModel()->index(sourceRow, DocumentModel::Document_Whiteboard, sourceParent); const QString whiteboardStr = sourceModel()->data(index3).toString(); const QModelIndex index4 = sourceModel()->index(sourceRow, DocumentModel::Document_ProjectLabel, sourceParent); const QString projectStr = sourceModel()->data(index4).toString(); if( idStr.contains(filter) || typeStr.contains(filter) || clientNameStr.contains(filter) || whiteboardStr.contains(filter) || projectStr.contains(filter)) { accepted = true; } } // for the treeview, check all the children if( _enableTreeView ) { int rows = sourceModel()->rowCount(index); for (int row = 0; row < rows; row++) { if (filterAcceptsRow(row, index)) { accepted = true; } } } // if the entry is accepted so far, check if it is within the time limit if( accepted && m_MaxRows > -1 ) { const QModelIndex index = sourceModel()->index(sourceRow, DocumentModel::Document_CreationDateRaw, sourceParent); const QDate docDate = sourceModel()->data(index).toDate(); int dateDiff = docDate.daysTo(QDate::currentDate()); if( dateDiff > m_MaxRows ) { accepted = false; } } return accepted; } bool DocumentFilterModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const { QVariant leftData = sourceModel()->data(source_left); QVariant rightData = sourceModel()->data(source_right); if (leftData.type() == QVariant::DateTime) { return leftData.toDateTime() < rightData.toDateTime(); } if(leftData.type() == QVariant::Date ) { return leftData.toDate() < rightData.toDate(); } else { const QString leftString = leftData.toString(); const QString rightString = rightData.toString(); return QString::localeAwareCompare(leftString, rightString) < 0; } } kraft-1.1/src/models/documentproxymodels.h000066400000000000000000000036341450127457600210520ustar00rootroot00000000000000/*************************************************************************** documentproxymodels - contains proxymodels to show the documentmodel in different views ------------------- begin : 2010-01-11 copyright : Copyright 2010 by Thomas Richard email : thomas.richard@proan.be ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DOCUMENTPROXYMODELS_H #define DOCUMENTPROXYMODELS_H #include #include class QModelIndex; class QVariant; class QObject; class DateModel; class DocumentModel; //Filters out the last 10 items of the DocumentModel class DocumentFilterModel : public QSortFilterProxyModel { public: DocumentFilterModel(int maxRows = -1, QObject *parent = 0); void setMaxRows( int ); void setEnableTreeview( bool treeview ); protected: bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const; private: int m_MaxRows; bool _enableTreeView; QScopedPointer _treeModel; QScopedPointer _tableModel; }; #endif kraft-1.1/src/models/globalcontactmodel.h000066400000000000000000000033041450127457600205550ustar00rootroot00000000000000/* This file is part of KAddressBook. Copyright (c) 2009 Tobias Koenig This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef GLOBALCONTACTMODEL_H #define GLOBALCONTACTMODEL_H namespace Akonadi { class ChangeRecorder; class ContactsTreeModel; class Monitor; class Session; } /** * @short Provides the global model for all contacts * * This model provides the EntityTreeModel for all contacts. * The model is accessable via the static instance() method. */ class GlobalContactModel { public: /** * Destroys the global contact model. */ ~GlobalContactModel(); /** * Returns the global contact model instance. */ static GlobalContactModel* instance(); /** * Returns the item model of the global instance. */ Akonadi::ContactsTreeModel* model() const; private: GlobalContactModel(); static GlobalContactModel *mInstance; Akonadi::Session *mSession; Akonadi::ChangeRecorder *mMonitor; Akonadi::ContactsTreeModel *mModel; }; #endif kraft-1.1/src/mysqldetails.ui000066400000000000000000000045701450127457600163440ustar00rootroot00000000000000 mySqlDetailsForm 0 0 401 213 Please enter the MySQL Database server settings. For detailed setup instructions for the MySQL to use with Kraft please check the Kraft website. true Database Host: Database Name: Database User: Password: Qt::Vertical 20 12 kraft-1.1/src/newdocassistant.cpp000066400000000000000000000202221450127457600171770ustar00rootroot00000000000000/*************************************************************************** newdocassistant - widget to select header data for the doc ------------------- begin : 2008-02-12 copyright : (C) 2008 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "newdocassistant.h" #include "defaultprovider.h" #include "filterheader.h" #include "doctype.h" #include "kraftsettings.h" #include "addressselectorwidget.h" #include "documentman.h" CustomerSelectPage::CustomerSelectPage( QWidget *parent ) :QWizardPage ( parent ) { QVBoxLayout *vbox = new QVBoxLayout; setLayout( vbox ); setTitle(i18n( "New Document Settings" )); QLabel *help = new QLabel; help->setText( i18n( "Please select a customer as addressee for the document. " "If there is no entry for the customer in the addressbook yet, it can be opened " "by clicking on the button below." ) ); // help->setTextFormat( Qt::RichText ); help->setWordWrap( true ); help->setSizePolicy( QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed )); vbox->addWidget( help ); mAddresses = new AddressSelectorWidget(this); connect( mAddresses, SIGNAL( addressSelected( const KContacts::Addressee& ) ), SIGNAL( addresseeSelected( const KContacts::Addressee& ) ) ); vbox->addWidget( mAddresses ); } void CustomerSelectPage::saveState() { mAddresses->saveState(); } void CustomerSelectPage::setupAddresses() { } CustomerSelectPage:: ~CustomerSelectPage() { } // ########################################################################### DocDetailsPage::DocDetailsPage( QWidget *parent ) : QWizardPage(parent), _haveAddressSelect(true), mCustomerLabel( nullptr ) { QVBoxLayout *vbox = new QVBoxLayout; setLayout( vbox ); setTitle(i18n( "New Document Settings" )); QLabel *help = new QLabel; help->setTextFormat( Qt::RichText ); help->setText( i18n( "Select a document type and a date. A comment on the whiteboard " "helps to classify the document." ) ); vbox->addWidget( help ); mCustomerLabel = new QLabel; mCustomerLabel->setFrameStyle( QFrame::Box + QFrame::Sunken ); mCustomerLabel->setTextFormat( Qt::RichText ); mCustomerLabel->setText( i18n( "Customer: Not yet selected!" ) ); vbox->addWidget( mCustomerLabel ); QFormLayout *grid = new QFormLayout; vbox->addLayout( grid ); mTypeCombo = new QComboBox; mTypeCombo->insertItems( 0, DocType::allLocalised() ); mTypeCombo->setCurrentIndex( mTypeCombo->findText( DefaultProvider::self()->docType() )); grid->addRow( i18n("Document &Type:"), mTypeCombo ); mDateEdit = new QDateEdit; mDateEdit->setDate( QDate::currentDate() ); grid->addRow( i18n( "Document Date: " ), mDateEdit ); mWhiteboardEdit = new QTextEdit; grid->addRow( i18n( "Whiteboard Content:" ), mWhiteboardEdit ); QHBoxLayout *hbox = new QHBoxLayout; vbox->addLayout(hbox); mKeepItemsCB = new QCheckBox( i18n("Copy document items from predecessor document")); hbox->addWidget( mKeepItemsCB ); mSourceDocIdentsCombo = new QComboBox; hbox->addWidget(mSourceDocIdentsCombo); mSourceDocIdentsCombo->setVisible(false); mKeepItemsCB->setChecked(true); mKeepItemsCB->setVisible(false); vbox->addStretch( 1 ); } DocDetailsPage::~DocDetailsPage() { } void DocDetailsPage::setNoAddresses() { _haveAddressSelect = false; } // ########################################################################### KraftWizard::KraftWizard(QWidget *parent, const char* name, bool modal ) :QWizard( parent ), mCustomerPage( nullptr ), mCustomerBox( nullptr ), mParent( parent ) { setObjectName( name ); setModal( modal ); const QByteArray geo = QByteArray::fromBase64( KraftSettings::self()->newDocWizardGeometry().toLatin1() ); restoreGeometry(geo); } KraftWizard::~KraftWizard() { } void KraftWizard::init( bool haveAddressSelect, const QString& followUpDoc ) { QScopedPointer addressProvider; addressProvider.reset(new AddressProvider); if( followUpDoc.isEmpty() ) { setWindowTitle( i18n( "Create a new Kraft Document" ) ); } else { setWindowTitle(followUpDoc); } mDetailsPage = new DocDetailsPage(); addPage(mDetailsPage); // w1, QLatin1Literal("

            ") + + QLatin1Literal("

            ") ); // only pick an addressee if the document is really new if( addressProvider->backendUp() && haveAddressSelect ) { mCustomerPage = new CustomerSelectPage( ); addPage( mCustomerPage); // w, QLatin1Literal("

            ") + i18n( "Select an Addressee" ) + QLatin1Literal("

            ") ); mCustomerPage->setupAddresses(); connect( mCustomerPage, SIGNAL( addresseeSelected(KContacts::Addressee)), this, SLOT( slotAddressee(KContacts::Addressee))); } } void KraftWizard::done( int r ) { if( mCustomerPage ) { mCustomerPage->saveState(); } const QByteArray geo = saveGeometry().toBase64(); KraftSettings::self()->setNewDocWizardGeometry(geo); QWizard::done(r); } void KraftWizard::slotAddressee(const KContacts::Addressee& addressee) { // qDebug () << "Addressee Changed!"; mAddressee = addressee; } QDate KraftWizard::date() const { return mDetailsPage->mDateEdit->date(); } QString KraftWizard::addressUid() const { return mAddressee.uid(); } QString KraftWizard::docType() const { return mDetailsPage->mTypeCombo->currentText(); } QString KraftWizard::whiteboard() const { return mDetailsPage->mWhiteboardEdit->toPlainText(); } void KraftWizard::setDocToFollow( DocGuardedPtr sourceDoc) { if( !sourceDoc ) { return; } DocGuardedPtr dPtr = sourceDoc; QString id = sourceDoc->docID().toString(); while( ! id.isEmpty() ) { // store the id of the follower and clear id const QString idT = dPtr->docIdentifier(); mDetailsPage->mSourceDocIdentsCombo->addItem(idT, id); id = QString(); // remember the current dptr to be able to delete it soon DocGuardedPtr oldDptr = dPtr; dPtr = DocumentMan::self()->openDocumentbyIdent( dPtr->predecessor() ); if( dPtr ) { id = dPtr->docID().toString(); } if( oldDptr != sourceDoc ) { delete oldDptr; } } if( mDetailsPage->mSourceDocIdentsCombo->count() > 0 ) { mDetailsPage->mKeepItemsCB->setVisible(true); mDetailsPage->mSourceDocIdentsCombo->setVisible(true); } // we already know the customer, disable the customer select page. mDetailsPage->setNoAddresses(); if ( mDetailsPage->mCustomerLabel ) { const QString followText = i18n("Followup Document for %1", sourceDoc->docIdentifier() ); mDetailsPage->mCustomerLabel->setText( followText ); } } QString KraftWizard::copyItemsFromPredecessor() { QString re; if( mDetailsPage->mKeepItemsCB->checkState() == Qt::Checked ) { re = mDetailsPage->mSourceDocIdentsCombo->currentData().toString(); } return re; } void KraftWizard::setAvailDocTypes( const QStringList& list ) { mDetailsPage->mTypeCombo->clear(); mDetailsPage->mTypeCombo->insertItems( -1, list ); } kraft-1.1/src/newdocassistant.h000066400000000000000000000061511450127457600166510ustar00rootroot00000000000000/*************************************************************************** new doc assistant - widget to select Addresses ------------------- begin : 2008-02-12 copyright : (C) 2008 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef NEWDOCASSISTANT_H #define NEWDOCASSISTANT_H #include #include #include #include #include "kraftdoc.h" #include "docguardedptr.h" class DocText; class TextSelection; class KraftWizard; class AddressSelectorWidget; class QDateEdit; class QComboBox; class QHBox; class QTextEdit; class QCheckBox; using namespace KContacts; // --------------------------------------------------------------------------- class CustomerSelectPage: public QWizardPage { Q_OBJECT friend class KraftWizard; public: CustomerSelectPage( QWidget *parent = 0 ); ~CustomerSelectPage(); void setupAddresses(); public slots: void saveState(); signals: void addresseeSelected( const KContacts::Addressee& ); private: AddressSelectorWidget *mAddresses; }; // --------------------------------------------------------------------------- class DocDetailsPage : public QWizardPage { Q_OBJECT friend class KraftWizard; public: DocDetailsPage( QWidget *parent = 0 ); ~DocDetailsPage(); void setNoAddresses(); private: bool _haveAddressSelect; QLabel *mCustomerLabel; QDateEdit *mDateEdit; QComboBox *mTypeCombo; QTextEdit *mWhiteboardEdit; QCheckBox *mKeepItemsCB; QComboBox *mSourceDocIdentsCombo; }; // --------------------------------------------------------------------------- class KraftWizard: public QWizard { Q_OBJECT public: KraftWizard(QWidget *parent = 0, const char* name = 0, bool modal = false ); void init(bool haveAddressSelect, const QString& followUpDoc = QString()); ~KraftWizard(); QDate date() const ; QString addressUid() const; QString docType() const; QString whiteboard() const; void setCustomer( const QString& ); void setDocToFollow( DocGuardedPtr sourceDoc); void setAvailDocTypes( const QStringList& ); void done(int r); QString copyItemsFromPredecessor(); protected slots: void slotAddressee( const KContacts::Addressee& ); private: CustomerSelectPage *mCustomerPage; DocDetailsPage *mDetailsPage; QHBox *mCustomerBox; QWidget *mParent; KContacts::Addressee mAddressee; }; #endif kraft-1.1/src/numbercycle.cpp000066400000000000000000000030251450127457600163000ustar00rootroot00000000000000/*************************************************************************** numbercycle.h - document number cycles ------------------- begin : Jan 15 2009 copyright : (C) 2009 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "numbercycle.h" NumberCycle::NumberCycle() { } NumberCycle::NumberCycle( dbID _id ) :id( _id ) { } void NumberCycle::setName( const QString& n ) { mName = n; } QString NumberCycle::name() { return mName; } void NumberCycle::setTemplate( const QString& t ) { mTemplate = t; } QString NumberCycle::getTemplate() { return mTemplate; } void NumberCycle::setCounter( int c ) { mCounter = c; } int NumberCycle::counter() { return mCounter; } QString NumberCycle::defaultName() { return QString( "default" ); } kraft-1.1/src/numbercycle.h000066400000000000000000000027361450127457600157550ustar00rootroot00000000000000/*************************************************************************** numbercycle.h - document number cycles ------------------- begin : Jan 15 2009 copyright : (C) 2009 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef NUMBERCYCLE_H #define NUMBERCYCLE_H #include #include "dbids.h" #include "kraftcat_export.h" class KRAFTCAT_EXPORT NumberCycle { public: NumberCycle(); NumberCycle( dbID ); void setName( const QString& ); QString name(); void setTemplate( const QString& ); QString getTemplate(); void setCounter( int ); int counter(); static QString defaultName(); private: dbID id; QString mName; QString mTemplate; int mCounter; }; #endif kraft-1.1/src/numbercycledialog.cpp000066400000000000000000000335351450127457600174710ustar00rootroot00000000000000/*************************************************************************** doctypeedit.h - the document type editor ------------------- begin : Fri Jan 2 2009 copyright : (C) 2009 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "prefsdialog.h" #include "kraftsettings.h" #include "kraftdb.h" #include "kraftdoc.h" #include "defaultprovider.h" #include "doctype.h" #include "doctypeedit.h" #include "numbercycledialog.h" NumberCycleDialog::NumberCycleDialog( QWidget *parent, const QString& initType ) :QDialog( parent ) // "NUMBER_CYCLES_EDIT", true, i18n( "Edit Number Cycles" ), Ok|Cancel ) { setObjectName( "NUMBER_CYCLES_EDIT" ); setModal( true ); setWindowTitle( i18n( "Edit Number Cycles" ) ); QVBoxLayout *layout = new QVBoxLayout; setLayout(layout); QWidget *w = new QWidget; layout->addWidget(w); mBaseWidget = new Ui::NumberCycleEditBase( ); mBaseWidget->setupUi( w ); mBaseWidget->mPbAdd->setIcon( DefaultProvider::self()->icon( "list-add" ) ); mBaseWidget->mPbRemove->setIcon( DefaultProvider::self()->icon( "list-remove" ) ); mBaseWidget->mCounterEdit->setMaximum( 1000000 ); mBaseWidget->mCounterEdit->setSingleStep( 1 ); const QString tip = i18n( "The template may contain the following tags:" "
            • %y or %yyyy - the year of the documents date.
            • " "
            • %yy - the year of the document (two digits).
            • " "
            • %w - the week number of the documents date.
            • " "
            • %ww - the week number of the documents date with leading zero.
            • " "
            • %d - the day number of the documents date.
            • " "
            • %dd - the day number of the documents date with leading zero.
            • " "
            • %m or %M - the month number of the documents date.
            • " "
            • %MM - the month number with leading zero.
            • " "
            • %c - the customer id from kaddressbook
            • " "
            • %i - the unique counter
            • " "
            • %ii .. %iiiiii - the counter padded with leading 0, ie. 012
            • " "
            • %n - a day based counter, resets every day. Combined with date, it makes the number unique.
            • " "
            • %nn .. %nnnnnn - the day based counter padded with leading 0.
            • " "
            • %type - the localised doc type (offer, invoice etc.)
            • " "
            • %uid - the contact id of the client.
            • " "
            %i or %n need to be part of the template." ); mBaseWidget->mIdTemplEdit->setToolTip( tip ); connect( mBaseWidget->mPbAdd, SIGNAL( clicked() ), SLOT( slotAddCycle() ) ); connect( mBaseWidget->mPbRemove, SIGNAL( clicked() ), SLOT( slotRemoveCycle() ) ); loadCycles(); connect( mBaseWidget->mCycleListBox, SIGNAL( currentRowChanged( int ) ), SLOT( slotNumberCycleSelected( int ) ) ); QListWidgetItem *initItem = mBaseWidget->mCycleListBox->findItems( initType, Qt::MatchExactly ).first(); if ( initItem ) { mBaseWidget->mCycleListBox->setCurrentItem( initItem, QItemSelectionModel::Select ); } QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); _okButton = buttonBox->button(QDialogButtonBox::Ok); _okButton->setDefault(true); _okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); layout->addWidget(buttonBox); slotUpdateExample(); connect( mBaseWidget->mIdTemplEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotTemplTextChanged( const QString& ) ) ); connect( mBaseWidget->mCounterEdit, SIGNAL( valueChanged( int ) ), SLOT( slotUpdateExample() ) ); } void NumberCycleDialog::loadCycles() { QSqlQuery q( "SELECT id, name, lastIdentNumber, identTemplate FROM numberCycles ORDER BY name" ); mBaseWidget->mCycleListBox->clear(); while ( q.next() ) { dbID id( q.value( 0 ).toInt() ); NumberCycle nc( id ); nc.setName( q.value( 1 ).toString() ); nc.setCounter( q.value( 2 ).toInt() ); nc.setTemplate( q.value( 3 ).toString() ); mNumberCycles[nc.name()] = nc; mBaseWidget->mCycleListBox->addItem( nc.name() ); } } void NumberCycleDialog::slotUpdateExample() { DocType dt; dt.setName( i18n( "Doc-Type" ) ); int id = mBaseWidget->mCounterEdit->value(); const QString tmpl = mBaseWidget->mIdTemplEdit->text(); dt.setIdentTemplate( tmpl ); QString idText = dt.generateDocumentIdent( QDate::currentDate(), QLatin1String(""), id, 2 ); // generateDocumentIdent automatically adds a %i to the pattern, if it has neither // %i nor %n. A note is added here to the dialog text if ( !(tmpl.contains("%i") || tmpl.contains("%n"))) { idText.append(" "); idText.append(i18nc("do not translate %i, it is a template variable.", "(%i added)")); } mBaseWidget->mExampleId->setText( idText ); } void NumberCycleDialog::slotTemplTextChanged( const QString& str ) { bool state = false; if ( !str.isEmpty() && (str.contains( "%i" ) || str.contains("%n") )) { state = true; } if( _okButton ) { _okButton->setEnabled( state ); } slotUpdateExample(); } void NumberCycleDialog::updateCycleDataFromGUI() { // Store the updated values if ( !mSelectedCycle.isEmpty() ) { // qDebug () << "Updating the cycle: " << mSelectedCycle; if ( mNumberCycles.contains( mSelectedCycle ) ) { QString h = mBaseWidget->mIdTemplEdit->text(); mNumberCycles[mSelectedCycle].setTemplate( h ); // qDebug () << "Number Cycle Template: " << h; int num = mBaseWidget->mCounterEdit->value(); // qDebug () << "Number Edit: " << num; mNumberCycles[mSelectedCycle].setCounter( num ); } else { // qDebug () << "WRN: NumberCycle " << mSelectedCycle << " is not known"; } } else { // qDebug () << "The selected cycle name is Empty!"; } } void NumberCycleDialog::slotNumberCycleSelected( int num ) { updateCycleDataFromGUI(); // set the new data of the selected cycle QString name = mBaseWidget->mCycleListBox->item( num )->text(); if ( ! mNumberCycles.contains( name ) ) { // qDebug () << "No numbercycle found at pos " << num; } NumberCycle nc = mNumberCycles[name]; // qDebug () << "Selected number cycle number " << num; mBaseWidget->mIdTemplEdit->setText( nc.getTemplate() ); mBaseWidget->mCounterEdit->setMinimum( 0 ); // nc.counter() ); mBaseWidget->mCounterEdit->setValue( nc.counter() ); mBaseWidget->mNameEdit->setText( nc.name() ); mBaseWidget->mNameEdit->setReadOnly( true ); // remember the cycle name mSelectedCycle = name; bool state = true; if ( name == NumberCycle::defaultName() ) { state = false; } mBaseWidget->mPbRemove->setEnabled( state ); } void NumberCycleDialog::slotAddCycle() { QString newName = QInputDialog::getText( this, i18n( "Add Number Cycle" ), i18n( "Enter the name of a new number cycle." ) ); if ( newName.isEmpty() ) return; bool uniq = true; if ( mNumberCycles.contains( newName ) ) { uniq = false; } if ( uniq ) { NumberCycle numCycle; numCycle.setName( newName ); numCycle.setTemplate( QString::fromLatin1( "%y%w-%i" ) ); QSqlQuery q( "SELECT 1+MAX(lastIdentNumber) FROM numberCycles" ); if ( q.next() ) { numCycle.setCounter( q.value( 0 ).toInt() ); } mNumberCycles[newName] = numCycle; mBaseWidget->mCycleListBox->addItem( numCycle.name() ); } else { // qDebug () << "The name is not unique!"; } QListWidgetItem *item = mBaseWidget->mCycleListBox->findItems( newName, Qt::MatchExactly ).first(); if ( item ) { mBaseWidget->mCycleListBox->setCurrentItem( item ); } } void NumberCycleDialog::slotRemoveCycle() { QString entry = mBaseWidget->mCycleListBox->currentItem()->text(); QListWidgetItem *item = mBaseWidget->mCycleListBox->currentItem(); if ( entry.isEmpty() || !item ) return; mRemovedCycles << entry; if ( item ) { mNumberCycles.remove( entry ); delete item; } } bool NumberCycleDialog::dropOfNumberCycleOk( const QString& name ) { QSqlQuery q; q.prepare( "SELECT count(att.id) FROM attributes att, attributeValues attVal WHERE att.id=attVal.attributeId AND att.hostObject=:dtype AND att.name=:attName AND attVal.value=:val" ); q.bindValue( ":dtype", "DocType" ); q.bindValue( ":attName", "identNumberCycle" ); q.bindValue( ":val", name ); q.exec(); if ( q.next() ) { int cnt = q.value( 0 ).toInt(); if ( cnt > 0 ) { QMessageBox msgBox; msgBox.setText(i18n( "The numbercycle %1 is still assigned to a document type.")); msgBox.setInformativeText(i18n("The number cycle can not be deleted as long as it " "is assigned to a document type." ).arg( name )); msgBox.setStandardButtons(QMessageBox::Ok); } return cnt == 0; } return true; } void NumberCycleDialog::accept() { // qDebug () << "Slot Ok hit"; // get the changed stuff from the gui elements updateCycleDataFromGUI(); // First remove the dropped cycles if ( mRemovedCycles.count() > 0 ) { QSqlQuery qDel; qDel.prepare( "DELETE FROM numberCycles WHERE name=:name" ); for ( QStringList::Iterator it = mRemovedCycles.begin(); it != mRemovedCycles.end(); ++it ) { // qDebug () << "about to drop the number cycle " << *it; if ( dropOfNumberCycleOk( *it ) ) { qDel.bindValue( ":name", *it ); qDel.exec(); } } } // update existing entries and insert new ones // CREATE TABLE numberCycles ( // id INTEGER PRIMARY KEY ASC autoincrement, // name VARCHAR(64) NOT NULL, // lastIdentNumber INT NOT NULL, // identTemplate VARCHAR(64) NOT NULL // ); QSqlQuery q; q.prepare( "SELECT id, name, lastIdentNumber, identTemplate FROM numberCycles WHERE name=:name" ); QMap::Iterator it; for ( it = mNumberCycles.begin(); it != mNumberCycles.end(); ++it ) { QString cycleName = it.key(); NumberCycle cycle = it.value(); q.bindValue( ":name", cycleName ); // name changes can not happen by design q.exec(); if ( q.next() ) { // qDebug () << "Checking existing number cycle " << cycleName << " for update"; // there is an entry if ( q.value( 2 ).toInt() != cycle.counter() ) { bool doUpdate = true; if ( q.value( 2 ).toInt() > cycle.counter() ) { if ( q.value( 3 ).toString() == cycle.getTemplate() ) { // The number has become smaller but the template remains the same. // That has high potential to end up with duplicate doc numbers. QMessageBox msgBox; msgBox.setWindowTitle(i18n("Dangerous Counter Change")); msgBox.setText(i18n("The new counter is lower than the old one. " )); msgBox.setInformativeText(i18n("That has potential to create duplicate document numbers. Do you really want to decrease it?" )); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton( QMessageBox::Yes ); int re = msgBox.exec(); if( re != QMessageBox::Yes ) { doUpdate = false; } } } if ( doUpdate ) { updateField( q.value( 0 ).toInt(), "lastIdentNumber", QString::number( cycle.counter() ) ); } } if ( q.value( 3 ).toString() != cycle.getTemplate() ) { updateField( q.value( 0 ).toInt(), "identTemplate", cycle.getTemplate() ); } } else { // qDebug () << "This number cycle is new: " << cycleName; QSqlQuery qIns; qIns.prepare( "INSERT INTO numberCycles (name, lastIdentNumber, identTemplate) " "VALUES (:name, :number, :templ)" ); qIns.bindValue( ":name", cycleName ); qIns.bindValue( ":number", cycle.counter() ); qIns.bindValue( ":templ", cycle.getTemplate() ); qIns.exec(); } } QDialog::accept(); } void NumberCycleDialog::updateField( int id, const QString& field, const QString& value ) { QSqlQuery qUpdate; QString sql = "UPDATE numberCycles SET " + field + "=:value WHERE id=:id"; qUpdate.prepare( sql ); // qUpdate.bindValue( ":field", field ); qUpdate.bindValue( ":value", value ); qUpdate.bindValue( ":id", id ); qUpdate.exec(); } kraft-1.1/src/numbercycledialog.h000066400000000000000000000041141450127457600171250ustar00rootroot00000000000000/*************************************************************************** numbercycledialog.h - edit number cycles ------------------- begin : Jan 15 2009 copyright : (C) 2009 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef NUMBERCYCLEDIALOG_H #define NUMBERCYCLEDIALOG_H #include #include #include #include "dbids.h" #include "numbercycle.h" #include "ui_numbercycleseditbase.h" class QLineEdit; class QLabel; class QPushButton; class QComboBox; class QCheckBox; /** * @author Klaas Freitag */ // ################################################################################ class NumberCycleDialog: public QDialog { Q_OBJECT public: NumberCycleDialog( QWidget *parent, const QString& initType = QString() ); public slots: protected slots: void slotAddCycle(); void slotRemoveCycle(); void slotNumberCycleSelected( int ); void slotTemplTextChanged( const QString& ); void accept(); void slotUpdateExample(); private: void updateField( int, const QString&, const QString& ); void loadCycles(); void updateCycleDataFromGUI(); bool dropOfNumberCycleOk( const QString& ); Ui::NumberCycleEditBase *mBaseWidget; QStringList mRemovedCycles; QMap mNumberCycles; QString mSelectedCycle; QPushButton *_okButton; }; #endif kraft-1.1/src/numbercycleseditbase.ui000066400000000000000000000126351450127457600200260ustar00rootroot00000000000000 NumberCycleEditBase 0 0 503 279 <h3>Edit Number Cycles</h3> false Number Cycle Details &Number Cycle: false mNameEdit &Counter: false mCounterEdit false Example Id: false ident &Template: false mIdTemplEdit false false example false &Select a number cycle and edit the details on the right: Qt::AlignVCenter true mCycleListBox New Item Qt::Horizontal QSizePolicy::Expanding 37 20 Click to add a new document type to the list. add click to remove the current document type remove kraft-1.1/src/pdfconverter.cpp000066400000000000000000000167161450127457600165040ustar00rootroot00000000000000/*************************************************************************** pdfconverter.cpp - convert documents to pdf ------------------- begin : March 2020 copyright : (C) 2020 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "pdfconverter.h" #include "defaultprovider.h" #include #include #include #include #include #include #include void PDFConverter::slotReceivedStderr( ) { QByteArray arr = mProcess->readAllStandardError(); mErrors.append( arr ); } // ==================================================================== ReportLabPDFConverter::ReportLabPDFConverter() :PDFConverter() { } void ReportLabPDFConverter::convert(const QString& sourceFile, const QString &outputFile) { // qDebug() << "Report BASE:\n" << templ; if ( sourceFile.isEmpty() ) { return; } // findTrml2Pdf returns a list of command line parts for the converter, such as // /usr/bin/pyhton3 /usr/local/share/erml2pdf.py QStringList rmlbin = DefaultProvider::self()->locatePythonTool("erml2pdf.py"); if ( ! rmlbin.size() ) { emit converterError(ConvError::TrmlToolFail); } QApplication::setOverrideCursor( QCursor( Qt::BusyCursor ) ); QStringList args; QString prg = rmlbin.at(0); if( rmlbin.size() > 1 ) { // something like "python3 erml2pdf.py args.append(rmlbin.at(1)); } args.append(sourceFile); mFile.setFileName(outputFile); mOutputSize = 0; if ( mFile.open( QIODevice::WriteOnly ) ) { qDebug() << "Converting " << mFile.fileName() << "using" << prg << args.join(QChar(' ')); mProcess = new QProcess(); connect(mProcess, &QProcess::readyReadStandardOutput, this, &ReportLabPDFConverter::slotReceivedStdout); connect(mProcess, &QProcess::readyReadStandardError, this, &ReportLabPDFConverter::slotReceivedStderr); connect(mProcess, QOverload::of(&QProcess::finished), this, &ReportLabPDFConverter::trml2pdfFinished); mProcess->setProgram( prg ); mProcess->setArguments(args); mTargetStream.setDevice( &mFile ); mProcess->start( ); if (!mProcess->waitForStarted(1000)) { emit converterError(ConvError::TrmlToolFail); } } } void ReportLabPDFConverter::slotReceivedStdout( ) { QByteArray arr = mProcess->readAllStandardOutput(); mOutputSize += arr.size(); mTargetStream.writeRawData( arr.data(), arr.size()); } void ReportLabPDFConverter::trml2pdfFinished( int exitCode, QProcess::ExitStatus stat) { if( mFile.isOpen() ) { mFile.close(); } Q_UNUSED(stat) QApplication::restoreOverrideCursor(); // qDebug () << "PDF Creation Process finished with status " << exitStatus; // qDebug () << "Wrote bytes to the output file: " << mOutputSize; if ( exitCode == 0 ) { QFileInfo fi(mFile.fileName()); if( fi.exists() ) { emit docAvailable( mFile.fileName() ); if( mProcess) { const QString rmlFile = mProcess->arguments().last(); // the file name of the temp rmlfile QFile::remove(rmlFile); // remove the rmlFile } } else { emit converterError(ConvError::TargetFileMissing); } } else { if( mErrors.contains(QLatin1String("No module named 'reportlab"))) { emit converterError(ConvError::NoReportLabMod); } else if (mErrors.contains("No module named 'PyPDF2")){ emit converterError(ConvError::NoPyPDFMod); } else { qDebug() << "Trml2Pdf Error:" << mErrors; emit converterError(ConvError::UnknownError); } } mProcess->deleteLater(); mProcess = nullptr; mFile.setFileName( QString() ); } // ==================================================================== WeasyPrintPDFConverter::WeasyPrintPDFConverter() :PDFConverter() { // Version string of version 55: WeasyPrint version 55.0 // WeasyPrint version 56.1 } void WeasyPrintPDFConverter::convert(const QString& sourceFile, const QString& outputFile) { mErrors.clear(); const QString prg = DefaultProvider::self()->locateBinary("weasyprint"); const QString styleSheet = DefaultProvider::self()->locateFile("reports/kraft.css"); QFileInfo prgInfo(prg); if ( ! prgInfo.exists() || ! prgInfo.isExecutable() ) { emit converterError(ConvError::WeasyPrintNotFound); return; } mFile.setFileName(outputFile); QApplication::setOverrideCursor( QCursor( Qt::BusyCursor ) ); mProcess = new QProcess; connect(mProcess, &QProcess::readyReadStandardOutput, this, &WeasyPrintPDFConverter::slotReceivedStdout); connect(mProcess, &QProcess::readyReadStandardError, this, &WeasyPrintPDFConverter::slotReceivedStderr); connect(mProcess, QOverload::of(&QProcess::finished), this, &WeasyPrintPDFConverter::weasyPrintFinished); QStringList args; QFileInfo styleFI(styleSheet); const QString styleSheetDir = styleFI.canonicalPath(); args << "-p"; args << "-u"; args << styleSheetDir; if (!_templatePath.isEmpty() && _templatePath != styleSheetDir) { args << "-u"; args << _templatePath; } args << sourceFile; args << mFile.fileName(); qDebug() << "Calling converter:" << prg << args; mProcess->setProgram( prg ); mProcess->setArguments(args); mOutput.clear(); mProcess->start( ); } void WeasyPrintPDFConverter::slotReceivedStdout( ) { QByteArray arr = mProcess->readAllStandardOutput(); mOutput.append(arr); } void WeasyPrintPDFConverter::weasyPrintFinished( int exitCode, QProcess::ExitStatus stat) { if( mFile.isOpen() ) { mFile.close(); } Q_UNUSED(stat) QApplication::restoreOverrideCursor(); // qDebug () << "PDF Creation Process finished with status " << exitStatus; // qDebug () << "Wrote bytes to the output file: " << mOutputSize; if ( exitCode == 0 ) { QFileInfo fi(mFile.fileName()); if( fi.exists() ) { emit docAvailable( mFile.fileName() ); if(mProcess) { const QString htmlFile = mProcess->arguments().first(); // the file name of the temp rmlfile QFile::remove(htmlFile); // remove the rmlFile } } else { emit converterError(ConvError::TargetFileMissing); } } else { qDebug() << "Weasyprint failed: " << mProcess->arguments(); emit converterError(ConvError::UnknownError); } mProcess->deleteLater(); mProcess = nullptr; mFile.setFileName( QString() ); } kraft-1.1/src/pdfconverter.h000066400000000000000000000061611450127457600161420ustar00rootroot00000000000000/*************************************************************************** pdfconverter.cpp - convert documents to pdf ------------------- begin : March 2020 copyright : (C) 2020 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef PDFCONVERTER_H #define PDFCONVERTER_H #include #include #include #include #include class PDFConverter : public QObject { Q_OBJECT public: PDFConverter() {} enum class ConvError { NoError, SourceFileFail, TrmlToolFail, TargetFileError, NoReportLabMod, NoPyPDFMod, TargetFileMissing, UnknownError, WeasyPrintNotFound, PDFMergerError }; virtual void convert(const QString& sourceFile, const QString& outputFile) = 0; QString getErrors() { return mErrors; } /* * Sets the path of the template which can be used as base path to find * stylesheets and images and such. */ void setTemplatePath(const QString& path) { _templatePath = path; } signals: void docAvailable(const QString& fileName); void converterError( ConvError ); protected slots: void slotReceivedStderr(); protected: QString mErrors; QProcess *mProcess; QFile mFile; QString _templatePath; }; // ==================================================================== class ReportLabPDFConverter: public PDFConverter { Q_OBJECT public: ReportLabPDFConverter(); void convert(const QString& sourceFile, const QString& outputFile) override; private slots: void trml2pdfFinished( int exitCode, QProcess::ExitStatus stat); void slotReceivedStdout(); private: QFile mFile; QDataStream mTargetStream; int mOutputSize; }; // ==================================================================== class WeasyPrintPDFConverter : public PDFConverter { Q_OBJECT public: WeasyPrintPDFConverter(); void convert(const QString& sourceFile, const QString& outputFile) override; private slots: void slotReceivedStdout(); void weasyPrintFinished(int exitCode, QProcess::ExitStatus stat); private: QByteArray mOutput; }; #endif // PDFCONVERTER_H kraft-1.1/src/pics/000077500000000000000000000000001450127457600142225ustar00rootroot00000000000000kraft-1.1/src/pics/CMakeLists.txt000066400000000000000000000003111450127457600167550ustar00rootroot00000000000000 ########### install files ############### install(FILES kraftapp_logo.png DESTINATION ${DATA_INSTALL_DIR}/kraft/pics) ecm_install_icons( ICONS sc-apps-kraft.svg DESTINATION ${KDE_INSTALL_ICONDIR}) kraft-1.1/src/pics/Calendar_page.png000066400000000000000000000051161450127457600174400ustar00rootroot00000000000000PNG  IHDR|/YbKGD pHYs B(xtIME &8J5 IDATxil\;2 ;P4vҬ%$JReQ"Q[Z?B !PC)*QQR(MR'Gib; Όcgc$KHw|sB!B!B!"-0ee:\Y_}GKz{ {+ɓ' Z88YNek|{a=c:6nLvuuUo/?ld>^42ۮau`]3{]2$մ6'W$;4=Jh@L[k!61,XSn]V"9:TGi!n7zNjŲ Ԏ ̬p6#Ѳ0BiRgXf;V(!͙eN AQ &tuڊ._)N-Ә,6kJwŻha+I5 eN7gkIKp!B… .$\Hp1nS0`j<l\oFɒo]JJ GȈ>_qґ6)v9x }3J3r#_\ _2԰im4 0CCc*!+˺ քaM9sQwM&/$ k\aJHsvv{Np\9篜!' _n[O~]S-<;71:,rۇcK\+N3NBX '`\27WFi$rJwbۇ&,0μ‡W g@c/<OX)Vu,xoyc-&5hm3(K`\e# ]+%w@AI}~STuu,&DL c,e>Nr__:MH\v gpF̝KQ&x[Ȝ@7@A+ _❏TVP9%'Z!v3ps(DS ӧIVv6PJd^^:Orr9IF,FM_I:3!7wo>u| e$Y\CME_vXy颭\d7ɉ3 >F~5t RPx:u o)K3`syPT^R;2aMH]!o/lpíUR6w$)N­zБ."-pC.=v6DT)x a4pUxpUi$ܦ O) עMh&RlJWkJ-Ӕ^mѦm" ׶Lrv>P6Aot܋ .$\Hp!B… .$\Hp .$\Hp!B… .$\Hp W $\Hp!B… .$\Hp!B%\Hp!B… .$\Hp!B…Kp!B… .$\Hp!si* eYmhhhPH-G,R6ҀH$ kooW6Ҁ`0c bJGjF[gg?y3JIjkmm}:fΝH$ܬ(Pf j|o޼3&5yz[ZZ^'m'ݭX[] Z[n̞=#G,AfDʕ+}V aÆnK=ZWW}e˖>7.mp8|2MsҥKi7=zџ}ٳmmm3N͋-P ՉZ]]ݻ>x/=z^:0 e3yW6mz=wU~5TTTܽv㝝Z%)pzO͚5gS5x*?|饗zLT۷,Xp0??vʧ-^m۶i8LӴvYjՑ'ǻy0=V[[{݊+YYZ_K(04662IQXZZ.[_TTz2 CoNp8 Ѿ`WWWkǩSNODlAIENDB`kraft-1.1/src/pics/README.icons000066400000000000000000000001211450127457600162060ustar00rootroot00000000000000Tabler icons MIT licensed icons from https://iconify.design/icon-sets/tabler/ kraft-1.1/src/pics/custom-icons/000077500000000000000000000000001450127457600166455ustar00rootroot00000000000000kraft-1.1/src/pics/custom-icons/archive.svg000066400000000000000000000006741450127457600210160ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/arrow-bar-to-left.svg000066400000000000000000000003541450127457600226340ustar00rootroot00000000000000kraft-1.1/src/pics/custom-icons/arrow-down.svg000066400000000000000000000006441450127457600214710ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/arrow-move-right.svg000066400000000000000000000006251450127457600226020ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/arrow-narrow-left.svg000066400000000000000000000006471450127457600227650ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/arrow-ramp-right.svg000066400000000000000000000007021450127457600225670ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/arrow-up.svg000066400000000000000000000006401450127457600211420ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/arrows-up-down.svg000066400000000000000000000006741450127457600223010ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/atom.svg000066400000000000000000000010721450127457600203260ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/book.svg000066400000000000000000000007741450127457600203300ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/calculator.svg000066400000000000000000000012351450127457600215200ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/cash-banknote.svg000066400000000000000000000007321450127457600221050ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/check.svg000066400000000000000000000005001450127457600204360ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/circle-0.svg000066400000000000000000000005771450127457600207750ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/circle-half-2.svg000066400000000000000000000006731450127457600217040ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/coin.svg000066400000000000000000000006711450127457600203220ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/copy.svg000066400000000000000000000006401450127457600203400ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/cut.svg000066400000000000000000000007011450127457600201570ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/device-floppy.svg000066400000000000000000000007111450127457600221330ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/dice.svg000066400000000000000000000011001450127457600202620ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/edit.svg000066400000000000000000000007301450127457600203130ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/extract.pl000077500000000000000000000011531450127457600206570ustar00rootroot00000000000000#!/usr/bin/perl use strict; use warnings; use LWP::Simple; # extract icons foreach my $line ( ) { chomp( $line ); # ![arrow-down](https://tabler-icons.io/static/tabler-icons/icons/arrow-down.svg) arrow-down| Down | prefswages.cpp | if ( $line =~ /\((.*)\)/ ) { my $url = $1; my @parts = split('/', $url); my $file = $parts[-1]; if ( $file =~ /.svg$/ ) { # print "$file -> $url\n"; print "custom-icons/$file\n"; } } # to download all files, remove comment from next line: # getstore($url, $file); } kraft-1.1/src/pics/custom-icons/eye.svg000066400000000000000000000006551450127457600201560ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/file-chart.svg000066400000000000000000000007371450127457600214130ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/file-description.svg000066400000000000000000000007261450127457600226330ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/file-export.svg000066400000000000000000000006531450127457600216300ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/file-plus.svg000066400000000000000000000007661450127457600212770ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/file-x.svg000066400000000000000000000007021450127457600205510ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/files.svg000066400000000000000000000007521450127457600204740ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/flag.svg000066400000000000000000000007221450127457600203000ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/help.svg000066400000000000000000000006611450127457600203210ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/id-badge-2.svg000066400000000000000000000010071450127457600211570ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/kraft-simple.svg000066400000000000000000005246021450127457600217750ustar00rootroot00000000000000 image/svg+xml kraft-1.1/src/pics/custom-icons/language.svg000066400000000000000000000007231450127457600211530ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/list.md000066400000000000000000000137531450127457600201530ustar00rootroot00000000000000| ![plus](https://tabler-icons.io/static/tabler-icons/icons/plus.svg) plus | Add | prefsdialog.cpp, prefsunits.cpp, prefswages.cpp | | ![arrow-down](https://tabler-icons.io/static/tabler-icons/icons/arrow-down.svg) arrow-down| Down | prefswages.cpp | | ![pencil](https://tabler-icons.io/static/tabler-icons/icons/pencil.svg) pencil| Edit | prefsunits.cpp, prefswages.cpp | | ![X](https://tabler-icons.io/static/tabler-icons/icons/x.svg) X| Remove | prefsdialog.cpp, prefsunits.cpp, prefswages.cpp | | ![receipt-tax](https://tabler-icons.io/static/tabler-icons/icons/receipt-tax.svg) receipt-tax| Taxes | prefsdialog.cpp | | ![atom](https://tabler-icons.io/static/tabler-icons/icons/atom.svg) atom| Units | prefsdialog.cpp | | ![arrow-up](https://tabler-icons.io/static/tabler-icons/icons/arrow-up.svg) arrow-up| Up | prefswages.cpp | | ![cash-banknote](https://tabler-icons.io/static/tabler-icons/icons/cash-banknote.svg) cash-banknote | Wages | prefsdialog.cpp | | ![calculator](https://tabler-icons.io/static/tabler-icons/icons/calculator.svg) calculator | accessories-calculator | templkataloglistview.cpp | | ![logout](https://tabler-icons.io/static/tabler-icons/icons/logout.svg) logout | application-exit | portal.cpp | | ![arrow-down](https://tabler-icons.io/static/tabler-icons/icons/arrow-down.svg) arrow-down| arrow-down | positionviewwidget.cpp | | ![arrow-up](https://tabler-icons.io/static/tabler-icons/icons/arrow-up.svg) arrow-up| arrow-up | positionviewwidget.cpp | | ![check](https://tabler-icons.io/static/tabler-icons/icons/check.svg) check | checkmark | prefsdialog.cpp | | ![arrows-up-down](https://tabler-icons.io/static/tabler-icons/icons/arrows-up-down.svg) arrows-up-down| configure | positionviewwidget.cpp | | ![file-x](https://tabler-icons.io/static/tabler-icons/icons/file-x.svg) file-x| document-delete | katalogview.cpp | | ![edit](https://tabler-icons.io/static/tabler-icons/icons/edit.svg) edit| document-edit | doctypeedit.cpp, flostempldialog.cpp, katalogview.cpp, portal.cpp | | ![file-export](https://tabler-icons.io/static/tabler-icons/icons/file-export.svg) file-export| document-export | portal.cpp | | ![file-plus](https://tabler-icons.io/static/tabler-icons/icons/file-plus.svg) file-plus| document-new | docassistant.cpp, katalogview.cpp, portal.cpp | | ![template](https://tabler-icons.io/static/tabler-icons/icons/template.svg) template| document-new-from-template | portal.cpp | | ![eye](https://tabler-icons.io/static/tabler-icons/icons/eye.svg) eye| document-preview | portal.cpp | | ![printer](https://tabler-icons.io/static/tabler-icons/icons/printer.svg) printer| document-print | portal.cpp | | ![edit](https://tabler-icons.io/static/tabler-icons/icons/edit.svg) edit| document-properties | docassistant.cpp | | ![copy](https://tabler-icons.io/static/tabler-icons/icons/copy.svg) copy | edit-copy | portal.cpp, prefsdialog.cpp | | ![cut](https://tabler-icons.io/static/tabler-icons/icons/cut.svg) cut| edit-cut | portal.cpp | | ![minus](https://tabler-icons.io/static/tabler-icons/icons/minus.svg)| edit-delete | docassistant.cpp, positionviewwidget.cpp | | ![transfer-in](https://tabler-icons.io/static/tabler-icons/icons/transfer-in.svg)transfer-in| edit-paste | portal.cpp | | use lock| encrypted | positionviewwidget.cpp | | ![archive](https://tabler-icons.io/static/tabler-icons/icons/archive.svg) archive| file-library-symbolic | portal.cpp | | ![file-plus](https://tabler-icons.io/static/tabler-icons/icons/file-plus.svg) file-plus| filenew | positionviewwidget.cpp | | ![flag](https://tabler-icons.io/static/tabler-icons/icons/flag.svg) flag| flag | positionviewwidget.cpp | | ![edit](https://tabler-icons.io/static/tabler-icons/icons/edit.svg) edit| folder-documents | katalogview.cpp, prefsdialog.cpp | | ![arrow-narrow-left](https://tabler-icons.io/static/tabler-icons/icons/arrow-narrow-left.svg) arrow-narrow-left| go-previous | docassistant.cpp, textselection.cpp | | ![help](https://tabler-icons.io/static/tabler-icons/icons/help.svg) help | help-about | portal.cpp | | ![arrow-ramp-right](https://tabler-icons.io/static/tabler-icons/icons/arrow-ramp-right.svg) arrow-ramp-right| kraft_alternative | positionviewwidget.cpp | | ![arrow-move-right](https://tabler-icons.io/static/tabler-icons/icons/arrow-move-right.svg) arrow-move-right| kraft_demand | positionviewwidget.cpp | | ![coin](https://tabler-icons.io/static/tabler-icons/icons/coin.svg) coin| kraft_fulltax | kraftview.cpp, positionviewwidget.cpp | | ![circle-0](https://tabler-icons.io/static/tabler-icons/icons/circle-0.svg) circle-0| kraft_notax | kraftview.cpp, positionviewwidget.cpp | | ![circle-half-2](https://tabler-icons.io/static/tabler-icons/icons/circle-half-2.svg) circle-half-2| kraft_redtax | kraftview.cpp, positionviewwidget.cpp | | ![dice](https://tabler-icons.io/static/tabler-icons/icons/dice.svg) dice | kraftdice | templkataloglistview.cpp | | plus (see add)| list-add | doctypeedit.cpp, flostempldialog.cpp, numbercycledialog.cpp | | minus (see remove)| list-remove | doctypeedit.cpp, flostempldialog.cpp, numbercycledialog.cpp | | ![mail-forward](https://tabler-icons.io/static/tabler-icons/icons/mail-forward.svg) mail-forward| mail-forward | portal.cpp | | ![lock](https://tabler-icons.io/static/tabler-icons/icons/lock.svg) locked| object-locked | positionviewwidget.cpp | | ![lock-open](https://tabler-icons.io/static/tabler-icons/icons/lock-open.svg) lock-open| object-unlocked | positionviewwidget.cpp | | ![language](https://tabler-icons.io/static/tabler-icons/icons/language.svg) language| preferences-desktop-locale | kraftdocheaderedit.cpp | | ![device-floppy](https://tabler-icons.io/static/tabler-icons/icons/device-floppy.svg) device-floppy| quickopen-file | doctypeedit.cpp, prefsdialog.cpp | | ![minus](https://tabler-icons.io/static/tabler-icons/icons/minus.svg) minus| remove | positionviewwidget.cpp | |![settings](https://tabler-icons.io/static/tabler-icons/icons/settings.svg) settings| settings-configure | portal.cpp | |![user-identiy](https://tabler-icons.io/static/tabler-icons/icons/id-badge-2.svg) id-badge-2 | user-identity | prefsdialog.cpp | kraft-1.1/src/pics/custom-icons/lock-open.svg000066400000000000000000000006431450127457600212600ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/lock.svg000066400000000000000000000006401450127457600203160ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/logout.svg000066400000000000000000000006471450127457600207060ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/mail-forward.svg000066400000000000000000000007141450127457600217540ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/minus.svg000066400000000000000000000005121450127457600205170ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/pencil.svg000066400000000000000000000006261450127457600206440ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/plus.svg000066400000000000000000000005631450127457600203550ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/printer.svg000066400000000000000000000007621450127457600210560ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/receipt-tax.svg000066400000000000000000000010421450127457600216100ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/settings.svg000066400000000000000000000015411450127457600212270ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/template.svg000066400000000000000000000010141450127457600211750ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/tool.svg000066400000000000000000000006021450127457600203410ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/transfer-in.svg000066400000000000000000000006071450127457600216210ustar00rootroot00000000000000 kraft-1.1/src/pics/custom-icons/x.svg000066400000000000000000000005561450127457600176430ustar00rootroot00000000000000 kraft-1.1/src/pics/kraft.qrc000066400000000000000000000046371450127457600160520ustar00rootroot00000000000000 Calendar_page.png postit.png kraft_customer.png custom-icons/plus.svg custom-icons/arrow-down.svg custom-icons/arrow-bar-to-left.svg custom-icons/pencil.svg custom-icons/x.svg custom-icons/receipt-tax.svg custom-icons/atom.svg custom-icons/arrow-up.svg custom-icons/cash-banknote.svg custom-icons/calculator.svg custom-icons/logout.svg custom-icons/arrow-down.svg custom-icons/arrow-up.svg custom-icons/check.svg custom-icons/arrows-up-down.svg custom-icons/file-x.svg custom-icons/edit.svg custom-icons/file-export.svg custom-icons/file-plus.svg custom-icons/template.svg custom-icons/eye.svg custom-icons/printer.svg custom-icons/edit.svg custom-icons/copy.svg custom-icons/cut.svg custom-icons/minus.svg custom-icons/transfer-in.svg custom-icons/archive.svg custom-icons/file-plus.svg custom-icons/flag.svg custom-icons/edit.svg custom-icons/arrow-narrow-left.svg custom-icons/help.svg custom-icons/arrow-ramp-right.svg custom-icons/arrow-move-right.svg custom-icons/coin.svg custom-icons/circle-0.svg custom-icons/circle-half-2.svg custom-icons/dice.svg custom-icons/mail-forward.svg custom-icons/lock.svg custom-icons/lock-open.svg custom-icons/language.svg custom-icons/device-floppy.svg custom-icons/minus.svg custom-icons/settings.svg custom-icons/id-badge-2.svg custom-icons/book.svg custom-icons/files.svg custom-icons/kraft-simple.svg custom-icons/file-description.svg custom-icons/file-chart.svg custom-icons/tool.svg kraft-1.1/src/pics/kraft_customer.png000066400000000000000000000114401450127457600177600ustar00rootroot00000000000000PNG  IHDR00WtEXtSoftwareAdobe ImageReadyqe<IDATxZi]Y~wx;;N8iRph46 TЖPAS "AT@-E~T]( ޔiK8x6sG 1f sMpw<ව ꋏc~]` ю8QSuyh=R[=3`;6LY< W3 }<<_4d, ~?e^!]hi;2Fɑ4Lv729/֔,{a<'{;l+dz}:sdǂ0XVV+ô_mdO XӴˤ]-)3U`Q?+eOM^4%@7ip9<ݹGN{_ ĽKjٖ-"K;ô]:!ycFXyGEᑇnŁr o=VTݿ^z= ɛb$ftc?:d7l?sMC?KLDy׆\HBE(v:]ty;?{|6[q YSs]سK.Y• j6i92ꦇ=b lu+*dLF-TDwA:9TVѢ#ׁ{M bdD8_ysWuA\^lm9T6T6^=҉/:4OV{Ư i Aԏ&2@u XFͶD9 sþad6q~zuJIE# dFرs|R Kg:_AU& l07%Kz}|\]vhP0 oFʏ"td_;KK l7>V*-,5 窛ݡ8Jwt ˎ򐉁9Cm:)^zfBρ/kvM`6,ǁC5<ze(+ aY$2ܨ t]3:EL2K}epw+z>1NAo9t V]?ҷ/4;v abba26p@ NEq8y-7XD1Z (3AR ڍv>|^$F$6L]3{ʥ܁ geF th"y!f*X}w '=YXvqۑ]8zx'cn`!ɖn (-~$>U7K*hWMJmt5 e rb)9X 'jBR*#v,^qxiEJؐfK8VEx,J l.r Ik$mIB֙UmCϹkdߊ$8 y4  :B ZBu ( NT7XW]U 0`|8b0 U3f4 J[v|C{K)0(ӑ׽M1q1o,/1384sIKx)Y&>9<p| ftזt |Hō(1.,n/ [~tjT^^ax8԰uOWuF'عmxj~gq2;i:mvhA&>c<с\.3e0dK5 WdND,k}F?YF[N%CFet#)5|?jy5U 3K8 4:8h1CN_Bg=U<9d{x<5F,t{L6sbe"u`3ņsnFWc"vSp9#) n–ϠRbtg|Wkx1ߦ,a{"e%ք\L=V*f9Q9hӡ@#e gbqE|6-ߏ*f)|I+'!f$Rwގѹ#_{fm]3BkVkr54dRgFulx!x<[^_|_Bg #Mv-d9 RpJ4 =q\=C]{|-1G cR0Xkx2W~X Y\xMЉ<(a,[}oib03zTC”c2"wrɏ@E+D(g#2?s;8kP퀑v8#C>!Cٗ x A~/$9fh}YKae*2c *i! ~< \3~K}yTIĖ7?73ͫ/)l qLOa3į+QŽq%(Ρ,Xܨh$Xo'oY:y`M7+w,Nݍ0nB7Iﻟ`xI5'$^{9ŻIB/TqH&MsIL|s0 34ʵDqWQaYCXrz_1>gkfQL$0_G'7XFpMXWq.t}{OlYC1ìW;ǵlN89JaR* &GʸkrÅTrTƔSrHt,,.+Qcj$*a/=S.h=p>8)n,CF ohቸĕ_۞$ ö09>ZRer$\2+MsjVP6Ռ"QGQB |ȽX;x/^\_?}_C @/lp\/:fH9Rh4=>Dof⻭\QJ>5YYp]qF1iI Ѧ9 LyeҒ I$~Ze<<6!$NHH7T$F"L% <`&'$S7r-5ic;K"QP+xK[mjI$,xRݓj2x D}A&b]b qh<hG A3DyME?z],bHL !wv$-(Lx=Q-aj֦:{Gл6>RCD9q3fRž4yD Wg{&۝q$5~7WE^V7HG_Qճ-beOo,t,JZKk-it=xtSuA4g c {O_Z+FD;ݒ+YMo]][mf;.SE|@E[2HhEH"wVd$ GIK1իu]{ĺT&x#Qa-U/peYyB^ȴ;pzSW>0D`;@0cYdSR#&ힰMJ->SoE| 0ۉ%mϏ~/G|2S7L-+EO32ENm2$-HcV%V4A8J]Cz?s?|pZ3:arxI/$p#K P·3 F8`&-!eDUE%tk><}/3o` V7nIENDB`kraft-1.1/src/pics/kraftapp_logo.png000066400000000000000000000062041450127457600175620ustar00rootroot00000000000000PNG  IHDR@@iqsRGBbKGD pHYs  tIME^H?tEXtCommentCreated with GIMPW IDATxkpuww |ShZX(Hd\MH6VWL>H'mY~LM'i&Nfq?$r+GIc%N슖&)E@I{o>HHb]Clr`yPqOJ9|M5Kh[;ZVr=P[W77R&&xz˗bסEiDb<l@<g@ >W(\J$C5lyr+^16=ѦS4>R}Cog^dڵ77 e&V5t|oU`ddN s^?:a}'GċPr9}H)o>xNNb&uTL;s؝_H*d&p@:n &I~ =84c Mry&3'lwWU(< Hǁ2+@~7dFl}76oE }6O4pEo!xEui-۶{}!c9ܳr R(nS{o%\G/( lJ}} q߶󶓡c%hqiB'Xĺu|rNP^^N(9x9۲ _NJN~r?ՑBm-[f鲥({~IS+¬ctttqv8~SW%oҵ4fymΝ=GyE_qֶSYYoAeDЃ򋟒,r%E_W4~?b}!;h Ho>;!>vno9S_rPB(Er|mo*(Z!/\=d D+[Zu#_~s^hR +c01m `vJ?mp ]{_!ɿ{,]zmo^&Q(4]DZmc9bT4|*- 5՗Lww7={8\䁝s^楃.HGbgljLM!XI\tcG5qe5uFk[[n~kw羚)[4 ߏmYdLgܕҹȂ奎M/J2XS8 pر<,>z8Jxk#lfӖb1zg0:?ৱ7o!HP@DzBJLMʲ.F}Сe˖ " jjjĽ?=X aMsKneuR*$40<$JMrYJ'@@ȥl݃W_0. e)A:B*oV^@扡0ժkaq>+C8qD:uV:mD%Ɉn@*ہ*ځҒR7 g `0Hee(D:ҽLxvM)1SO aRTn\^QN"=t]婒 xɒw'#lF}?s.&^)GV$rr9_So/N^Tmo@09C+p0@'%~q+oO,[`yPB|6SǞxu5WJRU9zJjcZB8[)++ˍ=pL&lG;;m@X: χǀ?0TG"˲XR (˲{׆%qF.^$JJ'p*!%H۶IML*XabXNk޾d"LMM ,]lln"$9ũHH? TUWں:oں:}N06y`y>G˔IENDB`kraft-1.1/src/pics/postit.png000066400000000000000000001746521450127457600162710ustar00rootroot00000000000000PNG  IHDRwzTXtRaw profile type exifxڥk$7r:O3@Y8,$p?}_=\^s7| χ"o%V|/wؾ7F)|nw(޹f\sZ~~d,5GoV;?賱o[MF~~.)kLYF wb o#dLwoKn7?, a _ϿbY?h~[t{w|V7re%p c?t4e헟YHoa b9h|qW׈E+)YFwj~Ļ^Kx~En`߹WKB>=PˈHM-oo`!,o ~~%[:q]'ǂ5PޅɄD| h![L9N"JIƜR%6$v|»6y$%U)5 VXn`hTr)+2jّaZKX5fFK-jZoǞ`IzcpȣwfiYf6s,*.[m5viǻnm=N8@SܩN; n[v?Q/R~Ew> (fD,@MQ1-9HV$bR>!~jq7rNF͝EԶzd'ߟ6Ιwƺ]<~4L?nlOW dD;9sm[(+po W\✽^k_ i'4kjU9r+)1vet[ŵ*߉Jl᱀>uI6W v5ѹC0ۿ@kr$")Ov,FZH˚=rĻ@.rjִ xH^.S 4]|om۝=ȪcX㦱Н_A[ֽ(m_g2qޜU*Iqn n/βv ] Rmtݛ?a1v5S㚿0k5J|,Y iG'Ci@ |-  iV'XjsL$h6k,b$|kc&i6zT$Mnzs"4!zvy<(@4أ2 ;V]Y0Xly)Xx3KA>P&ea!3/ lf{-A>;S ^MlT7֟Ǔ&P$ku|Xz*-[pւ8VG63TW̨e;W{`Wwu@=یLzuU22g`cT 4С T׋r MԈvW:AX5y9Jm}2#ѱEy@F+ Vר-%e˩iHQȠy甎ʽRި2%)sڏ#76GQ-?QXZcF& [G9h5  ua)A7:oy8v2mD>v ʟb v qha&J*a` ۃaVe dZۜ?edaƒJbSw# 5N&BVlٛ?6]*Y+mHbIj-Po ۡ)%Ejl6-BsȌvXҦ\9)+RH6Q^H9TBZ[ JP0vAkb<3) / EұsU GTy"*T6?2]#vd@%r ᅶZ5^ą (6JG ʼ=A_^%vjN juL@a!#y=ɴZKL%RaX#qxH2%]d}E {o(ý*k?5coɞTE> ؙAGi(.T"tN_LD6.'xYp2؄kb'Mìƻ ^Ml.5}gK-Ӻ8  R+B/Qcd~%rE`weEvGX옋z%%:d I 㛑⺈ %x_Bx4sRTvP#)AEzQ@H d8ZSU)S+j6)Q̅;A}¡R3L`=b맬w}Hz"4P1ddjMƅJ[EzDg C9"0p+gq2xxcj na!(#ےJvn;V ?ڔHl T* _""gXԡ'B%8xP(ViH+ad0kPaz`X'Al9P Q"͍3 $P" 8ROwdQ@VȎԇp$5.BI4>@2"}RBmc̽QF>rfrBhf *{PГj&RHadO%~ M$ 858^S)UI yT/G3mL87V׌M, <)J0aH+x}i} lp )tGVPN-˛Uj`qS2TŶ,J`)f|xzFWt)Yi#PU=ETk[$ #aZ':/R6,\ant$EY?8= l2&jp{ n햺9צ.Ύ*cA2#oE!V*~(K-2~CEׁ*Ձ#仡:jtиPLU%ߺvj.M h(5nEC1cLu[y6 ,~SGF FdM4`Fʛ$ ˬQ,p.pa&;]`P{jBZpm)CYE(1ɹ'<0꧲͊:1Zd5*Bd L#N9 &\EDƄif|4jaVaح-mqU ‡ww:;/7Pũ;D)܃xua(NZ 9+i2`&!PPW @&Fы.Ң$"p,듗ڛԳj~#:6$7a隝Eo,?jH@A=(a똅O8lfA\қd7Cc^sRWW>{0$cSAYY?gLNǪRѧ棗|`aк+|YAB.-h1i\tv&:mG<"wEߒwz@Bi po23݊yFwKa E|p̝R=p;E37(eؓ𴴅 dK :( wȀo@.!sw pLoұOc8>%{tG1"PpKk7 VF- cuȣ<jPdO"$Mm2&!RZlTQdWt ^W)IB>U *<@}0hsª Vَ\ʲtN@٭;qPLPdyED(i"8*sوuAV=KU9ԥtQjvz%'PeH:עAlw :ȑԬXa 8Sׄ‚E~w;lܖ,l8 `<')׮D5G2"Hyc7 j!DRI#:}_t[{j<VDL=:Gpnz"JXǹPºfp}pC9~^Uq? %KMcxK3*zʸt{n(dR U^qR>^Ǟr7EߢD`n Ǫ݉mtsuٮ8HYA8rI9mSpԀm PDOb,đCuqt^JO,cK!t$FUp<.*M+c2O?wHz"R,l6AV,u)t)q \Йzv' ]H#8ʥb ׊w,?MXJ \A^I&ZJ4{8._;|6HsQ=)RMz>}[K_* aAOǂH)?BKXo0%VT[0\6l[Mu0P;Z,c0_~ZBg8aA^\m Mpu czԤx$ң088܅([7bl/Nd! PƔE :2}7:n #%u<:nz]ב L+ BQr66w/=6"6Ÿ$5O5)𾂚:" @oQbId+КK'Oc6tACԙBrWL:15v|YbĨf Q3Hyw +OCՊB_DJ밖0j8HlL8<_}^ͦmwݫ^Eg%FMUVcĎcX0XC=KFǘM@1Z1KPS@d{,nL[ЖAz>`@-悉fܞ!ϕ&tPl7@҅ ;F>CwoVK@R Xs~Be7H^ujrzy>:{*Zuu{xȱ-g"{B$)&)jufSHIO:UNY Q'cݺmVԝD\:-BW츍 *1`iPy6$ ﭸT$nTd ĤHM]tyP`(JdI%Eg]#l1EL@n2 ߯4JQHG׹+ѰluW"JG iEVR!mԋ#GCXk#9׉TvF,G.^.z0ϳHr%zf([i Xi@=xʛbYO|N߳@r̦g(H?x;r}}N'9M+i+@/5o3Ȍ43nzStp]3 Fx$v NQ|PvL}[k?17 .y>z"ğ'B NtNԑ=co'Iɀ"U{Uz4Xx[%%8٦fFTNaL٫Cŵ_] 68sӂNӳ\w/^L!!$;:dc$P \> jj,٨tt_捍Ev=Qӈo=^2鑥к\V#ANPS`xĀřq _ ĕw*DXuDPJV*ǜFð؛[zj Xu%W86Qx* w66|YMAJ{StO~8!/Ek%1EI(-x+W=osԎC@1]=J`ꑲWqHa|9g5BVP.Z/*BQfJgiCCPICC profilex}=H@_S* ␡:YMP Vh/hҐ8 ?.κ: "ƃ~{2Ӭ1@m3c,cN_.Ƴ9ԜŀH< & ڴ VUsQ.Hu71өyXhcYԈ'SXY+WYuCH`K BA%a#FN}_"B9Pnĸ/1 t|;N>Wz_ӟZZo-M.w'C6eW y) k^o}>i*y#^yww{oiHr_sbKGD pHYs  tIME ;+ tEXtCommentCreated with GIMPW IDATx]%Wv[kWѷoM45hFZDz1a@@V;8yJd#J?x`'?DrxF 5 )rfvqN+{]lΌ"sԩSZl{=۞m϶g۳l{=۞m϶g۳l{=۞m϶g۳l{=۞m϶g۳l{=۞m϶g۳l7cwQ/k_W^E^x^OWyuI_?-wxw 㾿H_^^}^Ç^/w. /LO_|i}yon͍.Ƚ_n|y`۾ 6(pmpm0^ o߆v{r7/aGG9"px Vpq=w:_b;ȷ'o?p?"2;ֻlWw<>k58>xq͗+ ^{{ا_ ݹܻGux}~"&{~g1Ly Wi^8>F~=k/Ge_ϣ+j!}Rcw}' מo䧁7\Bo>~sK糐mv#;}!vx=L{y .b9pvɊK{7/#p,_ǍQ;)R,^&+.hؕ=d;F9=ؿԒV~嘏+ ia22?VN?mkpxE>n"'.Kqmv>uxw [iۏ{]G؍F̎Az6[)ބ2ͽ/x^}5r.k_Ww13^qO4կb7ncd˖7dX$k_xBlZ7O f~8:7>X~'|]p"12g| gf(I+x+̐<<7G}x|m~zr{ ·ߛ/ޱ[=ӹDp݃}dO<^üW.s-OG_ǮAre9\SO\.rt4 N0@帇G٥޴>Vs>%=^vwyyߏܨء_"@!rr {G;•|s͑ iz3CZMdyDC8ҽ ж.p6 *2WDSWd&6yх^ * B;#HBB#hRT#FH6B@ѐ4A$' !A ̾&&?Y{o{Klo;<_'2Qy N ] =^.T@Ӈ0'kA7!-;ʖ gcyy+rEvΑهq=0 {d(,wk/ .WOgA={w ]{[#]{?spi;"]`ݩٲL~O`}ζf!b'7a9Cmrg+xzz9C?+ B\}ЦGn@XZ aih\m& -BD\U XbI(Y=O(44 !!.VB Y~%#Z5?u}ئD5UH xف>r%_!۶o~nvOOclwv/z#ǕU({$[i9|-z_z+[A+niv춴ݙ fF[ҮlYwfA%X F@"j |&HL; gFЄE HJhHpJ $!BZeK-kTG[+T1!tkJKL12'F?ANjv6d^z݂W%KcSa7hZ}Rk-}L8n"Ӎ?)|!;d'+н]і/ݒX"g]-НeEP\!=r1qAkUo<ky}!Ƶkn۝ʭ[hzPCΐkW}@9CCU9AcUU""mඃ~ܾGAZEdc(Hb- =$$ &ɟ F א? ۰}O"s(W1g̉"kbY^-$E-+q~Q\IĕD,[yLѹdb?+6=Jъu`U`(_[qͺciE)c6$YBQaiDs5#}'7oYYm`рs6zǎ'pm>sgaڟ38;> &cZ ǀ,d܊}! V;_cE/=4ѹ9\6 C5M|("!ҴYD](ٝLh -[Jrܬ1$%̄ !qxz k\ 㡋Uڭ!A1 <7N)y`؟kK?sAz)#w;Yb%HK4AHA$!?%40KVaI=\,P)G +VkbmL@rbQI* EYj8n*$qQ>y% ,y3G}]"=;+|4|׮KDvN jiWY\.6=7n̮oh+2 ZF#2AH(]FS: J-M!d!j ӆ f*"HRU4B(h#H %4A/XU, 0R0 )V#Ը E^酪RW:h}!HTg9k[?9`yx;:&.'o+g(|6tfQĕqQ[P'v^mq'.|OES){'b% c* FE7Cc6R HX.wr~\=w/c7b2`]iJ =\g;!?\G_D>'/('${ aU8 >H |;/^ҋT)hi*;fjHE~]`*N`T@ɉkFc8BCyHfXF3/P |ېZs/2Rm1RlpF7}I!YTrXBJ@yÚIcpOMC?_F Ld1\|w_\޽{p1 oE, #t]jn&x RP^ X4&iD]$=fٺ&$h4@JeFj\I业-d'GnC$D_Q3QGmH]  b!G@_?C>vߡ=[s9>`S`$GT+n՟y8ԐC^E+>Y. D|dhk&01L*bNiB=񧲮bf[$xk:gxJ8f2ω &==`]S.y,c,~kir^r.ȓp !.>DV+t w~! >Qu$ih ěrJ^?V*UX\5B瞆 d/ylo<|JiTsPt!b!fPӌ Ϩ#yi:'Sp. 7?fG,4WmAyT>P{+8`5W5E+=#eP,q;.E3W߶#*H+$+S <9TJRe av&|_ue=O5 ~xqQ #i}#FDAzQÔGiMErI[@jh\0ј~~=ʻӰt1,yEih ԩS-Z~k1@6[cmrZW"FҘO _#H̠Ydysk`oC!BȨ4?sK gk" -/!I3$bӞ43=[?;(6VrE$;^i4,8ԥ65XhwdIeX5}[.l^@eT0lϿk`";ַwsmםݻ+._p*MOMxs,ȕ@P+BmR#TY-\3e&+SRtҘ-T]خ,6`[RTKYaLy3!HXc]p@#J6y$)DA[%x(Kf[GkD~O Ox~8/0~OϊҮ8sgܘ}כD"jiJTFe `q45nx%ÍMJʖ!FɎ h֛k3Ye(X*ףl9e|G‡?RB$:5$]Hi͏]Oѐ4jv'{ /@?yw` .&z%x-N旾~jUT\!`oxh2~=HJ9~>1DkjZAuQULs+{dSaCW$3\ '6aJUKQe KG>gfmܷN>\$%˃p=E'Gz6HEܹf9ҐhWipHkXzLUh^`BW~ɕA,^2 (MqKŸ kA gȒ[u BB'^)r1X.R<2ԝPe$2[\0*g+B3GΫ4@3t'㷡;z{̮say= ~Ra~_oCT!|g9#gDJ`ŀgSs I BYCvBWGpЈY:z-c@y*+ErF*3!Y!f&'D??S/ g-"ߏt{~Md{e8N"J h6ĉF6T(LT;N+UڷS'.LjEvX)~MdJ14+ +4pZZuwB Z Xj:pE3X֦ B* }l 7)+fm8pAw2395c'4p~G>ƎyO \'d]Ufl5G+_f_6 IDATWwxf٦V_4xL) aHIkJ J˶70].>-E*g/dcjţ-,~ iٷ^]slE׹; '34~-ȩ@)PI`Rf\kw N0Ju;`ע .Ua9%$\UrU9dXh"Ҍ!)9*#:~%(Ʉ T bu Vkf ZN~}?b ,B?lށ>=N %!%X"M3Ǿ?3t!Ƶ(k(U;x9бg(*в\܃+>m2edhu32dK=)5HS/ũ),`ֵR41ſ9'O]߄4~nQLe“Һ qfcX 2_Фi&TBK1YMDJ#UgIfdpQoFŕR&yR%*)hUZ?aдj@fu I")Bj31Mpֲ(H3Ag2U% zGwEy1x~Ye'~Gen|cXrq WYaĕ M1rIkVm;ރ8ƙʣz(4'BaDs+\3XEbHh3k3KNlX{Eu^hn $&5X+C$ #"_e%in8#Eԡre\aI,6rަ壏th[2%Ɋ3l[ת]2#%&ٚzKOK'F#WJO@urӬN+8Rv6c!z<^"uW/ƢN?YP^?fy;?zkw~iY>GpNcA @FRϭO󣭽{{߻~u=9'<^NG8Һ 0qL^aXo-@)GKM>3ZmSHP5W?g^"DŽ8TQ}c))R4{궪Ҫu7{1 =3ˈk ǯF$R;ݼ +^œ5Idr)$F,MG:y%5Z=긒9p^MM1w.1-> G<]2gQZhtZƁ)^i< E. Yi_9@yDT zm *8Gɮ4#b7H4F(*amצ\*u%~1&1]҅k?nhr6ÅdSm68IbĤtn~!SDa!ce4^%x0UEoC:9qoS4Ю#WhKڛ~W89e 4](@|>_%Ip)t]٭[4慰%(c'1kV͡ȳ0C˅d=a%roy|@a7iig!%9R1CQx3|a < VgJC+ 1aeb 0]E=7O >Q)(tȬjYoH RDZr3R%Ĺ$ҞM_En-SRRM̍tFRNj:I<ax̜WgqNxgGZkVI`-@r˫9'cMĊ Ib'Q;_ww'0nʒ4١Sh{t={D{!9m,LMc bN_ҔZ*' l&5=UTrŬ2N`Ć693cR?(д8cO_W9V0^WUsȎJwn}%i{7"/_E%]#Q{P rC\]NLږ"W)rU\R$dM u(vb;ٖ^-"d`Ӧ*VҐ4Ś\6rms3.&NR#4'LBin[bVa7q8H͜8MCJ54yZӇ[r9 iMnXI2bvwn_{~luNX5Mѭ=.%^CkYzI Z7-rƑPY-:+;H, %W66BnU]Bd{(I(O[)s :6WR*p#cɄ?sus#X^Cөf!2,kd9r|ucRgfڈ^:W ب-8BvShPG5ƊVU-[:[r!o^F%aÈܠTtԢdLju+efy`QWqos2{nIۂ jПv;9ϳs>sx>hB5a{KH`!m;XX\1T`Zaj^# U#%8:p7JvKb_tD#,cF!Qz] KO0z,@s6)C,]3|$I9GȬcSEB17g'%Za$A!7`0nqepw^H^|LF*fM}8jː'`SؚqN5{E2-t&DR vJ-re0(/b@ OP٦M2Ѕk`_ݧ?z}kf]OX).~2ߥJأm[J7$mF)dL| j)}Z:]*屹&Q22'n:,VewLOx{@qz7UrU VBU?CH>P cYN'=;c'wN+r["){U'h[BIjD*dǸR:YF YRR]F'+ u_Ћ QB:tb)3霏eo+2 sR=025$d=)c*<5Sّ!֧qz1kP9GV+,b O'ӨC @7mzBC_HsuL4y+%В < VBt Zɾm̼G$fYBÀ]gziٳk_%xE;ڑ:t˿(qJ7i@9 } d)lU^ 9Śo'rl&9H+'u@ϒ,.YprwXl06nZBW, Ah˲kX-g%222<,+.tHE8ZђtcV0a8FuB.rᔔR/K"rVk+caB\ic`U.$B BVռe5kY-|N auPP]l+22MHRW&lPl>qsb^B=|B'/I0F T&͞zaX*u4YmI ¯*`BhX,N{}sk[T1:&,^)qZJQdݨ%] %Jk1rB wRndW6 x>6ӐKo>+ 8F"tǨ*hԊx^;\øw82!͙AlE,5з-e6%c ԏMC z>c|gj>cX9mB\R%mׇU+B%౯U@;k[-CEwi@Eʡ҄4hwFrJ12G1u5g 0)ڔYn/pTl54${6g!w,Iy,N:o2U"Ѻ`=QK[keܠ\VP<G!JJUaTc6 W ѻu/hي DdViF`[= Esy$ZX0T0I qAܥpZo[cV3'ksf>+J!dBV;s9.9gق4˝٬mr9 I dc /d{18 (GlyJ٨̅KÇl7إcfxLc S|):Z#  c2%y$VV`q} M`Xq=庨@<|G kԑz{pk .G{||gw41qx#UvA;[Kֻ;Β|˜ !nD>zzZS )#$%0VeޞRJ(Ira.)NN&!$.buasÛ -TΆbiь=%&a p3:fK4H8C|x'y{qԨG|SxBHr1 k zRF'uK $<"ыi\*wU+nyuNsZnۑȊH쒷6lfX|&wOpvG{]u4JX2T 8k9rzd}enoz~w$.Ħ#l w͖hZ;g(\rٚ+ީL|TM1B('kٶL\B-VHY$z->Flt_{Skϣ޹MΪI./#3+ >3Bu3TOnI&\L;Q咂4#I7hD4HkQLJΰ:4`4Tvb !2Z7'*tbܤ[2y֮uZJơ(PW LK's%um۱wrv$hIq[МhV+5!h4TRŜ4_/; eKGܥח3|Fl[bNZ \N=Sӵuo %{kfគCBSSP;'cg-d~lmr~!2aZrF̤%ӒnIbXM Gy \s 9&dy9y߸|#1r͌sVFҭ sR_(]miجoxFemњ}92봔shZ5=֡pmB[qXlc^8\*[וBY)x]b;9AFYDZX'<@NL[9#f9i1?]syGքGq6Cf\a,|͡I*n &SdեY_sqר\q,*iBϘ!jhƾSzi3;kJ%u ;'X3UnC0$Hf 2ZHvwX` ހ/@]*v{r ,44Ly=!l?FpL)ZeOEޙekNC.BUB /ZbmF.k^8PoP},*3EC-u3 [4y! PCJa푚^;͍m3)̿´q,Wiqo^t g][n,~0&DZfE߆\6kHZ ]-ʽQa4y(otwV#'%xȖ9&3]"~UuGlz-UmGvEJBzhڱZBi@/ݐ;<ʵ4]󙏅s\GV~^)id}ڒ=aOŋyotR_g2j)ֹ eTo[[WQGNO)Qׇ6j,fTC9lΰqCqb71 )f6])dz+Xs!)^qI|<$lvS\ϭkr ֏MxF04^r/cٲT*7=>ϙTt)y-lMj:RI+̄)Yu|6r]̤&3͸%ZKe @1F> Uo&xُ.s+6^&&>m}3QJEh͑M|]CŔ̩buIF*G6E ldbY'GCEې2`>Oƙ6cKWsKc S$6њ5 _A#;y sjqj9tc[BE4Si^Ixw/d Bⱆϱ5GOw sw JfH^sc뵇%<v?(O 7nJ4#Vcq7ʐ9RpCz4L ѻFp„{VNRVKP=ymqh,c$o@[\$d&NRXSSKEQC0 X] $\e1tx:|*K&[ҜX`=Lf2Ve(9IXC!@e# bx"d {1S$+}6#~'B yߐ; xo?ܻrls0!}iǪpi!٘Bݤ8#4NC{h91V,topƧd >!U A CJX jJE>̖UGQ IS+vAX5;4z kWy|[%nF8yvYoEy4H7mbEF3"`uc=jcv IDAT_΄񢧘3Zt6ħܑr {E6mn$DH{r9z ϭ2{}^ 24U\=9 #6J̧%)FɌd3JJr е A:kx)=BK%1’o0 b 4PԂ+ 3z$mRWWS6 b!Sxc)=E?Cڜe UI0xXNwyaoOfV0_S;fWx>}s+eD\ԀXc 0NCib4gb_kZ#Fj{{ۓtz 5b6g(YefأG9$>X##^;i Uu3xETz?f&* j*.L)+ x6:7P#Sn|UX*]j!py6h5ePɭKq"6">#CD4Lzc7moX(툘B< S!iՂeH qئ8xc?Jb Sij+iVjHQ fm7r Fea X0TNp m4-q}iq^~cwƶȀ #^Un?)1nTF&c{er].& *͜R Eᇱ".a64}KOs }x~E&c&H eGږz p-VѸǻl͆%+33J&_}Bf#AaK]i^84ڊongU%lۯTu=./ O)+=N..fmd=&!AQO\6rqQ vyb` zY'OX#vVSvTӑFt2綗q7)bD+e/b9*i}b&n;͋F`xf G.`BJicaqB~ */d=$*W,PP< ;zF"fb Z^FO@7KFVVy%4@v1ǒX)%B+*rw҃UtN$̀ưx;McuxxB,}Dfd9ʯ,ZyvBXbnChC)^ aWn =}>"TYL;;؇]$c'%;#\+„Vԁ46)%QȆlݡea2M/Edelj5ze*Mlu+dh Ei:uϳ.PvAZ{;]^ ӔmBB mP*Ѡљ'{ CL"`i qM"CQpupqVOyM8>_MإkUf!CaL rznXN fn4L8,unq|o4qixU2:ܿOO՝A4,x &! ^f y=p keih^Ͻ,xMQT cjC4W Q=ґ<2 7-1m\hn˼ ODc 8hIÐvf$=,Ef#NW%-ac}M,UcJJ𞋬pJ`=\- %AUɮʏk^7<>8>& 뛘a~Ryxs`wcoDCǔ6ˎIo`Fpv6D mf"{ÌAu-q/w9 r<Ź2j{),dFJ1<ϴ]Naݺt;sy `4xOe߮z@T^(?T T,E'Q_*\va)30ߐS!K m(КQ\ti6<3 Y5 {n}joM߰u8Lf\{MSG3/%cI`L!!2 B[AQӍ7Uر' Ɠ BbIY9\'$X}9A,~R%,clBY@1v 4X"(y8Gi*g&)s=A/ E~w{f5)@Ng`}ޞ0IĻc2_D+cUnۙg|HrHϢ[k'.A9Os˵.ZD[f%TJ5Ќ=&= N/lqjΤ}v ԩ`:H1Ř]*WJ2ٲSr32{q21ajnM8ѣ^$ OMd(*es ܳwRP4qj4fP005='OqoܭkӟOqR)+V s􎖡R& 0:*֬Н)R8,#tZ|ήv#.уZ?M0ELvf5-1 뚨qtt;SmBQe&9+KSa)9) pu{_ | Q НxrLbp'J}e?p1yx茆e^IX>$Bؕؒr-C>; (ee:;v`(]5`q oȔAprϾ_ܨDWrnƵB-z`PX%ܶ ަ`iDq p^F:9bV5 p!N ߰4vO1Glyi7,HȩA-u9T~VYajՕ~5xߩ3^*MG|%E@qZn4b`Y-}2 alHJHC8Q0@ &\C=fN~ ߓot:BWd.@zBNK6Ej3g3E4 UPUI!:\e̽8ƽH0i#,)`ary(Zg漮nV6j(#e썰ĕC F+UɶDS19(,:q /М, $P5[Ur]SȘ @B =+ީQ=j@q>MgY1@,`)AH&*)s?M8+ ށ @o _A_*#N! ]1wG݃jqZf9pqgQݺ{8@.Ln:*՝}A|2\ YU͂wid8mXR~`4IMzg δXd^ޕbVS.c[ttt%o_G /t4Ij@q p>Stx\X:t6Kq@P݆`|8(a[fD  pkmT X!o'uu7DMz6_p7asUH\w]DC NބptƢX-Ƨ;L,"zK9fӰƚUV%,Ǚ8"@&gF 35t9Ļ|,~J0'go>9 Wo/^@5諯>~"z :ܷr\ w'䅡2G+{@3jp!/ ;d.7xc2eWH>"#CS^ (Sopƒ`=tY/{+lD(:M#Ύ7h12{K(Hy,H&SMzb.M<`Tٍq.3+ds,e>,E0(e ]ddo.>o|^.B-p0Av"\QͣQQNl, *3D Y{cqsl.Hv5Ȃg Zj]ha$M/"}ѴOgP.=\N)$}ޭ[V荑*N-QK,>:tJuO@.4'1C;H0z䷪M]$z.{N9ZM}0s֖ -؝P3OlYkr5lu>h_7\EKV9([#Ytu&4є{ ǤuG}ɹ:@Xo09 nӔ@344ՑvJD9;eT Li ՀϥC>Hb`񛪴4>˽X(omRW;@ {i #K^J@732$PؙN%VKPf\2(K&Ƕ6_ْɤY .n5Y-SMkiMЉz;7 x_V\\icTjLDq+jBj|]xGܷNF,e LIǨ {%Dn<|MZM90)tfDL/So: E~~ًb|!/\w[E# ? ,-9@]$-,(gxP"3ųOvT}Hwᅡzg߇UZtPuZJLe *i0\U%`9{1k,LY:~I>/j@-%z!p*{ I,=_ST>" E#ZV-FƔE97 P*ڮQ 6Z)NIиCVo]P4NCJqFj!Ujg#ɠF6YNN ; Ь Vlq &Ti0+]ExׯxF:]G߽%% v- tMz_R֓iK*$Y)X\jWZ@S|TꚚõ\5`}EU^E p,I”㺛0a -=X6ΖycE# j 4!jgR/=uii%jlj=jt3NQQoؒC %M\z!B ΂3)L:%tځ1#:x!ɨUM&?Ky]>S2{Sa x>ܺK.v tskx#]η;v_.+-,\cҜ:cy< /zmNv}מ5ŁCKAMsaOUa6xsvxsVɶ.ŚPB4t8ZO]g.ob#|- zC7n?=FzSw #uylAD ?{\#׿zUU~YogdE 8zW|41r<ʍi>A+܀Κ>"mocl#*p`5Hj^(:jX]pxu/`ocM RC&vrɲ5Pk'Q'*3tcۨ) B5(Za 'H6x2u(s]ŌՓV<WI9:f,N-˥ӅXv=: O0*m-R)1g`1i͋ȄTAԥO!wZ|Z™+h/LtOv;yTvGлW g_) 5ɬ(tiMsMjLs.O'vn]PN{W,NNf`)HC70*>J5m DVUö y Jjv5J }VJԥdʨJCCVL6@HPswn\d+KH(4=tR~8|t-OV>_'e񡀗9C:YFzqu(آ\;%]"-|A>]Ue)8\ն7N׮g_ Nf#s!nEMt&:5P!:1N$wA sFݷi7Y IDATwJ +Yf V K9;iDRuW+#9#!L~L%Q(jz ?B$7j>cf;])7kYI@Q I8x;Xbn:kL|E؂͔2r㒋U^8p)b yzB[JkE#њ%i&EQ,&zCgPKO 9RSG|nF9.}E/ಕl쀉tF+]SX:'E^Vp(쓠b%ɖa\aO,5u׃: 5g~:pe&;/맍kj́U+VX]N";DVqc@ xڃ*pl\WRvVGGXƓm{%ATpś~I˚{h|\,?[E2~-#["6m g89`.XA殏<8o{ښ=]"gg8G yahLL<5FO8؄N@i**?y;f#t+|3WVwwЇۂ/3Ep <=7GKz.)AqoYNgN`-qUc ^VmD@0B#ҏt)P ̓oZt)3`F"ƔX!"V/T0Xc3a| /@Or<қ=љ#t.Q{*b~Zμz9ܣ&;".qzxQ+)Ujkrp)s_Pr )cR|f~V#P;Eł`śs#[:pw?iG-O \ez|^BF,.XVnb7t5Ց;442hQ#,J#G"e{ F"0WZAK+~Vsool)s (8 ?[\iV9y\s\) < K+_}}ϵl^UXp}w=JBd.ʲPCj]pM4i73%JC?5Ui~Lh?%ƔT'l:fHbΕ,7֤gP7Hqv\n.l[؜Uɗxhǂ~"tyT;ɿ.KƂ<>7K׽HL?^In{6SR3b %KyJaLo!U7o^ʛ|%E7ӱs]tEGJƨWC }%=8 dXl4F"ϫٻ48p PoZuDwl-e# EcO- mmeE.fc|w`Gn%nD)Y>*I(TMEgX Jl]!p+!b{j.9^I'S7H|-Qt*]Ѡ&оWa`ż(}7|3\/ =BqUtTt i*n"a]*\bPo\;9Vsq/ELsr )?l&+"Zx2& keIA| F:vkEd ч~SKHkuma* y&KU0“};s;FA`n*%lWǒn+IܶWL<x׳KqN`g@@W %2n97%~0+ Zl"FbA":wPa? DCb^FӇ׸{n8A< dNj'1 K7Ʈ:P#ٓ TV#9]P|ی?/Պt iisDA 1?]fog,QW+avukIdCpڗftmn[߫>D6"C ȍpOeU>jDBjNÊ?eBu=6Fm1@9GQc^-MFحT&k jQu'5N4J) j\|2O90Kczҩ=w[AlIo.0!U3Pqd|{h'@w{\eoX+k\-"`}`dz`У‹m.!v!Ξrn@aofcKVjG-hG*2P"v߅_?Y ~T4!xmQHIdxëqIE7 g;Xْ\ 1s(Dk "4Cgj]FGրי8C~pߣ~vS]y Y,ܞGÒtK{}PUx+JZ3MhaNfBdPi^2U6eR20F+}1WL9\/iB:avşyC NFS9\hbҲyWchHHֶbq+gO؈/ z=La΂iϘ1M  &ULg9O)6&i1!U=L TSxr55פ5*;uKXl3pɱj0hnɏАcߢjY7V< CyXr8'ҩȟ _*3'bi5jac-cJG&mYl WPX 6I Fh)>j14O% v09Q%`%ɮdSxڟKcNHR|J (-!Ri :v-@9{[?_A+K_F/ ZRLZ6r]NҲ좒[ٟ>AwإXyp#j0mkA3g)AOE/gwt,(Yf\|ۀԑ$0%p2-.їbLRF I\s_},) %LMk":Sji1tf[sG/wjlAsOIWb~%t(e˴y}ņPnԢ%8V mҖ̰$Ediɂ5,2k=1xvgHNWȫh=e=d7AdҞk9zw. $zo~Ou,/U xֳLS>!ct}Py#OxW9?-V2E"Z|l~9.Z+"?Mc#9G*b}dƺ [Ȏp, 薹$-M(rrrcQG Jz.Lzlȇ6XB XC#tBOD:5$A&gV}1"$l2V ̸Td1-+¯I)D$ Cu+O1()K1*k2v{9$EL'$K{F4 /dj Vn#+VJAxNbω  K9 ID\x"Zr~QJa4D,Ao\q$[WeqqZlӵR"R˪%cO: HUgUƒ7}U>t -F'Hΐtem6S!(MWǵ[f6~Rڅ0Ԭ(ܤuIUZ< -y!U|2H;=)p*>v)'I#Xcp4NTgNgZTc@ uG#7H]h8FLut~iL ͨs-R@6 3cE(NZ`DUxqi{PeKEMHt]tU#igg_AP6e= n`dzgV8uV[rZThWw|_xRȲadN ,'zI41u5*1} ]t }pOus"UP@f81vA?=C C&ILv1kZ4M\_1%}[iR5=CLBM;n۫uG9<]H7`L|i{%ɮ%NsR:a/nܴ**բ>h5!YH͓q]qݜXZ23L]#j? )̍'6"׸#?'/o/|yyWD`iYBno)&Cԥ ύp_~$%ĊPKZƧv2ԍ6H%٠*SRgX}%X4@=CzXK2tW#ЦfY@;h w7V™Wukn7-QxRx}!,ْPvtT,Ţ  kn e$[k@8Esn|̈MK5;GCWKb[Ur^9ab&6=,=o 43Y'Y@\vVWoq_7m 5t.PP?G: oWdJ(!z)wțh~H LIcia̴{g/ K<Tk˞.e@%WK>n4pG_Tsz5c C\bW.FViN!(ukhࠀhN<&BY.CH"A8FWtRY)R-^1fn;|TP0p1Ю4!=4+Իs.@1@ r Ul ʩV3(z;Ay ޝhfܽcGwq`9+_E!x~W,|ͳ2Sxb9`YM6앸F?ЧN.`C gNLՌ#z]ҫ^4rۙm>x3Pm,B7awlͳ%^x9t.YBxE=WU1<bMd> ǺA<>*w `|0f<=\\0oom(5S(<[֬mUv&= 7UKn^TixB!ycHdK0v[EnjCbFl=A@Auex U};$gU1Zrxf{eMҪ4w%.܊Ϛ\U g9hE (:2h.]\nlfWox1j"};㒺^bd խ yuEe8 MډLKSMK+ n~D^=kuyׯ_v;ng }& ۇMp[9&t2+e<uM}΍Xz}dП3mGJdY#_#=Y)6 Kj#6]:r1h(b9 3 4A&)a-EUlG2vArCNvOPqz7T/bOyaDV',9# xYZ!w]+A)a} ?_Z30$0%4`KrXt mL⻡&%#fմ pZdz҉1x26fG C{FK.El4IRa@UXMY[$*Ì?FzA/+榼֗_XאY1rK2"nEҰ'U1G!Q܊N]%j"ZYKl>S6qĬVѫ8,\vc7Fa,bq&zUi%'%̳Klc6v$<%42'헐ӫp+\G-b*H^י_ t<8\md`U`9~(t|^}M,#%9?ݒK<XN y$x;H\N<3e\MjZxv {ms2ޣ l2]l] gu-V,h,Ә27"Z [w,o4+ywa %ֆvo:Ϊ`HU\NGSԙ8c [;x9B!lho9(kU>(S.E΀H=$ 8W8SDnλ>(5x7T%_LLEhYÌYx>#jCI۩RDlGc)1Rsn5LbY7ǨԂߐbW:j7SS}zwe.T`n9V]KN穃>@٨,ֽyW9  tdZ_4 lQyC%@|8 1ϴ) t`dLN85ؙ$~4͕: '8r,V5~/ _ tl+gSNJZ [ȳu6$ؔs2HLt 0-Lyw#: !$7d:LUY2e$RT2*<ͨs3p$m*AMݠ}HGb\u7H.zت RvԢA[Ǻbanxrl] p}L 4@/J$g]698zs (:8 [JWHeCE#UF4邎6fuzw\a)q1`%λ" .e+t|yW'0p~#P G1"0i kvC_d#$LvMTʺ402)ok|EƔl.Q LI4Fc$k:O/toJnVא#pxsVr*w%`^ sBesKi \A٩$kw54;q۫.MS<.r۾ڭaԣ/wBMZmfTd+ܝ&#ȋSKXB.UQG "0NS3s}Xl " +9, ll.\ 77s>Կz*Y&IBW:NoOZmM*@08Pu][?5QszA T<`HhdN3ϰ za[Kw卭0EͫbR͈ L1JF䇼归l&Jg&wBP4ؓ>IosBqJl&ܰ8AC9ӳnk©Lo}Mmu`s\d" - nob~/nn~-ps tBqURŴ*KYPLubε ?db&XfٗR'Aqݥ& V˾Ҋl'&5_>1cZn^v5ܻe  vhw -9;pw]F]ITg%Bв s'qKFb.WTu++[!WX2/*qKx߳$@V׆ xx..Žx&`̀)?j{,@T_߫Ujؒ}T+3JA!?iXFZukQzVWssgOp x݃ LA*׿ ߃eP6b).%~^!=uLXY|1)$`pR RHUB08h/Å#R䱏2TïngZI$T1bp`E27(grAZ4U ?Xnb5v2VT.HmN .T#vo:?{ρ'so1c諗@v\o_c& ^a$ɝul.敜 @tkdRBHsrx#Rأl"߿ K.'7KXy6Y8ss(PoDI?|tZLx wIbFHA8V/gE.Xw35b#( 4[$D.m(UjGR 3 91gyK(tP$Rj7fveiI\OWB&N"S'LnL {癹Mn^L_(+jk{MrGurL=Dh t-q,Q=+TQjWPEarZ؏?H 6ChHv`Y;˗|<>y⋷G_, Q,]ײ "O)W#[VϊU#dPMNԨQ +ќۺ"%{U-΁+%+.Y#oǬAAG9e)\gX̅+ǀ#ZlSQhp^RHrwI5ns2aĤ h.j*}Ъ%>q^*PJ""ǮF{󽒦* DHuC^OsON0hb(-v1z]q[ _CZ3ow|"KB R,O$WE)LՓܷp8|\o:G FB.`[bOhF>1(O&׾(Ώ| /ucK'X)3Hؤ|?z쳸or|_ϒ8p BEQU?wn&`l$:N2٩$@Sr .uO5l)2ytqn&' oOm|Ѭ`Y+#2!=[Rp ϿhOºSԍ@/O}_ z\ aƤZ,D Id w0D`Rq phP3^0[L^dV~6cוx25/hMƈ 07 JZ:Ywe X6/o 92bHs}RĠey)g,S,#P-#z C&e.~N.ٞԒ HfCsh|_igL UE KtW3`&dtK-QmErsyЬ쎶]2Tv,!5T4JQ\ZigBMUSXkahƠک2$ZBoNo@w\l]Og@܈c."vۦ{d OӐbm\eجvn30C=raREipk< =i~xzuapoKLr~mU3 LD}?>/glgB4 ZNl^މ˔eTPvJh R6sӑ41(MjW(:1˾6>a`_1'z495.O,BŻ#n~n$7?,4ˁL-;XBPfsQĮ$KGQl$95:%Ԩ"R Ԯvi{i= rGu~Qg8ڭvR|b``rEM$T=xQ z8O~c~`k7Coo_)9oo͖ iU߹S-IڑǞ y؛gh]FK.vbq"gK$d݇2VK{s>*ԽX{ie0~U *Y& yIk ?)aA+h}A񖽿"=䙹6'*!ά/{!HiT} wxtW5;ZI&YKP*Ql mG.'D\U}Ķ\U}%CLg^%/0ڋG\W7l5ҵGUeD;)X@g&x &樔7)w,E, V\Xqj]^Ϯ Y"9$NȶT켚tdmZ@ @g•辰q=s?s97/w%urnCvZ,R_8q mE?Q)?1Qۑ/܂}dIlkR{ .\܎USl"і)r8u}5WDz Ë^!&G#dtKh~}.slf%6g6+yvs1UlhW }{K[yNmEs0FQ]{AٱuxPSh:5G  6 qoB7')׸4~3 A(Wl/n?Dzв;/^K.f` eOoxg]{ 7r3b>#ܕd%1rp+5ppAL}G1*գL=L*=Oni[&s ˕6O׭{`}ޕ2mDiceUmYP+^!cTTئn,^9 Fu:ilOpȒvkLh0-"s<_58qhF=<_?Ϊ-F jIWPjHnwwC(qEqs5.بzwv`h[7f[@&Pڕ'v ;:"m` ],SB!̹kB́MnAr@LKe@^t!Ӡ"ʲE&xS|4Rmf;&CYo>֐#.hqeyOyv`4DME\Iҋ8$2"ETDbF~wX  Ph` Ei+D/Rcv@Zjvp5_4y6wz@3<_}vdA_w焫=*TV|iX Djmxч{kzyw" hJP kkϖ5Nkks֯,XKEV3\qQFVV56EdH? @:.7ߙ#a.>]|?GFڒ$5:ӛطgJbN9 GXA0{7O<)H @/i[…uu<|< i7m̱}%Vya@?WI-xAupGؔG襀bEm>~\iTwNkW9k?xKL `b\OJq.oU3o߿L0R. L\UI0f' z1&wԪv8kDֆc{$ZwguU,ɋ4 1z;{*!׭XA1Q]-OJkC"3gqN(!aK.fS:xVI<8jaҤK7K$)ª&k'jQ<1H+-"VMu np{!''^qx 01$ZڊMW'3F$6hpf8Mx6? {T엥D&\* >Nh2! ھK[ .g1HN?rcD<9QU V IDATħ{) 1/)n^`d{AB}slhFj5q[Vb4%؄P dhKXl'{ʡ #%׉Vf>6zp)jA Π;Ґ#u%>܌A~.PHE6q+'U7e?BT ^5 {蕧bZc?GULO,AP273(@}oϣ OL PaRly 0/Q(9 E.q6-#xr ŰJϑ.*LJ$.e4 -Vw ThF %G#.DIE 8[Pȝc_()@{Ǡa0Ge@r⊚G:HĻ`h) woJ0,jW@liЀj@uѮVpu ?PVpڜ- !SPnn^@2{z}3y9pr\Mum\_k{8E'gme7p3?ӰiļP4bؒ(3#NΨ:{_dq\w^Q#)J`#$xaZhv\ba֡Z0M!1tw"3C^e==++Fy־Ȯ^vz'I)-bQ Uj(}h>aAaZ1 #^ܽTc k@6􂮄6:F[x.VZŔS8JOEIojr"VD'݇մYQ[$jD6p6{(VU,dǃȠ]k1>A2%%@yP/c1]I wgl><6n)uy&޾1'l`jBIe+ylbX-BLH %s+\SNZ917v-7D+.ic1 W o]W+5bg jFfRٖ<2:!J73(@SlĎ$y`M,VC;`bF*`v\6{?Ttp1ɜ񥻂{8H`iCT>abW<+(8yST.9vM\ooﺯP.́Kp|?r؝kIqĄΦc朗7Dz 7k5%t7" ^L{*TCھ; IdX.0*Xǿga$<|q_ǻ(?BAboS>3D="A"6U12Ax9?ĝ>^]ܦ]OR-H2[4>@3Zkgy"Š rh4aw,_h[> Z$x@`vdk\Nn&s"3-kcC vzԝ@sO"v Vݫ*EޖW❂}ɲJ NF}R=޳Ϭ1 +iPysjx VzD_K # G pA&IJc*; AŦkpY@mU >cnN_ 0d\?Y_DWo`OBtB!U!DN 볯><7g /} ekSEcY:!sDjM'@NGO]xcps^P W # ^bb*M '%aM!BбJUoKiRK_+j=FsǏIdG͎w~U[;ZSHBPktq ttX<6_R"Hi+1pj%7&‚n4MJgJ-VӔ mȺQYФvA Gp( tyh|Aqtr +4\؅>(-Vҝ*X]<왼".bx/aTG7R}<t%Nϴa Q+ӯF4.m\L"Rq[2u뤄Ώ$>My:4%:69eWdS5IaQx6MXARw\x..7Ao@b},nͤ;)$ 5›G&Ǥ[{QDMMan]^}<>\&<Ak{D8 x4op|HC#+m䄚hUW^L@rd{SkfJ20/(UZ J,qVl;q?F[ҝ|fdm1ɻVV+IXv}i=w/$ZM+"^FU+U.Gvp危l4ޫTQ1mK)#"P(6Y3RhԎiM;p, rFR7%s5LJ48;5ԋC3.>遆.mۦZܢ%έ J=RFG;f6#?ޠp|PyXe!X_cGI*$3wUΛ"6f`AlJed輞8ܽ:(EH\b v'j%iL>0f 7 遃؞:Z2HkֆK빗ÓOꁕ^G0RQbO'%[WTZ:R7 鑭LociP#uZnxIvg O'4yJy18umQI~q [P֒ zn;V0*V=Ċ\Vڏn+ӫ=-N7$^k0zz$yBZ;yaBw.cMJ1?4ZWBW8ײ-Lxo:^l#6=YVy1ry*LPxj$zK1wo:c,脼A \.k1n@ջJ8ECo,҄*ܡ*$]_!.S^X8 ._~=/;ՕNͭ1[ES;i] yNKZӘx!/+NƊk#COE Fէ r1jKũ/TN)$-IKmh%!CC"DF΂1+9*CF{=wJh<ڂJ7-r{u7@B|Guj l0!a&?'FJYu-±fT%XDBzf5%*֖J,8EQ-sy{g5"-#U Q Mu-,H/?8u`z `> ,>)@.)_}*,s YVPennp GFQA8Z]qnc-Ӷhm%ȃ*aC>{r},DI۞_c91MW?8h-mkHE!\F3E.>g8^/d.\QWeX9)-P[wg3L99nR雮$a#Yۀ o"ħeiE{^߳#_PxIaO.SXpje:J1b5"Ut:'U:rE#֯11mctR>b?+O ꠰lJ7Cr4FFMv.=c>} }btx( xx[ĖW}17PYUP.aGHԥZrv|.컆q&&I'DIAS$csP5-Ohڗfk{VNEwif%h ~AM\ՔqElJ6BSU3zUyc1h>_@OndS$8%Q720> WÑ2NBGozWYnV,|ߕXzlldc4Ny^'F: )MgFtug{ZP$xQ)h/OR*7?9Yol VZ{ T١/˙[/)%;"^^ScDa- }>@k_a> fRH!ks:Zt/?ǎع&yx 5եљk.F$zH 1ĭ(ukPU}.݌ze֟]Og(hImg׆FP][a}_JrH59pU'qdYq@#!9(%= .&/f}[AwEq5Vzה bwDDYMYq֧ؾc ulMB Ji+mR`}1U\ѪJ?C;b+ n1u?֌<m+L@@NyuW@rzCGG00=#a*TuX.82>{8[1:7lwRy 9p& dePk+;AVu6;Ϲ9`Xlu4;p9OlM 鮵XG?ڤDyOp׋Jo' >5h.te$-vh)zpJ/1$;ZiDL߅g}᭦&w|6Bn1x OfZ^#ɺ!5ՑlK%a#QōJ/laiƑi kF3P쯥*&HͫPC`<ғ{rTtAGl!{@>]Gq I7!e#vÓwd0Kn[!k%$CnX$"#oYrۻKXuk<7MG9`?9dZC809AkSɔd"Q$xZ$]M-aqcSS4hpbD>D1N(V5jŢ:n.tL#!kZ{y5`hF5ԁTq3/Lo(J^gC?эBp, Yn$$\byF5ôD2iä$IY"?E&nu%9vmdEh5M[5gG ~zpj7G%hUk.+w=H4gOy(s5^&%5ў\.hC=09NG7q<,b t0Jŷ(LHĐa3))A;jr`RQЧ**+ǭ60-Sv^EP:SI\2c:9Q&}`K؍4M^5`o=cT0 S2nB-寰<lĠҬ@Lݚ]V'q V|iXRxBH$u$ c} rJQNKJOה؂zunrJqme=@..Gkx[Ȥ6>rJ^''ޒLF`@l]hƫJҦwثϵudy04jXlBR'd۩ϿhwcVNJT)QW?k\ 1 Sr;r@jNʦ3CQ`ԉ "?ciV#HIna}Mc-?{\˄9+e_GKWot%ro.ep)BtwHa!wPF$ ;L鏾NC155Iѳkݏf1JASմXggp|WܫBHn_m]ʚO?)Z@ 4ޱ{^.Sx\S_& |[\Hk9+gvuG mHeSn`)ũL@8g0uL@KXbjҹ%2 ٸ.7^HE 3:?O",.P y V ֟Φ +v?j4}V5)?T 7,%y#YqME8 I}Ma.Lb9R?t{aPhre}SOp S6O;m,e6ܽaERQ̭r>89aara ɾu) J $Ad`T߾AVB0GSbƦD֧ܘ7ě5aޭL 4<AZ3MoBב&t媏6{|%q)tɠG\eiihh(-|bDMX\ĹuWRWe}7?h:YW`Fβ-a3BfJb6"WeX׺Juo%3sm$ц`$D2T{@nO3J>@rvhuŨj1`s>K@I5>yʣaQ9).\Y^ 4 *9xg!ITq4;1dhm G]_Cɘ&,B(vH[|י%rXS ,`6,a%TS1ujy  9ZHN}W0wGkR ȓ ^`^."IuVKd\!4mYl6^yH%ߙ.q|V]jbWzi 5mB]#l`AJ[OޫUfl-ع@[Ҁњ̈R7DRsr0s.Uw:_"L#fRYP9X+\LHyl8g-"'Ӻ[c6SڣNj~uaFZM$ 㖺8rhhcfctWM&]D~L\2p(q!Te$\BP3{h#&E=~wX%ţEc(ֺnm珱 UY¤ԈHQuT&(s"m`p6Bպ bZںY 涪m:U&Z]ܪP !ga(0c10Al⭯ǏxiZpwJ:!_ 3Y$whE'\ORi &ۇ{KX^;gTwӒXACLX{gduiv}]]9=v6nIDAT1U 0Y6 /m[&9*{H9iC2L$HJSMos w5ME"u9pВ_}uS`^OVn_ E JJw@vPֲ]bڸjjU- ШY D#$.(HN7R%-W_Ao~'п3Jf!&(JV$%ϿS=kDuk7]gaf7~FcCUwrcd4*#􂢡uCOԎ'uǥ+FS r`Jj{8UVI, e*WؼFP0R͈6)<*a 64[xU0jYݵkc/ECi2[4AUVn-T0q?!"G#TPh3 xGP8ko>V 6pTÍ\͸FV}"/u~=1 |1-a5mqR0iĴmF;$0ٔսr1D@%IsbHD-8RQ@hQ`@ CW,YlQn =.i8B'I76 c6Քxw-[DxGwj&}/I ,%BhRT!X &5Xf ?() #a)S1G,0b9P>'g~} ,?xs&L0dL y%hܿLu %?(^m,-%2v;,@hf\t(G]ѳ '#V{?&íBxd41d',3>BOźIf<?+.pYl<)a i9t+G0M(mLCҺցZm'T;Qh#m3S '5`=s9ި ^f$',s'L,$`Q@X,_Ϙ+LS?C;#c#yfI&)׆F|S/D% G 1šVP2;?sZe..bot/XIjA-2[hqEmVzżH] $&Zԧlz"T|I5 *=UkF&X됑jz*`ٰnn:eوVĪV2=Od=cR1A! lG!EPJ¢&RH`ļ'QPŒ<%3_OAM;ݓ'P |xˉ0pŀQ@ uR4*;=i' $f2RneKe畜fڇq/5>FmٰFRT2ZpFʡXTWn*jUgC+cq^[k:_c!E ,&oVEnV] @g{JHb[LW?Ww{M@x?'Xqr&\'QZkg6V8"C).LݺE3f}s2*;nc!Pb ӳ 0ȣjUctƉ jOͩ%)(LPPfFQ} QD0PeH( r R A~cOj7o}}[X */ժ7/ v>ȋFPegU>ᮠ\k>j;ec\Aiw G> oy^m hfv2i[ׯ(>Nk< ;nݽguK2b(9-d .lc P zZ lDŽtدaw+[^wP"wr픨i[h= d@6З C0m 5Q$ cņ,@|O9[46wx}=gwͿ; M,wg/3d̐Ai"'\A Rf  = -sGA?z  78R x5&qfd0NQ}}ߍ>NM@,Gcݎ) TUg_goX RyU዆+;Kۙ{>CgߥZ{ kj@Nj'`X(df[E3 ם.V vzn9P'V8,Nbj, uQw6i̹\}Q >`ݻu^ZCDSiqsz-d݁Mow75Y8AvTUݙ,~}AJ 3dLt .h31Kdfhyr 2Л?>#pt~ Џ?~cB/Dg@oq\9;p2͊z99<*' /`C_8!H9`w~oA: OP"l@_1񡁀 Hm F1ҾڱrD;$(OhӃ߆u* 4sL<|hx GdZR9za di;sE޳}bCf7Gis|`$L)lI&䓂~/_X2Cx٘x5^ ;Nq`}/egEy}YQA#r`p'-G-+AX˶S!{ >]0v>%ξU=K[@ʎ1AI}ȵm ;&\3o!dez`8X {BdɎDJnoO6CbJp8_4Cюza^HvVP,p {@N)@VG`b-d7@wA{|rMO#.AO] E8(}d7ɞx0^@ #gA{|:T]J6X\\@u$XQsU/oaXKqj茄iߋB<ޮb 3k osp6foiWveJ"oՊ j'Lt;cuvCrl&JMBy73t܁x$β8+{w{0tۿF:LR@CɊ++﻾|s2\Al!#'$, e&]-;:e;G#\.};%F5g~1 TAcXh^UQc@ jԇ ۺ%]z7iGR W,g_̛dJ/ :'˨fd3d d;N'C[ prcBkGM7\_'oxH7v|o P|-̇ ts _?<nFhz.FO&_<<7eې?SgϠгgkv3+W ~|v>˟B_g>_?8ߵPIѸ불3xSC?>qŰ@*| AWWVT+iPjQ:<)h5op$o{fDbsЯXX-ưn*م-6m޾Z۫,s,u=0 %C0φ hHa8@ϐ}/'9?|!}}o?{* l_ۢ?|%|q~Z?bQ':z*; $-{tw ϠO8R2r FkۇG;f@ӌs/< Ubkst2d[[F"VZ|w4K'ꓟ })F yjN<! TYbа@/rU,BMZ}pz}2ɀC̐]a+;o\ի~o_%/k wSyUVLV_5>9pŅEǠs㩭קo S}Q>YO/x+eiwIENDB`kraft-1.1/src/pics/sc-apps-kraft.svg000066400000000000000000005246021450127457600174270ustar00rootroot00000000000000 image/svg+xml kraft-1.1/src/portal.cpp000066400000000000000000001245151450127457600153010ustar00rootroot00000000000000/*************************************************************************** portal.cpp - The Kraft portal page ------------------- begin : Mar 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for QT #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // include files for KDE #include #include #include // application specific includes #include "kraftview.h" #include "portal.h" #include "portalview.h" #include "kraftdb.h" #include "katalog.h" #include "katalogman.h" #include "kraftdoc.h" #include "templkatalogview.h" #include "materialkatalogview.h" #include "prefsdialog.h" #include "documentman.h" #include "reportgenerator.h" #include "kraftsettings.h" #include "defaultprovider.h" #include "archdoc.h" #include "newdocassistant.h" #include "doctype.h" #include "tagtemplatesdialog.h" #include "kraftview_ro.h" #include "databasesettings.h" #include "setupassistant.h" #include "addressprovider.h" #include "alldocsview.h" #include "exportxrechnung.h" #include "ui_xrechnung.h" Portal::Portal(QWidget *parent, QCommandLineParser *commandLineParser, const char* name) : QMainWindow( parent ), mCmdLineArgs( commandLineParser ), _readOnlyMode {false} { setObjectName( name ); _readOnlyMode = mCmdLineArgs->isSet("r"); const QStringList iconPaths {":kraft/custom-icons"}; QIcon::setFallbackSearchPaths(iconPaths); /////////////////////////////////////////////////////////////////// // call inits to invoke all other construction parts initActions(); initView(); setAttribute( Qt::WA_QuitOnClose ); /////////////////////////////////////////////////////////////////// mAddressProvider = new AddressProvider( this ); const QByteArray state = QByteArray::fromBase64( KraftSettings::self()->portalState().toLatin1() ); restoreState(state); const QByteArray geo = QByteArray::fromBase64( KraftSettings::self()->portalGeometry().toLatin1() ); restoreGeometry(geo); // setAutoSaveSettings(); QTimer::singleShot( 0, this, SLOT( slotStartupChecks() ) ); } void Portal::initActions() { QIcon newIcon; newIcon = DefaultProvider::self()->icon( "logout"); _actFileQuit = new QAction(newIcon, i18n("&Quit"), this); _actFileQuit->setShortcuts(QKeySequence::Quit); connect(_actFileQuit, &QAction::triggered, this, &QWidget::close); newIcon = DefaultProvider::self()->icon( "cut"); _actEditCut = new QAction(newIcon, i18n("&Cut"), this); _actEditCut->setShortcuts(QKeySequence::Cut); connect(_actEditCut, &QAction::triggered, this, &Portal::slotEditCut); newIcon = DefaultProvider::self()->icon( "copy"); _actEditCopy = new QAction(newIcon, i18n("C&opy"), this); _actEditCopy->setShortcuts(QKeySequence::Copy); connect(_actFileQuit, &QAction::triggered, this, &Portal::slotEditCopy); newIcon = DefaultProvider::self()->icon( "transfer-in"); _actEditPaste = new QAction(newIcon, i18n("&Paste"), this); _actEditPaste->setShortcuts(QKeySequence::Paste); connect(_actEditPaste, &QAction::triggered, this, &Portal::slotEditPaste); newIcon = DefaultProvider::self()->icon( "settings"); _actPreferences = new QAction(newIcon, i18n("&Settings"), this); _actPreferences->setShortcuts(QKeySequence::Preferences); connect(_actPreferences, &QAction::triggered, this, &Portal::preferences); newIcon = DefaultProvider::self()->icon( "file-plus"); _actNewDocument = new QAction(newIcon, i18n("&Create Document"), this); _actNewDocument->setShortcuts(QKeySequence::New); connect(_actNewDocument, &QAction::triggered, this, &Portal::slotNewDocument); newIcon = DefaultProvider::self()->icon( "template"); _actCopyDocument = new QAction(newIcon, i18n("&Copy Document"), this); // _actCopyDocument->setShortcuts(); connect(_actCopyDocument, &QAction::triggered, this, &Portal::slotCopyCurrentDocument); newIcon = DefaultProvider::self()->icon( "file-export"); _actFollowDocument = new QAction(newIcon, i18n("Create &Followup Document"), this); _actFollowDocument->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_F )); connect(_actFollowDocument, &QAction::triggered, this, &Portal::slotFollowUpDocument); newIcon = DefaultProvider::self()->icon( "printer"); _actPrintDocument = new QAction(newIcon, i18n("Print Document"), this); _actPrintDocument->setShortcut( QKeySequence::Print); connect(_actPrintDocument, &QAction::triggered, this, &Portal::slotPrintCurrentDocument); newIcon = DefaultProvider::self()->icon( "eye"); _actViewDocument = new QAction(newIcon, i18n("Show Document"), this); _actViewDocument->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_R )); connect(_actViewDocument, &QAction::triggered, this, &Portal::slotViewCurrentDocument); newIcon = DefaultProvider::self()->icon( "edit"); _actOpenDocument = new QAction(newIcon, i18n("Edit Document"), this); _actOpenDocument->setShortcut( QKeySequence::Open ); connect(_actOpenDocument, &QAction::triggered, this, &Portal::slotOpenCurrentDocument); newIcon = DefaultProvider::self()->icon( "archive"); _actOpenArchivedDocument = new QAction(newIcon, i18n("Open Archived Document"), this); _actOpenArchivedDocument->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_A )); connect(_actOpenArchivedDocument, &QAction::triggered, this, &Portal::slotArchivedDocExecuted); newIcon = DefaultProvider::self()->icon("mail-forward"); _actMailDocument = new QAction(newIcon, i18n("Mail Document"), this); _actMailDocument->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_M )); connect(_actMailDocument, &QAction::triggered, this, &Portal::slotMailDocument); newIcon = DefaultProvider::self()->icon( "mail-forward"); _actXRechnung = new QAction(newIcon, i18n("Export XRechnung"), this); _actXRechnung->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_R )); connect(_actXRechnung, &QAction::triggered, this, &Portal::slotXRechnungCurrentDocument); newIcon = DefaultProvider::self()->icon( "settings"); _actEditTemplates= new QAction(newIcon, i18n("Edit Tag Templates"), this); _actEditTemplates->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_E )); connect(_actEditTemplates, &QAction::triggered, this, &Portal::slotEditTagTemplates); newIcon = DefaultProvider::self()->icon( "settings"); _actReconfDb = new QAction(newIcon, i18n("Redo Initial Setup..."), this); _actReconfDb->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_R )); connect(_actReconfDb, &QAction::triggered, this, &Portal::slotReconfigureDatabase); newIcon = DefaultProvider::self()->icon( "book"); _actHandbook = new QAction(newIcon, i18n("Kraft Handbook..."), this); _actHandbook->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_H )); connect(_actHandbook, &QAction::triggered, this, &Portal::slotHandbook); newIcon = DefaultProvider::self()->icon( "help"); _actAboutQt = new QAction(newIcon, i18n("About Qt..."), this); _actAboutQt->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_Q )); connect(_actAboutQt, &QAction::triggered, this, &Portal::slotAboutQt); newIcon = DefaultProvider::self()->icon( "kraft-simple"); _actAboutKraft = new QAction(newIcon, i18n("About Kraft..."), this); _actAboutKraft->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_K )); connect(_actAboutKraft, &QAction::triggered, this, &Portal::slotAboutKraft); _actFileQuit->setStatusTip(i18n("Quits the application")); _actEditCut->setStatusTip(i18n("Cuts the selected section and puts it to the clipboard")); _actEditCopy->setStatusTip(i18n("Copies the selected section to the clipboard")); _actEditPaste->setStatusTip(i18n("Pastes the clipboard contents to current position")); _actNewDocument->setStatusTip( i18n( "Creates a new Document" ) ); _actPrintDocument->setStatusTip( i18n( "Print and archive this Document" ) ); _actCopyDocument->setStatusTip( i18n( "Creates a new document which is a copy of the selected document" ) ); _actFollowDocument->setStatusTip( i18n( "Create a followup document for the current document" ) ); _actOpenDocument->setStatusTip( i18n( "Opens the document for editing" ) ); _actViewDocument->setStatusTip( i18n( "Opens a read only view on the document." ) ); _actMailDocument->setStatusTip( i18n( "Send document per mail" ) ); _actXRechnung->setStatusTip( i18n("Export invoice in XRechnung XML format.")); _actEditTemplates->setStatusTip( i18n("Edit the available tag templates which can be assigned to document items.") ); _actReconfDb->setStatusTip( i18n( "Configure the Database Kraft is working on." ) ); _actOpenArchivedDocument->setStatusTip( i18n( "Open a viewer on an archived document" ) ); _actOpenDocument->setEnabled( false ); _actViewDocument->setEnabled( false ); _actPrintDocument->setEnabled( false ); _actCopyDocument->setEnabled( false ); _actFollowDocument->setEnabled( false ); _actMailDocument->setEnabled( false ); _actOpenArchivedDocument->setEnabled( false ); _actXRechnung->setEnabled( false ); // use the absolute path to your kraftui.rc file for testing purpose in createGUI(); QString prjPath = QString::fromUtf8(qgetenv("KRAFT_HOME")); QMenu *fileMenu = menuBar()->addMenu(i18n("&File")); fileMenu->addAction(_actFileQuit); #if 0 QMenu *editMenu = menuBar()->addMenu(i18n("&Edit")); editMenu->addAction(_actEditCopy); editMenu->addAction(_actEditCut); editMenu->addAction(_actEditPaste); #endif QMenu *docMenu = menuBar()->addMenu(i18n("&Document")); docMenu->addAction(_actViewDocument); if (!_readOnlyMode) docMenu->addAction(_actOpenDocument); docMenu->addAction(_actOpenArchivedDocument); docMenu->addAction(_actXRechnung); if (!_readOnlyMode) { docMenu->addSeparator(); docMenu->addAction(_actNewDocument); docMenu->addAction(_actCopyDocument); docMenu->addAction(_actFollowDocument); docMenu->addSeparator(); docMenu->addAction(_actPrintDocument); docMenu->addAction(_actMailDocument); } QToolBar *toolBar = addToolBar(i18n("Kraft")); if (!_readOnlyMode) { QMenu *prefsMenu = menuBar()->addMenu(i18n("&Preferences")); prefsMenu->addAction(_actEditTemplates); prefsMenu->addAction(_actReconfDb); prefsMenu->addSeparator(); QMenu *submen = prefsMenu->addMenu(i18n("Toolbars")); submen->addAction(toolBar->toggleViewAction()); prefsMenu->addSeparator(); prefsMenu->addAction(_actPreferences); } QMenu *helpMenu = menuBar()->addMenu(i18n("&Help")); helpMenu->addAction(_actHandbook); helpMenu->addSeparator(); helpMenu->addAction(_actAboutKraft); helpMenu->addAction(_actAboutQt); // Toolbar toolBar->setObjectName("PortalToolbar"); if (!_readOnlyMode) { toolBar->addAction(_actNewDocument); toolBar->addAction(_actCopyDocument); toolBar->addAction(_actFollowDocument); toolBar->addAction(_actPrintDocument); toolBar->addAction(_actMailDocument); } else { toolBar->addAction(_actOpenArchivedDocument); toolBar->addAction(_actXRechnung); toolBar->addAction(_actViewDocument); } // initial enablements _actEditCut->setEnabled(false); _actEditCopy->setEnabled(false); _actEditPaste->setEnabled(false); } void Portal::initView() { /* Since we do the database version check in the slotStartupChecks, we can not do database interaction here in initView. */ //////////////////////////////////////////////////////////////////// // create the main widget here that is managed by KTMainWindow's view-region and // connect the widget to your document to display document contents. m_portalView.reset(new PortalView( this, "PortalMainView" )); QVector menus = m_portalView->docDigestView()->contextMenus(); foreach( QMenu *menu, menus ) { menu->setTitle( i18n("Document Actions")); menu->addSection(i18n("Document Actions")); menu->addAction( _actViewDocument ); if (!_readOnlyMode) menu->addAction( _actOpenDocument ); menu->addAction( _actOpenArchivedDocument ); menu->addAction( _actXRechnung); if (!_readOnlyMode) { menu->addSeparator(); menu->addAction( _actNewDocument ); menu->addAction( _actCopyDocument ); menu->addAction( _actFollowDocument ); menu->addSeparator(); menu->addAction( _actPrintDocument ); menu->addAction( _actMailDocument ); } } connect( m_portalView.data(), SIGNAL(openKatalog( const QString&)), this, SLOT(slotOpenKatalog(const QString&))); connect( m_portalView.data(), SIGNAL(katalogToXML(const QString& )), this, SLOT(slotKatalogToXML(const QString&))); // document related connections connect( m_portalView.data(), SIGNAL( createDocument() ), this, SLOT( slotNewDocument() ) ); connect( m_portalView.data(), SIGNAL( copyDocument( const QString& ) ), this, SLOT( slotCopyDocument( const QString& ) ) ); connect( m_portalView.data(), SIGNAL( openDocument( const QString& ) ), this, SLOT( slotOpenDocument( const QString& ) ) ); connect( m_portalView.data(), SIGNAL( viewDocument( const QString& ) ), this, SLOT( slotViewDocument( const QString& ) ) ); connect( m_portalView.data(), SIGNAL( openArchivedDocument( const ArchDocDigest& ) ), this, SLOT( slotOpenArchivedDoc( const ArchDocDigest& ) ) ); connect( m_portalView.data(), &PortalView::exportXRechnungArchivedDocument, this, &Portal::slotExportXRechnungArchivedDoc); connect( m_portalView.data(), &PortalView::documentSelected, this, &Portal::slotDocumentSelected); connect( m_portalView.data(), SIGNAL( archivedDocSelected( const ArchDocDigest& ) ), this, SLOT( slotArchivedDocSelected( const ArchDocDigest& ) ) ); setCentralWidget(m_portalView.data()); } void Portal::slotStartupChecks() { const QString dbName = DatabaseSettings::self()->dbDatabaseName(); SetupAssistant assi(this); if( assi.init( SetupAssistant::Update) ) { if (_readOnlyMode) { // Update not under our control here. QMessageBox::warning(this, i18n("Database not running"), i18n("Kraft was started in readonly mode, but the configured " "database can not be connected.\n\nKraft will abort.")); QTimer::singleShot(500, this, [this] { close(); }); return; } else { assi.exec(); } } if( ! KraftDB::self()->isOk() ) { QSqlError err = KraftDB::self()->lastError(); // qDebug () << "The last sql error id: " << err.type(); QString text; if ( err.text().contains( "Can't connect to local MySQL server through socket" ) ) { text = i18n( "Kraft can not connect to the specified MySQL server. " "Please check the Kraft database settings, check if the server is " "running and verify if a database with the name %1 exits!" , dbName ); } else if ( err.text().contains( "Unknown database '" + dbName + "' QMYSQL3: Unable to connect" ) ) { text = i18n( "The database with the name %1 does not exist on the database server. " "Please make sure the database exists and is accessible by the user " "running Kraft.", dbName ); } else if ( err.text().contains( "Driver not loaded" ) ) { text = i18n( "The Qt database driver could not be loaded. That probably means, that " "they are not installed. Please make sure the Qt database packages are " "installed and try again." ); } else { text = i18n( "There is a database problem: %1", err.text() ); } m_portalView->systemInitError( m_portalView->ptag( text, "problem" ) ); // disable harmfull actions if( !_readOnlyMode) { _actNewDocument->setEnabled( false ); _actCopyDocument->setEnabled( false ); _actFollowDocument->setEnabled(false); _actOpenDocument->setEnabled( false ); } _actViewDocument->setEnabled( false ); _actPrintDocument->setEnabled( false ); _actOpenArchivedDocument->setEnabled( false ); _actXRechnung->setEnabled(false); _actMailDocument->setEnabled( false ); slotStatusMsg( i18n( "Database Problem." ) ); } else { // if readonly, enable the change polling on the db if (_readOnlyMode) { KraftDB::self()->enableTimerRefresh(true); } // Database interaction is ok after this point. m_portalView->slotBuildView(); m_portalView->fillCatalogDetails(); m_portalView->fillSystemDetails(); slotStatusMsg( i18n( "Check commandline actions" ) ); if ( mCmdLineArgs ) { const QString docId = mCmdLineArgs->value("d"); if ( ! docId.isEmpty() ) { // qDebug () << "open a archived document: " << docId; slotPrintDocument( QString(), dbID( docId.toInt() ) ); } } // Fetch my address const QString myUid = KraftSettings::self()->userUid(); bool useManual = false; if( ! myUid.isEmpty() ) { KContacts::Addressee contact; // qDebug () << "Got My UID: " << myUid; connect( mAddressProvider, SIGNAL( lookupResult(QString,KContacts::Addressee)), this, SLOT( slotReceivedMyAddress(QString, KContacts::Addressee)) ); AddressProvider::LookupState state = mAddressProvider->lookupAddressee( myUid ); switch( state ) { case AddressProvider::LookupFromCache: contact = mAddressProvider->getAddresseeFromCache(myUid); slotReceivedMyAddress(myUid, contact); break; case AddressProvider::LookupNotFound: case AddressProvider::ItemError: case AddressProvider::BackendError: // Try to read from stored vcard. useManual = true; break; case AddressProvider::LookupOngoing: case AddressProvider::LookupStarted: // Not much to do, just wait break; } } else { // in case there is no uid in the settings file, try to use the manual address. useManual = true; } if( useManual ) { // check if the vcard can be read QString file = QStandardPaths::writableLocation( QStandardPaths::AppDataLocation ); file += "/myidentity.vcd"; QFile f(file); if( f.exists() ) { if( f.open( QIODevice::ReadOnly )) { const QByteArray data = f.readAll(); VCardConverter converter; Addressee::List list = converter.parseVCards( data ); if( list.count() > 0 ) { KContacts::Addressee c = list.at(0); c.insertCustom(CUSTOM_ADDRESS_MARKER, "manual"); slotReceivedMyAddress(QString(), c); } } } } connect( &_reportGenerator, &ReportGenerator::docAvailable, this, &Portal::slotDocConverted); connect( &_reportGenerator, &ReportGenerator::failure, this, &Portal::slotDocConvertionFail); } } void Portal::slotReceivedMyAddress( const QString& uid, const KContacts::Addressee& contact ) { disconnect( mAddressProvider, SIGNAL(lookupResult(QString,KContacts::Addressee)), this, SLOT(slotReceivedMyAddress(QString, KContacts::Addressee))); if( contact.isEmpty() ) { if( !uid.isEmpty() ) { // FIXME: Read the stored Address and compare the uid const QString err = mAddressProvider->errorMsg(uid); qDebug () << "My-Contact could not be found:" << err; } return; } myContact = contact; // qDebug () << "Received my address: " << contact.realName() << "(" << uid << ")"; _reportGenerator.setMyContact( myContact ); QString name = myContact.formattedName(); if( !name.isEmpty() ) { name = i18n("Welcome to Kraft, %1", name); statusBar()->showMessage(name, 30*1000); } } bool Portal::queryClose() { return true; } bool Portal::queryExit() { return true; } ///////////////////////////////////////////////////////////////////// // SLOT IMPLEMENTATION ///////////////////////////////////////////////////////////////////// void Portal::busyCursor( bool on ) { if ( on ) { QApplication::setOverrideCursor( QCursor( Qt::BusyCursor ) ); } else { QApplication::restoreOverrideCursor(); } } void Portal::slotNewDocument() { slotStatusMsg(i18n("Creating new document...")); KraftWizard wiz; wiz.init(true); if ( wiz.exec() ) { DocumentMan *docman = DocumentMan::self(); DocGuardedPtr doc = docman->createDocument( wiz.docType() ); doc->setDate( wiz.date() ); doc->setAddressUid( wiz.addressUid() ); doc->setWhiteboard( wiz.whiteboard() ); createView( doc ); } slotStatusMsg(); } void Portal::slotFollowUpDocument() { const QString locId = m_portalView->docDigestView()->currentDocumentId(); DocGuardedPtr sourceDoc = DocumentMan::self()->openDocument( locId ); DocType dt( sourceDoc->docType() ); KraftWizard wiz; wiz.init( false, i18nc("Dialog title of the followup doc dialog, followed by the id of the source doc", "Create follow up document for %1", sourceDoc->ident())); QStringList followers = dt.follower(); if ( followers.count() > 0 ) { // only if there are currently followers defined, if not the default wiht // all doc types works. wiz.setAvailDocTypes( dt.follower() ); } // qDebug () << "doc identifier: "<< doc->docIdentifier(); wiz.setDocToFollow( sourceDoc ); DocPositionList posToCopy; delete sourceDoc; if ( wiz.exec() ) { QString selectedId = wiz.copyItemsFromPredecessor(); if(!selectedId.isEmpty()) { DocGuardedPtr copyDoc = DocumentMan::self()->openDocument( selectedId ); posToCopy = copyDoc->positions(); delete copyDoc; } DocGuardedPtr doc = DocumentMan::self()->createDocument(wiz.docType(), locId, posToCopy); doc->setDate( wiz.date() ); doc->setWhiteboard( wiz.whiteboard() ); createView( doc ); } } void Portal::slotCopyCurrentDocument() { const QString locId = m_portalView->docDigestView()->currentDocumentId(); slotCopyDocument( locId ); } void Portal::slotCopyDocument( const QString& id ) { if ( id.isEmpty() ) { return; } QString oldDocIdent; DocGuardedPtr oldDoc = DocumentMan::self()->openDocument( id ); if(oldDoc) { const DocType dt = oldDoc->docType(); oldDocIdent = i18nc("Title of the new doc dialog, %1 is the source doc id", "Create new Document as Copy of %1", oldDoc->ident()); delete oldDoc; } KraftWizard wiz; wiz.init(true, oldDocIdent); if ( wiz.exec() ) { DocGuardedPtr doc = DocumentMan::self()->copyDocument(id); doc->setDate( wiz.date() ); doc->setDocType( wiz.docType() ); doc->setWhiteboard( wiz.whiteboard() ); if(doc->addressUid() != wiz.addressUid() ) { doc->setAddress(QString()); } doc->setAddressUid( wiz.addressUid() ); doc->saveDocument(); m_portalView->docDigestView()->slotUpdateView(); // qDebug () << "Document created from id " << id << ", saved with id " << doc->docID().toString(); } } void Portal::slotOpenCurrentDocument() { QString locId = m_portalView->docDigestView()->currentDocumentId(); slotOpenDocument( locId ); } void Portal::slotViewCurrentDocument() { QString locId = m_portalView->docDigestView()->currentDocumentId(); slotViewDocument( locId ); } void Portal::slotViewDocument( const QString& id ) { slotStatusMsg(i18n("Opening document to view...")); if( !id.isEmpty() ) { DocumentMan *docman = DocumentMan::self(); DocGuardedPtr doc = docman->openDocument( id ); createROView( doc ); } slotStatusMsg(); } void Portal::slotXRechnungCurrentDocument() { // qDebug () << "printing document " << locId; ArchDocDigest dig = m_portalView->docDigestView()->currentLatestArchivedDoc(); slotExportXRechnungArchivedDoc(dig); } void Portal::slotExportXRechnungArchivedDoc(const ArchDocDigest& d) { ExporterXRechnung *exporter = new ExporterXRechnung; const QString tmplFile = exporter->templateFile(); QString err; if (tmplFile.isEmpty()) { err = i18n("XRechnung Template file not set. Please check the application settings!"); } else { QFileInfo fi(tmplFile); if (!fi.isFile()) { err = i18n("The XRechnung template file can not be read!"); } } if (!err.isEmpty()) { QMessageBox::warning(this, i18n("XRechnung Export"), err); delete exporter; return; } auto dia = new QDialog(this); Ui::XRechnungDialog ui; ui.setupUi(dia); QDate today = QDate::currentDate(); ui._dueDateEdit->setDate(today.addDays(21)); ui._buyerRefEdit->setText("unknown"); if (dia->exec() == QDialog::Accepted) { exporter->setDueDate(ui._dueDateEdit->date()); exporter->setBuyerRef(ui._buyerRefEdit->text()); connect(exporter, &ExporterXRechnung::xRechnungTmpFile, this, [=](const QString& fName) { qDebug() << "This is the xrechnung file name." << fName; const QString proposeName = QString("%1/xrechnung_%2.xml").arg(QDir::homePath()).arg(d.archDocIdent()); const QString f = QFileDialog::getSaveFileName(this, i18n("Save XRechnung"), proposeName); QFile::copy(fName, f); this->slotStatusMsg(i18n("Saved XRechnung to %1").arg(f)); exporter->deleteLater(); }); exporter->exportDocument(d); } } void Portal::slotOpenArchivedDoc( const ArchDocDigest& d ) { busyCursor( true ); ArchDocDigest digest( d ); const QString file = d.pdfArchiveFileName(); // qDebug () << "archived doc selected: " << file; slotOpenPdf( file ); busyCursor( false ); } QDebug operator<<(QDebug debug, const dbID &id) { QDebugStateSaver saver(debug); debug.nospace().noquote() << id.toString(); return debug; } void Portal::slotPrintCurrentDocument() { QString locId = m_portalView->docDigestView()->currentDocumentId(); // qDebug () << "printing document " << locId; busyCursor( true ); slotStatusMsg( i18n( "Generating PDF..." ) ); DocumentMan *docman = DocumentMan::self(); _currentDoc = docman->openDocument( locId ); QString ident; if ( _currentDoc ) { ident = _currentDoc->ident(); dbID archID = KraftDB::self()->archiveDocument(_currentDoc); Q_ASSERT(archID.isOk()); slotPrintDocument( ident, archID ); // m_portalView->docDigestView()->addArchivedItem(docPtr->docID(), archID); } busyCursor( false ); slotStatusMsg( i18n( "Ready." ) ); } void Portal::slotMailDocument() { const QString locId = m_portalView->docDigestView()->currentDocumentId(); // qDebug () << "Mailing document " << locId; slotStatusMsg( i18n( "Generating PDF for EMail" ) ); DocumentMan *docman = DocumentMan::self(); DocGuardedPtr docPtr = docman->openDocument( locId ); QString ident; if ( docPtr ) { ident = docPtr->ident(); dbID archID = KraftDB::self()->archiveDocument( docPtr ); busyCursor( true ); _reportGenerator.createDocument(ReportFormat::PDFMail, ident, archID ); busyCursor( false ); } slotStatusMsg( i18n( "Ready." ) ); } void Portal::slotDocConvertionFail(const QString& failString, const QString& details) { QMessageBox::warning(this, i18n("Doc Generation Error"), failString + "\n\n"+details); } void Portal::slotDocConverted(ReportFormat format, const QString& file, const KContacts::Addressee& customerContact) { if (format == ReportFormat::PDF) { slotOpenPdf(file); } else if (format == ReportFormat::PDFMail) { openInMailer(file, customerContact); } } void Portal::openInMailer(const QString& fileName, const KContacts::Addressee& contact) { QString mailReceiver; if( !contact.isEmpty() ) { mailReceiver = contact.fullEmail(); // the prefered email } QStringList args; QString prog; // Use from system, we will not deliver them in an AppImage if( KraftSettings::self()->mailUA().startsWith("xdg") ) { args.append( "--utf8"); args.append( "--attach"); args.append(fileName); if( !mailReceiver.isEmpty() ) { args.append( mailReceiver); } prog = QLatin1String("/usr/bin/xdg-email"); } else { // Fallback to thunderbird prog = QLatin1String("/usr/bin/thunderbird"); args.append("-compose"); QString tmp; if( !mailReceiver.isEmpty() ) { tmp = QString("to=%1,").arg(mailReceiver); } tmp += QString("attachment='file://%1'").arg(fileName); args.append(tmp); } qDebug () << "Starting mailer: " << prog << args; if (!QProcess::startDetached(prog, args)) { qDebug () << "Failed to start thunderbird composer!"; } } /* * id : document ID * archID: database ID of archived document */ void Portal::slotPrintDocument( const QString& id, const dbID& archID ) { if ( archID.isOk() ) { slotStatusMsg(i18n("Printing archived document...") ); _reportGenerator.createDocument(ReportFormat::PDF, id, archID ); // work on document identifier. } } void Portal::slotOpenPdf( const QString& fileName ) { QUrl url( fileName ); QDesktopServices::openUrl(url); } /* * A special document tree is built up here. */ void Portal::savePdfInCustomerStructure(const QString& fileName) { // save pdf into a / structure if( _currentDoc ) { QString uid = _currentDoc->addressUid(); QString docType = _currentDoc->docType(); if( !uid.isEmpty() ) { QString outputDir = KraftSettings::self()->pdfOutputDir(); if ( outputDir.isEmpty() ) { outputDir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); } if ( ! outputDir.endsWith( "/" ) ) outputDir += QLatin1String("/"); QDir customerDir(outputDir + QString("%1/%2").arg(uid).arg(docType)); if( !customerDir.exists() ) { customerDir.mkpath( customerDir.absolutePath()); } if( customerDir.exists() ) { QFileInfo fi(fileName); QString target = customerDir.canonicalPath() + QLatin1Char('/') + fi.fileName(); QFileInfo tfi(target); if( tfi.exists() ) { QFile::remove(target); } QFile::copy( fileName, target ); } } } } void Portal::slotOpenDocument( const QString& id ) { if (_readOnlyMode) { slotViewDocument(id); return; } slotStatusMsg( i18n("Opening document %1", id ) ); // qDebug () << "Opening document " << id; if( !id.isEmpty() ) { DocumentMan *docman = DocumentMan::self(); DocGuardedPtr doc = docman->openDocument( id ); createView( doc ); } slotStatusMsg(); } void Portal::slotDocumentSelected( const DocDigest& doc ) { // qDebug() << "a doc was selected: " << doc; bool enable = !doc.id().isEmpty(); _actViewDocument->setEnabled( enable ); _actOpenDocument->setEnabled( (!_readOnlyMode) && enable ); _actPrintDocument->setEnabled( (!_readOnlyMode) && enable ); _actCopyDocument->setEnabled( (!_readOnlyMode) && enable ); _actMailDocument->setEnabled( (!_readOnlyMode) && enable ); _actFollowDocument->setEnabled( (!_readOnlyMode) && enable ); auto archDocs = doc.archDocDigestList(); if (archDocs.isEmpty()) { _actOpenArchivedDocument->setEnabled(false); _actXRechnung->setEnabled(false); } else { _actOpenArchivedDocument->setEnabled( enable ); ArchDocDigest archDoc = archDocs.at(0); _actXRechnung->setEnabled(archDoc.isInvoice() && enable); } } void Portal::slotArchivedDocExecuted() { ArchDocDigest dig = m_portalView->docDigestView()->currentLatestArchivedDoc(); slotOpenArchivedDoc( dig ); } void Portal::slotArchivedDocSelected( const ArchDocDigest& ) { // slotDocumentSelected( QString() ); _actOpenArchivedDocument->setEnabled( true ); _actXRechnung->setEnabled(true); _actViewDocument->setEnabled( false ); _actOpenDocument->setEnabled( false ); _actPrintDocument->setEnabled( false ); _actMailDocument->setEnabled( false ); } void Portal::slotEditTagTemplates() { TagTemplatesDialog dia( this ); if ( dia.exec() ) { // qDebug () << "Editing of tag templates succeeded!"; } } void Portal::slotReconfigureDatabase() { // qDebug () << "Reconfiguring the Database"; SetupAssistant assi(this); if( assi.init( SetupAssistant::Reinit ) ) { assi.exec(); } } void Portal::createView( DocGuardedPtr doc ) { // FIXME: We allow only one view for the first time. // Later allow one write view and other read onlys. if ( !doc ) return; // if there is a read only view already, close it and open a // editor if( mViewMap.contains(doc)) { if( (mViewMap[doc])->type() == KraftViewBase::ReadOnly ) { KraftViewBase *view = mViewMap[doc]; mViewMap.remove(doc); delete view; } } if( !mViewMap.contains(doc) ){ KraftView *view = new KraftView( this ); const QByteArray geo = QByteArray::fromBase64( KraftSettings::self()->docEditGeometry().toLatin1() ); view->restoreGeometry(geo); view->setup( doc ); view->redrawDocument(); view->slotSwitchToPage( KraftDoc::Positions ); view->show(); connect( view, SIGNAL( viewClosed( bool, DocGuardedPtr ) ), this, SLOT( slotViewClosed( bool, DocGuardedPtr ) ) ); connect( view, &KraftViewBase::openROView, this, &Portal::slotViewDocument ); mViewMap[doc] = view; } else { mViewMap[doc]->raise(); // pop first view to front // qDebug () << "There is already a view for this doc!"; } } void Portal::createROView( DocGuardedPtr doc ) { if ( !doc ) return; if( !mViewMap.contains(doc)) { KraftViewRO *view = new KraftViewRO( this ); view->setup( doc ); // view->redrawDocument(); const QByteArray geo = QByteArray::fromBase64( KraftSettings::self()->docViewROGeometry().toLatin1() ); view->restoreGeometry(geo); view->show(); mViewMap[doc] = view; connect( view, SIGNAL( viewClosed( bool, DocGuardedPtr ) ), this, SLOT( slotViewClosed( bool, DocGuardedPtr ) ) ); } else { mViewMap[doc]->raise(); } } void Portal::slotViewClosed( bool success, DocGuardedPtr doc ) { // doc is only valid on success! if ( doc ) { KraftViewBase *view = mViewMap[doc]; const QByteArray geo = view->saveGeometry().toBase64(); if( success ) { if( view->type() == KraftViewBase::ReadWrite ) { AllDocsView *dv = m_portalView->docDigestView(); dv->slotUpdateView(); KraftSettings::self()->setDocEditGeometry(geo); } else { KraftSettings::self()->setDocViewROGeometry(geo); } } if( mViewMap.contains(doc)) { mViewMap.remove(doc); view->deleteLater(); } // qDebug () << "A view was closed saving and doc is new: " << doc->isNew(); delete doc; } else { // qDebug () << "A view was closed canceled"; } } void Portal::closeEvent( QCloseEvent *event ) { slotStatusMsg(i18n("Exiting...")); // close the first window, the list makes the next one the first again. // This ensures that queryClose() is called on each window to ask for closing //We have to delete katalogviews ourself otherwise the application keeps running in the background QMap::iterator i; for (i = mKatalogViews.begin(); i != mKatalogViews.end(); ++i) { // KatalogView *view = i.value(); // qDebug () << "Windowstate" << view->windowState(); i.value()->deleteLater(); } // FIXME: Close the document windows. const QByteArray state = saveState().toBase64(); KraftSettings::self()->setPortalState(state); const QByteArray geo = saveGeometry().toBase64(); KraftSettings::self()->setPortalGeometry(geo); KraftSettings::self()->save(); if( event ) event->accept(); } void Portal::slotEditCut() { slotStatusMsg(i18n("Cutting selection...")); slotStatusMsg(); } void Portal::slotEditCopy() { slotStatusMsg(i18n("Copying selection to clipboard...")); slotStatusMsg(); } void Portal::slotEditPaste() { slotStatusMsg(i18n("Inserting clipboard contents...")); slotStatusMsg(); } void Portal::slotStatusMsg(const QString &text) { /////////////////////////////////////////////////////////////////// // change status message permanently statusBar()->clearMessage(); if (text.isEmpty()) { if (_readOnlyMode) statusBar()->showMessage(i18n("Ready. Kraft is running in read only mode. Document editing is prohibited.")); else statusBar()->showMessage(i18n("Ready.")); } else { statusBar()->showMessage(text); } } /** Show the window with floskeltemplates */ void Portal::slotShowTemplates(){ } void Portal::slotOpenKatalog(const QString& kat) { // qDebug () << "opening Katalog " << kat; if ( mKatalogViews.contains( kat ) ) { // bring up the katalog view window. // qDebug () << "Katalog " << kat << " already open in a view"; mKatalogViews.value(kat)->show(); mKatalogViews.value(kat)->raise(); } else { QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); KatalogView *katView = nullptr; if( kat == MaterialKatalogView::MaterialCatalogName ) { /* Materialkatalog */ katView = new MaterialKatalogView(); } else { /* normaler Vorlagenkatalog */ katView = new TemplKatalogView(); } if ( katView ) { // qDebug () << katView; katView->init(kat); katView->show(); mKatalogViews.insert(kat, katView); KatalogMan::self()->registerKatalogListView( kat, katView->getListView() ); } QApplication::restoreOverrideCursor(); } } void Portal::slotOpenKatalog() { // qDebug () << "opening katalog!"; KatalogView *katView = new TemplKatalogView(); //this); katView->show(); } void Portal::slotKatalogToXML(const QString& katName) { // qDebug () << "Generating XML for catalog " << katName; Katalog *kat = KatalogMan::self()->getKatalog(katName); if(kat) { kat->writeXMLFile(); } } QString Portal::textWrap( const QString& t, int width, int maxLines ) { QString re; int lines = 0; if( t.length() <= width ) { re = t; } else { int start = 0; int pos = width; while( pos < t.length() && (lines < maxLines || maxLines < 0) ) { pos = t.indexOf( QLatin1Char('\n'), start ); if( pos > -1 && (pos-start) < width ) { re += t.mid(start, pos-start)+QLatin1Char('\n'); start = pos+1; } else { pos = t.indexOf( QLatin1Char(' '), start+width ); if( pos > -1 ) { re += t.mid( start, pos-start)+QLatin1Char('\n'); start = pos+1; } else { re += t.mid( start ); pos = t.length(); } } lines++; } if( lines == maxLines && pos != t.length() ) { re += QStringLiteral("..."); } } return re; } void Portal::preferences() { _prefsDialog = new PrefsDialog(this); connect( _prefsDialog, SIGNAL(finished(int)), SLOT(slotPrefsDialogFinished(int)) ); connect( _prefsDialog, SIGNAL(newOwnIdentity(const QString&, KContacts::Addressee)), SLOT(slotReceivedMyAddress(QString,KContacts::Addressee))); _prefsDialog->setMyIdentity( myContact, mAddressProvider->backendUp() ); _prefsDialog->open(); } void Portal::slotPrefsDialogFinished( int result ) { if( result == QDialog::Accepted) { } _prefsDialog->deleteLater(); } void Portal::slotHandbook() { QUrl url; QLocale *loc = DefaultProvider::self()->locale(); QString hbLocale; if (loc) { hbLocale = loc->bcp47Name(); } // find the localized version QString hbFile = DefaultProvider::self()->locateFile(QString("manual/kraft-%1.html").arg(hbLocale)); // if not found, fall back to the english manual QFileInfo fi(hbFile); if (hbFile.isEmpty() || !fi.exists()) { hbFile = DefaultProvider::self()->locateFile(QStringLiteral("manual/kraft-en.html")); } if( !hbFile.isEmpty() ) { url = QUrl::fromLocalFile(hbFile); qDebug() << "opening manual url" << url.toString(); } if (!url.isEmpty()) { QDesktopServices::openUrl(url); } } void Portal::slotAboutQt() { QApplication::aboutQt(); } void Portal::slotAboutKraft() { m_portalView->displaySystemsTab(); } QWidget* Portal::mainWidget() { return m_portalView.data(); } kraft-1.1/src/portal.h000066400000000000000000000142021450127457600147350ustar00rootroot00000000000000/*************************************************************************** portal.h - Portal view for Kraft ------------------- begin : Mar 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef PORTAL_H #define PORTAL_H // include files for Qt #include #include #include #include #include #include "docguardedptr.h" #include "katalogview.h" #include "dbids.h" #include "portalview.h" #include "reportgenerator.h" class KraftViewBase; class ArchDocDigest; class AddressProvider; class PrefsDialog; /** */ class Portal : public QMainWindow { Q_OBJECT friend class KraftView; public: /** construtor of Portal, calls all init functions to create the application. */ Portal( QWidget* parent = 0, QCommandLineParser *commandLineParser = 0, const char* name = 0); static QString textWrap(const QString& t, int width=40, int maxLines = -1 ); QWidget* mainWidget(); protected: /** initializes the QActions of the application */ void initActions(); /** creates the centerwidget of the KTMainWindow instance and sets it as the view */ void initView(); /** queryClose is called by KTMainWindow on each closeEvent of a window. Against the * default implementation (only returns true), this calles saveModified() on the document object to ask if the document shall * be saved if Modified; on cancel the closeEvent is rejected. * @see KTMainWindow#queryClose * @see KTMainWindow#closeEvent */ virtual bool queryClose(); /** queryExit is called by KTMainWindow when the last window of the application is going to be closed during the closeEvent(). * Against the default implementation that just returns true, this calls saveOptions() to save the settings of the last window's * properties. * @see KTMainWindow#queryExit * @see KTMainWindow#closeEvent */ virtual bool queryExit(); protected slots: void slotStartupChecks(); void slotOpenArchivedDoc( const ArchDocDigest& ); void slotExportXRechnungArchivedDoc(const ArchDocDigest&); void slotXRechnungCurrentDocument(); void slotPrefsDialogFinished( int ); void slotDocConverted(ReportFormat format, const QString& file, const KContacts::Addressee& customerContact); void slotDocConvertionFail(const QString& failString, const QString &details); void openInMailer(const QString& fileName, const KContacts::Addressee& contact); public slots: /** closes all open windows, then quits the application. */ void closeEvent( QCloseEvent * event ); /** put the marked text/object into the clipboard and remove * it from the document */ void slotEditCut(); /** put the marked text/object into the clipboard */ void slotEditCopy(); /** paste the clipboard into the document */ void slotEditPaste(); /** changes the statusbar contents for the standard label permanently, used to indicate current actions. * @param text the text that is displayed in the statusbar */ void slotStatusMsg(const QString &text = QString()); /** Show the window with floskeltemplates */ void slotShowTemplates(); void slotOpenKatalog(const QString& ); void slotOpenKatalog(); void slotKatalogToXML(const QString&); void preferences(); void slotNewDocument(); void slotCopyCurrentDocument(); void slotCopyDocument( const QString& ); void slotOpenDocument( const QString& ); void slotOpenCurrentDocument(); void slotViewCurrentDocument(); void slotViewDocument( const QString& ); void slotFollowUpDocument(); void slotDocumentSelected( const DocDigest& ); void slotArchivedDocExecuted(); void slotArchivedDocSelected( const ArchDocDigest& ); void slotPrintCurrentDocument(); void slotPrintDocument( const QString&, const dbID& ); void slotViewClosed( bool, DocGuardedPtr ); void slotEditTagTemplates(); void slotReconfigureDatabase(); void slotAboutQt(); void slotAboutKraft(); void slotHandbook(); void busyCursor( bool ); void slotMailDocument(); void slotOpenPdf( const QString& ); void slotReceivedMyAddress( const QString&, const KContacts::Addressee& ); private: void createView( DocGuardedPtr ); void createROView( DocGuardedPtr ); void savePdfInCustomerStructure(const QString& fileName); QScopedPointer m_portalView; // QAction pointers to enable/disable actions QAction* _actFileQuit; QAction* _actEditCut; QAction* _actEditCopy; QAction* _actEditPaste; QAction* _actAboutQt; QAction* _actAboutKraft; QAction* _actHandbook; QAction* _actPreferences; QAction* _actReconfDb; QAction* _actNewDocument; QAction* _actCopyDocument; QAction* _actOpenDocument; QAction* _actViewDocument; QAction* _actFollowDocument; QAction* _actPrintDocument; QAction* _actMailDocument; QAction* _actXRechnung; QAction* _actEditTemplates; QAction* _actOpenArchivedDocument; QAction* _actViewFlosTemplates; QCommandLineParser *mCmdLineArgs; QMap mKatalogViews; QMap mViewMap; AddressProvider *mAddressProvider; KContacts::Addressee myContact; PrefsDialog *_prefsDialog; DocGuardedPtr _currentDoc; ReportGenerator _reportGenerator; bool _readOnlyMode; }; #endif kraft-1.1/src/portalhtmlview.cpp000066400000000000000000000032271450127457600170550ustar00rootroot00000000000000/*************************************************************************** portalhtmlview.cpp - show a html page in the portal ------------------- begin : Jan 2007 copyright : (C) 2007 Klaas Freitag ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "portalhtmlview.h" #include #include PortalHtmlView::PortalHtmlView( QWidget *parent ) : HtmlView( parent ) { connect( this, SIGNAL(openUrl(QUrl)), this, SLOT(slotLinkClicked(QUrl))); } void PortalHtmlView::slotLinkClicked(const QUrl& url) { QUrlQuery q(url); const QString katName = q.queryItemValue(QLatin1String("kat")); const QString action = q.queryItemValue(QLatin1String("action")); if ( action == QLatin1String("open") ) { // qDebug () << "open catalog " << katName; emit( openCatalog( katName ) ); } else { if( url.isValid() ) { QDesktopServices::openUrl(url); } } } kraft-1.1/src/portalhtmlview.h000066400000000000000000000024121450127457600165150ustar00rootroot00000000000000 /*************************************************************************** portalhtmlview.h - show a html page in the portal ------------------- begin : Jan 2007 copyright : (C) 2007 Klaas Freitag ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef PORTALHTMLVIEW_H #define PORTALHTMLVIEW_H #include "htmlview.h" class PortalHtmlView : public HtmlView { Q_OBJECT public: PortalHtmlView( QWidget *parent ); signals: void openCatalog( const QString& ); protected slots: void slotLinkClicked(const QUrl& url); }; #endif kraft-1.1/src/portalview.cpp000066400000000000000000000405001450127457600161630ustar00rootroot00000000000000/*************************************************************************** portalview.cpp - the main portal class ------------------- begin : 2004-05-09 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include #include #include #include #include #include "version.h" #include "kraftdb.h" #include "portalview.h" #include "portalhtmlview.h" #include "katalogman.h" #include "alldocsview.h" #include "documentman.h" #include "defaultprovider.h" #include "reportgenerator.h" #include "texttemplate.h" #include "format.h" PortalView::PortalView(QWidget *parent, const char*) : QWidget( parent ), _allDocsView(nullptr), mCatalogBrowser(nullptr), mSystemBrowser(nullptr) { const QSize iSize{64,64}; _contentsWidget = new QListWidget(this); _contentsWidget->setViewMode(QListView::IconMode); _contentsWidget->setIconSize(iSize); _contentsWidget->setMovement(QListView::Static); _contentsWidget->setMaximumWidth(132); _contentsWidget->setSpacing(0); _pagesWidget = new QStackedWidget(this); _pagesWidget->addWidget(documentDigests()); _pagesWidget->addWidget(new QWidget()); // doc timeline _pagesWidget->addWidget(katalogDetails()); // catalogs _sysPageIndx = _pagesWidget->addWidget(systemDetails()); // system createIcons(iSize); _contentsWidget->setCurrentRow(0); QHBoxLayout *horizontalLayout = new QHBoxLayout; QVBoxLayout *vbox = new QVBoxLayout; vbox->addWidget(_contentsWidget); QPushButton *pb = new QPushButton(i18n("About Kraft")); pb->setIcon(DefaultProvider::self()->icon("kraft-simple")); vbox->addWidget(pb); connect(pb, &QPushButton::clicked, this, &PortalView::displaySystemsTab); horizontalLayout->addLayout(vbox); horizontalLayout->addWidget(_pagesWidget, 1); setLayout(horizontalLayout); } PortalView::~PortalView( ) { } void PortalView::createIcons(const QSize& iconSize) { QSize sHint{128, 100}; // Scale the icon via a pixmap, as in AppImages, for some reasons the icons are small // stackoverflow reports that svg icons can not be scaled up. auto icon = [iconSize](const QIcon& i) { const QPixmap pix = i.pixmap(iconSize); QIcon icon(pix); QList sizes = icon.availableSizes(); qDebug() << "III" << sizes; return icon; }; QListWidgetItem *documentsButton = new QListWidgetItem(_contentsWidget); documentsButton->setIcon(icon(DefaultProvider::self()->icon("file-description"))); documentsButton->setText(i18n("Documents")); documentsButton->setTextAlignment(Qt::AlignHCenter); documentsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); documentsButton->setSizeHint(sHint); QListWidgetItem *timeLineButton = new QListWidgetItem(_contentsWidget); timeLineButton->setIcon(icon(DefaultProvider::self()->icon("file-chart"))); timeLineButton->setText(i18n("Timeline")); timeLineButton->setTextAlignment(Qt::AlignHCenter); timeLineButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); timeLineButton->setSizeHint(sHint); QListWidgetItem *catButton = new QListWidgetItem(_contentsWidget); catButton->setIcon(icon(DefaultProvider::self()->icon("book"))); catButton->setText(i18n("Catalogs")); catButton->setTextAlignment(Qt::AlignHCenter); catButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); catButton->setSizeHint(sHint); connect( _contentsWidget, &QListWidget::itemClicked, this, &PortalView::changePage); } void PortalView::changePage(QListWidgetItem *current) { if (!current) return; int indx = _contentsWidget->row(current); if( indx == 0 ) { // the flat documents list _allDocsView->setView( AllDocsView::FlatList ); } else if( indx == 1 ) { // the timeline _allDocsView->setView( AllDocsView::TreeView ); indx = 0; } _pagesWidget->setCurrentIndex(indx); } void PortalView::displaySystemsTab() { _pagesWidget->setCurrentIndex(_sysPageIndx); } QWidget* PortalView::katalogDetails() { QWidget *w = new QWidget; QBoxLayout *b = new QHBoxLayout; w->setLayout( b ); mCatalogBrowser = new PortalHtmlView( w ); mCatalogBrowser->setTitle( i18n( "Kraft Document Overview" ) ); mCatalogBrowser->setStylesheetFile( "catalogview.css" ); b->addWidget( mCatalogBrowser ); QString html; html = "

            " + i18n("Available Catalogs") + "

            "; html += "
            \n"; html += i18n( "No catalogs available." ); html += "
            "; mCatalogBrowser->displayContent( html ); connect( mCatalogBrowser, SIGNAL( openCatalog( const QString& ) ), SIGNAL( openKatalog( const QString& ) ) ); return w; } void PortalView::fillCatalogDetails() { if ( ! mCatalogBrowser ) return; const QStringList katalogNamen = KatalogMan::self()->allKatalogNames(); QString html; html = QStringLiteral("

            ") + i18n("Available Catalogs") + QStringLiteral("

            "); html += QStringLiteral("
            \n"); int cnt = 0; for(QStringList::ConstIterator namesIt = katalogNamen.begin(); namesIt != katalogNamen.end(); ++namesIt ) { QString katName = *namesIt; html += printKatLine( katName, cnt++ ); } html += QStringLiteral("
            \n"); mCatalogBrowser->displayContent( html ); } QString PortalView::printKatLine( const QString& name, int cnt ) const { QString urlName = name.toHtmlEscaped(); // qDebug () << "Converted Katalog name: " << urlName; QString html; html += "
            "+urlName+"
            "; html += ""; html += i18n("Open"); html += ""; KatalogMan::CatalogDetails details = KatalogMan::self()->catalogDetails(name); html += "%1").arg(i18n("No templates yet.")); } else { const QString dateStr = Format::toDateString(details.maxModDate.date(), Format::DateFormatGerman); html += QString("") + i18n("%1 templates in %2 chapters
            last modified at %3", details.countEntries, details.countChapters, dateStr) + QLatin1String(""); } html += "\n"; return html; } QString PortalView::ptag( const QString& content, const QString& c ) const { QString html( "setLayout( b ); mSystemBrowser = new PortalHtmlView( w ); b->addWidget( mSystemBrowser ); mSystemBrowser->setStylesheetFile( "systemview.css" ); return w; } QString PortalView::systemView( const QString& htmlMsg ) const { if ( ! mSystemBrowser ) return QString (""); const QString templateName = ( htmlMsg.isNull() ? QString( "views/systemviewdetails.thtml" ) : QString ( "views/systemviewerror.thtml" ) ); const QString tmplFile = DefaultProvider::self()->locateFile( templateName ); // Note: This code is stolen from DocDigestDetailView::slotShowDocDetails // It should be refactored. TextTemplate tmpl; tmpl.setTemplateFileName(tmplFile); if( !tmpl.isOk() ) { return QString (""); } const QString logoFile = DefaultProvider::self()->locateFile("styles/pics/kraftapp_logo_trans.png" ); tmpl.setValue( "KRAFT_LOGO_FILE", logoFile ); tmpl.setValue( "KRAFT_WEBSITE", i18n( "Kraft Website" ) ); QDate d = QDate::currentDate(); tmpl.setValue( "KRAFT_COPYRIGHT_YEAR", QString::number(d.year()) ); tmpl.setValue( "KRAFT_LICENSE_TEXT", i18nc("The string is followed by a link to the GPL2 text", "Kraft is free software licensed under the")); tmpl.setValue( "KRAFT_GITHUB", i18nc("The string is followed by the link to github", "Kraft is maintained on ")); tmpl.setValue( "KRAFT_AUTHORS", i18n("Authors")); tmpl.setValue( "KRAFT_MAINTAINER", i18n("Developer and Maintainer")); tmpl.setValue( "KRAFT_DEVELOPER", i18n("Developer")); tmpl.setValue( "KRAFT_GRAPHICS", i18nc("The person who provided the logo graphics", "Logo design")); tmpl.setValue( "KRAFT_MANUAL", i18nc("The person who provided the user manual", "User Manual")); // kraft infos tmpl.setValue("KRAFT_INTRO_DESC", i18n("Kraft helps you to handle documents like quotes and invoices in your small business.")); tmpl.setValue( "KRAFT_WELCOME_LABEL", i18n( "Welcome to Kraft" ) ); tmpl.setValue( "KRAFT_VERSION_LABEL", i18n( "Kraft Version" ) ); tmpl.setValue( "KRAFT_VERSION", Kraft::Version::number()); tmpl.setValue( "KRAFT_CODENAME_LABEL", i18n( "Codename" ) ); tmpl.setValue( "KRAFT_CODENAME", Kraft::Version::codeName() ); // string like // git sha on branch built on () tmpl.setValue( "GIT_BRANCH", Kraft::Version::gitBranch()); tmpl.setValue( "GIT_SHA1", Kraft::Version::gitSha()); tmpl.setValue( "BUILD_HOST", Kraft::Version::buildHost()); tmpl.setValue( "BUILD_HOST_DISTRO", Kraft::Version::buildHostDistro()); tmpl.setValue( "GIT_BUILD_LABEL", i18n("Git Information")); tmpl.setValue( "GIT_BUILD_STRING", QString("git sha %1 on branch %2 built on %3 (%4)") .arg(Kraft::Version::gitSha()) .arg(Kraft::Version::gitBranch()) .arg(Kraft::Version::buildHost()) .arg(Kraft::Version::buildHostDistro())); const QString countryName = DefaultProvider::self()->locale()->nativeCountryName(); tmpl.setValue( "COUNTRY_SETTING_LABEL", i18n( "Country Setting" ) ); tmpl.setValue( "COUNTRY_SETTING", QString( "%1 (%2)" ).arg( countryName ).arg( DefaultProvider::self()->locale()->country() )); const QString languageName = DefaultProvider::self()->locale()->nativeLanguageName(); tmpl.setValue( "LANGUAGE_SETTING_LABEL", i18n( "Language Setting" ) ); tmpl.setValue( "LANGUAGE_SETTING", QString( "%1 (%2)" ).arg( languageName ).arg( DefaultProvider::self()->locale()->language() )); if ( !htmlMsg.isNull() ) { tmpl.setValue( "ERROR_TITLE_LABEL", i18n( "Kraft Initialisation Problem" ) ); QString errorMessage = i18n( "There is a initialisation error on your system. Kraft will not work that way." ); errorMessage += htmlMsg; tmpl.setValue( "ERROR_TEXT", errorMessage ); return tmpl.expand(); } // database infos tmpl.setValue( "DATABASE_TITLE_LABEL", i18n( "Database Information" ) ); tmpl.setValue( "DATABASE_NAME_LABEL", i18n( "Kraft database name" ) ); tmpl.setValue( "DATABASE_NAME", KraftDB::self()->databaseName() ); QString schemaVersion = QString::number( KraftDB::self()->currentSchemaVersion() ); if ( KraftDB::self()->currentSchemaVersion() != Kraft::Version::dbSchemaVersion() ) { schemaVersion += " - " + QString( "%1: %2" ).arg( i18n ( "Required Version" )) .arg( Kraft::Version::dbSchemaVersion() ); } tmpl.setValue( "DATABASE_SCHEMA_VERSION_LABEL", i18n( "Database schema version" ) ); tmpl.setValue( "DATABASE_SCHEMA_VERSION", schemaVersion ); tmpl.setValue( "DATABASE_DRIVER_LABEL", i18n( "Qt database driver" ) ); tmpl.setValue( "DATABASE_DRIVER", KraftDB::self()->qtDriver() ); bool dbOk = KraftDB::self()->getDB()->isOpen(); const QString databaseConnection = ( dbOk ? i18n("established") : QString( "%1" ).arg( i18n( "NOT AVAILABLE!" ) ) ); tmpl.setValue( "DATABASE_CONNECTION_LABEL", i18n( "Database connection" ) ); tmpl.setValue( "DATABASE_CONNECTION", databaseConnection ); if( dbOk ) { QSqlQuery q("SHOW VARIABLES like 'version';"); if( q.isActive() ) { q.next(); const QString version = q.value(1).toString(); tmpl.createDictionary("DATABASE_VERSION_SECTION"); tmpl.setValue( "DATABASE_VERSION_SECTION", "DATABASE_VERSION_LABEL", i18n( "Database Version" ) ); tmpl.setValue( "DATABASE_VERSION_SECTION", "DATABASE_VERSION", version ); } } // Akonadi and friends QScopedPointer aprov; aprov.reset( new AddressProvider); tmpl.setValue( "ADDRESSBOOK_BACKEND_LABEL", i18n( "Addressbook Backend" ) ); tmpl.setValue( "ADDRESSBOOK_BACKEND_TYPE_LABEL", i18n( "Backend type" ) ); const QString backendTypeValue = QString( "%1 (%2)").arg( aprov->backendName()) .arg(aprov->backendUp() ? i18n("running") : i18n("not running") ); tmpl.setValue( "ADDRESSBOOK_BACKEND_TYPE", backendTypeValue ); // external tools tmpl.setValue( "EXTERNAL_TOOLS_LABEL", i18n( "External Tools" ) ); tmpl.setValue( "RML2PDF_TOOL_LABEL", i18n( "RML to PDF conversion tool" ) ); const QStringList trml2pdf = DefaultProvider::self()->locatePythonTool("erml2pdf.py"); QString trml2pdfValue = (trml2pdf.count() ? trml2pdf.join(" ") : i18n("not found!") ); tmpl.setValue( "RML2PDF_TOOL", trml2pdfValue ); tmpl.setValue( "ICONV_TOOL_LABEL", i18n( "iconv tool for text import" ) ); tmpl.setValue( "ICONV_TOOL", DefaultProvider::self()->iconvTool() ); tmpl.setValue( "WEASYPRINT_TOOL_LABEL", i18n( "weasyprint for PDF generation" ) ); QString wp = DefaultProvider::self()->locateBinary("weasyprint"); if (wp.isEmpty()) { wp = i18n("not available"); } tmpl.setValue( "WEASYPRINT_TOOL", wp); // aknowledgement tmpl.setValue( "ICON_ACKNOWLEDGEMENT_LABEL", i18n("Some Icons are made by") ); tmpl.setValue( "ACKNOWLEGEMENT_LABEL", i18n( "Acknowledgements" ) ); return tmpl.expand(); } void PortalView::fillSystemDetails() { const QString html = systemView( QString() ); mSystemBrowser->displayContent( html ); } void PortalView::systemInitError( const QString& htmlMsg ) { const QString html = systemView( htmlMsg ); mSystemBrowser->displayContent( html ); } QWidget* PortalView::documentDigests() { QWidget *w = new QWidget; QBoxLayout *b = new QHBoxLayout; b->setContentsMargins( 0, 0, 0, 0 ); w->setLayout( b ); _allDocsView = new AllDocsView( w ); b->addWidget( _allDocsView ); connect( _allDocsView, &AllDocsView::createDocument, this, &PortalView::slotCreateDocument); connect( _allDocsView, &AllDocsView::openDocument, this, &PortalView::openDocument); connect( _allDocsView, &AllDocsView::viewDocument, this, &PortalView::viewDocument); connect( _allDocsView, &AllDocsView::copyDocument, this, &PortalView::copyDocument); connect( _allDocsView, &AllDocsView::openArchivedDocument, this, &PortalView::openArchivedDocument); connect( _allDocsView, &AllDocsView::exportXRechnungArchivedDocument, this, &PortalView::exportXRechnungArchivedDocument); connect( _allDocsView, &AllDocsView::docSelected , this, &PortalView::documentSelected ); connect( _allDocsView, &AllDocsView::openArchivedDocument, this, &PortalView::archivedDocSelected ); return w; } void PortalView::slotCreateDocument() { // this slot is called if the user wants to initiate the creation of a new doc // It is routed to higher layers. emit createDocument(); } void PortalView::slotBuildView() { // QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) ); _allDocsView->slotBuildView(); // QApplication::restoreOverrideCursor(); } /* END */ kraft-1.1/src/portalview.h000066400000000000000000000052151450127457600156340ustar00rootroot00000000000000/*************************************************************************** portalview.h ------------------- begin : 2004-05-09 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _PORTALVIEW_H #define _PORTALVIEW_H #include #include #include // include files #include "docguardedptr.h" /** * */ class QWidget; class AllDocsView; class dbID; class PortalHtmlView; class ArchDocDigest; class DocDigest; class PortalView : public QWidget { Q_OBJECT public: PortalView (QWidget *parent=0, const char *name=0 ); ~PortalView(); AllDocsView* docDigestView() { return _allDocsView; } void systemInitError( const QString& ); QString ptag( const QString&, const QString& c = QString() ) const; public slots: void slotBuildView(); void fillCatalogDetails(); void fillSystemDetails(); void displaySystemsTab(); protected slots: void slotCreateDocument(); private slots: void changePage(QListWidgetItem *current); signals: void openKatalog( const QString& ); void katalogToXML( const QString& ); void createDocument(); void openDocument( const QString& ); void copyDocument( const QString& ); void viewDocument( const QString& ); void openArchivedDocument( const ArchDocDigest& ); void exportXRechnungArchivedDocument( const ArchDocDigest&); void documentSelected( const DocDigest& ); void archivedDocSelected( const ArchDocDigest& ); private: QString printKatLine( const QString&, int ) const; void createIcons(const QSize &iconSize); QWidget *katalogDetails(); QWidget *systemDetails(); QWidget *documentDigests(); QString systemView( const QString& ) const; AllDocsView *_allDocsView; PortalHtmlView *mCatalogBrowser; PortalHtmlView *mSystemBrowser; QListWidget *_contentsWidget; QStackedWidget *_pagesWidget; int _sysPageIndx; }; #endif /* END */ kraft-1.1/src/positionviewwidget.cpp000066400000000000000000000533071450127457600177430ustar00rootroot00000000000000/*************************************************************************** positionviewwidget - inherited class for doc position views. ------------------- begin : 2006-02-20 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include "positionviewwidget.h" #include "geld.h" #include "kraftsettings.h" #include "defaultprovider.h" #include "itemtagdialog.h" #include "tagman.h" PositionViewWidget::PositionViewWidget() :QWidget(), Ui_positionWidget(), mModified( false ), m_skipModifiedSignal( false ), mToDelete(false), mOrdNumber(0), mPositionPtr( 0 ), mExecPopup( new QMenu( this ) ) , mStateSubmenu( 0 ), mState( Active ), mKind( Normal ), mPositionPriceValid( false ), mLocale( 0 ) { setupUi( this ); m_sbUnitPrice->setMinimum( -999999.99 ); m_sbUnitPrice->setMaximum( 999999.99 ); m_sbUnitPrice->setDecimals( 2 ); const QString currSymbol = DefaultProvider::self()->locale()->currencySymbol(); m_sbUnitPrice->setSuffix(" " + currSymbol); m_sbAmount->setMinimum( -999999.99 ); m_sbAmount->setMaximum( 999999.99 ); m_sbAmount->setDecimals( 2 ); mDiscountPercent->setMinimum( -100.0 ); mDiscountPercent->setMaximum( 9999.99 ); mDiscountPercent->setDecimals( 2 ); pbExec->setCheckable( false ); pbExec->setIcon( DefaultProvider::self()->icon( "tool") ); pbTagging->setCheckable( false ); pbTagging->setIcon( DefaultProvider::self()->icon( "flag" ) ); connect( m_sbAmount, SIGNAL( valueChanged( double )), this, SLOT( slotRefreshPrice( ) ) ); connect( m_sbUnitPrice, SIGNAL( valueChanged( double )), this, SLOT( slotRefreshPrice( ) ) ); connect( mDiscountPercent, SIGNAL( valueChanged( double ) ), this, SLOT( slotRefreshPrice() ) ); connect( pbExec, SIGNAL( pressed() ), this, SLOT( slotExecButtonPressed() ) ); connect( pbTagging, SIGNAL( pressed() ), this, SLOT( slotTaggingButtonPressed() ) ); /* modified signals */ connect( m_cbUnit, SIGNAL( activated(int) ), this, SLOT( slotModified() ) ); connect( m_teFloskel, SIGNAL( textChanged() ), this, SLOT( slotModified() ) ); connect( m_sbAmount, SIGNAL( valueChanged(double)), this, SLOT( slotModified() ) ); connect( m_sbUnitPrice, SIGNAL( valueChanged(double)), this, SLOT( slotModified() ) ); connect( mDiscountPercent, SIGNAL( valueChanged( double ) ), this, SLOT( slotModified() ) ); connect( mDiscountTag, SIGNAL( activated( int ) ), this, SLOT( slotModified() ) ); mExecPopup->setTitle(i18n("Item Actions") ); // state submenu: mStateSubmenu = mExecPopup->addMenu(i18n( "Item Kind" )); mStateSubmenu->addAction( i18n( "Normal" ), this, SIGNAL( positionStateNormal() ) ); mStateSubmenu->addAction( DefaultProvider::self()->icon( "arrow-ramp-right" ), i18n( "Alternative" ), this, SIGNAL( positionStateAlternative() ) ); mStateSubmenu->addAction( DefaultProvider::self()->icon( "arrow-move-right" ), i18n( "On Demand" ), this, SIGNAL( positionStateDemand() ) ); // mExecPopup->addSeparator(); // mTaxSubMenu mTaxSubmenu = mExecPopup->addMenu(i18n( "Tax" )); QActionGroup *agroup = new QActionGroup( this ); agroup->setExclusive ( true ); mNilTaxAction = new QAction( DefaultProvider::self()->icon("circle-0"), i18n("Taxfree Item"), this ); connect( mNilTaxAction, SIGNAL(triggered()), this, SLOT(slotSetNilTax()) ); mNilTaxAction->setCheckable( true ); agroup->addAction( mNilTaxAction ); mTaxSubmenu->addAction( mNilTaxAction ); mRedTaxAction = new QAction( DefaultProvider::self()->icon("circle-half-2"), i18n("Reduced Tax"), this ); connect( mRedTaxAction, SIGNAL(triggered()), this, SLOT(slotSetReducedTax())); mRedTaxAction->setCheckable( true ); agroup->addAction( mRedTaxAction ); mTaxSubmenu->addAction( mRedTaxAction ); mFullTaxAction = new QAction( DefaultProvider::self()->icon("coin"), i18n("Full Tax"), this ); connect( mFullTaxAction, SIGNAL(triggered()), this, SLOT(slotSetFullTax())); mFullTaxAction->setCheckable( true ); agroup->addAction( mFullTaxAction ); mTaxSubmenu->addAction( mFullTaxAction ); mExecPopup->addSeparator(); mExecPopup->addAction( DefaultProvider::self()->icon("arrow-up"), i18n("Move Up"), this, SIGNAL( moveUp() ) ); mExecPopup->addAction( DefaultProvider::self()->icon("arrow-down"), i18n("Move Down"), this, SIGNAL( moveDown() ) ); mLockId = mExecPopup->addAction( DefaultProvider::self()->icon("lock"), i18n("Lock Item"), this, SIGNAL( lockPosition() ) ); mUnlockId = mExecPopup->addAction( DefaultProvider::self()->icon("lock-open"), i18n("Unlock Item"), this, SIGNAL( unlockPosition() ) ); mDeleteId = mExecPopup->addAction( DefaultProvider::self()->icon("minus"), i18n("Delete Item"), this, SIGNAL( deletePosition() ) ); connect(this, &PositionViewWidget::positionStateNormal, this, [this]() { slotSetPositionKind(Normal, true); slotRefreshPrice(); emit positionModified(); } ); connect(this, &PositionViewWidget::positionStateAlternative, this, [this]() { slotSetPositionKind(Alternative, true); slotRefreshPrice(); emit positionModified(); } ); connect(this, &PositionViewWidget::positionStateDemand, this, [this]() { slotSetPositionKind(Demand, true); slotRefreshPrice(); emit positionModified(); } ); connect(this, &PositionViewWidget::lockPosition, this, &PositionViewWidget::slotLockPosition); connect(this, &PositionViewWidget::unlockPosition, this, &PositionViewWidget::slotUnlockPosition); connect( mExecPopup, &QMenu::aboutToShow, this, &PositionViewWidget::slotMenuAboutToShow); connect( mExecPopup, &QMenu::aboutToHide, this, &PositionViewWidget::slotMenuAboutToHide); mUnlockId->setEnabled(false); lStatus->setPixmap( QPixmap() ); lKind->setPixmap( QPixmap() ); this->setAutoFillBackground(true); this->setBaseSize(this->width(), 100); this->layout()->setMargin( 6 ); } void PositionViewWidget::setDocPosition( DocPositionBase *dp) { if( ! dp ) { qCritical() << "setDocPosition got empty position!"; return; } DocPosition *pos = static_cast(dp); // FIXME: Do not keep this pointer ... mPositionPtr = pos; m_skipModifiedSignal = true; m_teFloskel->setPlainText( pos->text() ); lStatus->hide(); lKind->hide(); AttributeMap amap = dp->attributes(); QString unit = pos->unit().einheitSingular(); m_cbUnit->setCurrentIndex(m_cbUnit->findText( unit )); if( dp->type() == DocPositionBase::Position ) { positionDetailStack->setCurrentWidget( positionPage ); m_sbAmount->blockSignals( true ); m_sbAmount->setValue( pos->amount() ); m_sbAmount->blockSignals( false ); m_sbUnitPrice->blockSignals( true ); m_sbUnitPrice->setValue( pos->unitPrice().toDouble() ); m_sbUnitPrice->blockSignals( false ); if ( amap.containsUndeleted( DocPosition::Kind ) ) { Attribute kindAttr = amap[DocPosition::Kind]; const QString kindStr = kindAttr.value().toString(); Kind kind = techStringToKind(kindStr); slotSetPositionKind(kind, false); } else { slotSetPositionKind(Kind::Normal, false); } // qDebug () << "Setting position ptr. in viewwidget: " << pos; } else if ( dp->type() == DocPositionBase::ExtraDiscount ) { positionDetailStack->setCurrentWidget( discountPage ); // qDebug() << " " << dp->type(); Attribute discount = amap[DocPosition::Discount]; mDiscountPercent->setValue( discount.value().toDouble() ); QString selTag; if ( amap.contains( DocPosition::ExtraDiscountTagRequired ) ) { Attribute tagSelector = amap[DocPosition::ExtraDiscountTagRequired]; const TagTemplate tt = TagTemplateMan::self()->getTagTemplateFromId(tagSelector.value().toString()); selTag = tt.name(); } /* Fill and set the extra discount selection combo */ const QString allPos = i18n( "All items" ); mDiscountTag->addItem( allPos ); // , i18n( "Overall Position Discount" ) ); QStringList taglist = TagTemplateMan::self()->allTagTemplates(); QString currentEntry = allPos; for ( QStringList::Iterator tagIt = taglist.begin(); tagIt != taglist.end(); ++tagIt ) { QString tagger; TagTemplate tmpl = TagTemplateMan::self()->getTagTemplate( *tagIt ); QPixmap pix( 16, 12 ); pix.fill( tmpl.color() ); tagger = i18n( "%1-tagged items", *tagIt ); mDiscountTag->addItem(pix, tagger); if ( selTag == *tagIt ) { currentEntry = tagger; } } mDiscountTag->setCurrentIndex(mDiscountTag->findText( currentEntry )); } else { // qDebug () << "unknown doc position type " << dp->type(); } slotSetOverallPrice( currentPrice() ); // set tags marked mTags = dp->tags(); slotUpdateTagToolTip(); slotSetTax( dp->taxType() ); m_skipModifiedSignal = false; } void PositionViewWidget::slotShowPrice( bool show ) { m_sumLabel->setVisible(show); m_sbUnitPrice->setVisible(show); } void PositionViewWidget::slotUpdateTagToolTip() { QString tip; bool first = true; if ( mTags.count() == 1 ) { tip = i18n( "Tag: %1", mTags.first() ); } else if ( mTags.count() > 1 ) { tip = i18n( "Tags:
              " ); for ( QStringList::Iterator it = mTags.begin(); it != mTags.end(); ++it ) { if ( first ) { tip += QString( "
            • %1
            • " ).arg( *it ); first = false; } else { tip += QString( "
            • %1
            • " ).arg( *it ); } } tip += "
            "; } else { tip = i18n( "No tags assigned yet." ); } pbTagging->setToolTip( tip ); } QString PositionViewWidget::extraDiscountTagRestriction() { QStringList taglist = TagTemplateMan::self()->allTagTemplates(); int currentItem = mDiscountTag->currentIndex(); if ( currentItem > 0 && currentItem <= taglist.count() ) { // subtract one for the "all items" entry in the combo box at first position currentItem -= 1; return taglist[currentItem]; } else { // qDebug () << "taglist index possibly out of range!"; } return QString(); } void PositionViewWidget::slotTaggingButtonPressed() { // qDebug () << "opening tagging dialog"; ItemTagDialog dia( 0 ); dia.setPositionTags( mTags ); if ( dia.exec() ) { mTags = dia.getSelectedTags(); slotUpdateTagToolTip(); slotModified(); update(); // qDebug () << "Selected tags: " << mTags.join( ", " ); } } void PositionViewWidget::slotSetNilTax() { slotSetTax( DocPositionBase::TaxNone ); } void PositionViewWidget::slotSetReducedTax() { slotSetTax( DocPositionBase::TaxReduced ); } void PositionViewWidget::slotSetFullTax() { slotSetTax( DocPositionBase::TaxFull ); } void PositionViewWidget::slotSetTax( DocPosition::TaxType tt ) { mTax = tt; QString icon; if( tt == DocPositionBase::TaxFull ) { icon = QString::fromLatin1("coin"); mFullTaxAction->setChecked( true ); } else if( tt == DocPositionBase::TaxReduced ) { icon = QString::fromLatin1("circle-half-2"); mRedTaxAction->setChecked( true ); } else if( tt == DocPositionBase::TaxNone ) { icon = QString::fromLatin1("circle-0"); mNilTaxAction->setChecked( true ); } mTaxSubmenu->setIcon( DefaultProvider::self()->icon( icon )); emit positionModified(); } void PositionViewWidget::slotAllowIndividualTax( bool allow ) { mFullTaxAction->setEnabled(allow); mRedTaxAction->setEnabled(allow); mNilTaxAction->setEnabled(allow); mTaxSubmenu->setEnabled( allow ); } DocPositionBase::TaxType PositionViewWidget::taxType() const { return mTax; } void PositionViewWidget::slotExecButtonPressed() { // qDebug () << "Opening Context Menu over exec button"; // set bg-color mExecPopup->popup( QWidget::mapToGlobal( pbExec->pos() ) ); } void PositionViewWidget::slotMenuAboutToShow() { QPalette palette; palette.setColor(this->backgroundRole(), QColor("#757476")); this->setPalette(palette); } void PositionViewWidget::slotMenuAboutToHide() { // qDebug () << "Set normal again"; QPalette palette; setPalette( palette ); pbExec->setChecked(false); } void PositionViewWidget::slotLockPosition( ) { slotSetState( Locked ); } void PositionViewWidget::slotUnlockPosition( ) { slotSetState( Active ); } void PositionViewWidget::slotEnableKindMenu( bool s ) { mStateSubmenu->setEnabled( s ); } QString PositionViewWidget::stateString( const State& state ) const { QString str; if( state == Active ) { str = i18n( "Active" ); } else if( state == New ) { str = i18n( "New" ); } else if( state == Deleted ) { str = i18n( "Deleted" ); } else if( state == Locked ) { str = i18n( "Locked" ); } else { str = i18n( "Unknown" ); } return str; } void PositionViewWidget::slotSetState( State state ) { mState = state; // qDebug () << "Setting new widget state " << stateString( state ); if( state == Active ) { mLockId->setEnabled( true ); mUnlockId->setEnabled( false ); lStatus->hide(); lStatus->setPixmap( QPixmap() ); mToDelete = false; slotSetEnabled( true ); } else if( state == New ) { lStatus->setPixmap( DefaultProvider::self()->icon("file-plus").pixmap(QSize(20,20))); lStatus->show(); } else if( state == Deleted ) { lStatus->setPixmap( DefaultProvider::self()->icon( "minus" ).pixmap(QSize(20,20)) ); lStatus->show(); mToDelete = true; slotSetEnabled( false ); } else if( state == Locked ) { mLockId->setEnabled( false ); mUnlockId->setEnabled( true ); slotSetEnabled( false ); lStatus->setPixmap( DefaultProvider::self()->icon( "lock" ).pixmap(QSize(20,20))); lStatus->show(); } } void PositionViewWidget::setOrdNumber(int o) { mOrdNumber = o; if( mModified ) { QColor c( "darkred" ); QPalette palette = m_labelPosition->palette(); palette.setColor(m_labelPosition->foregroundRole(), c); m_labelPosition->setPalette(palette); } m_labelPosition->setText( QString("%1.").arg( mOrdNumber ) ); } void PositionViewWidget::slotSetEnabled( bool doit ) { if( !doit ) { m_sbAmount->setEnabled( false ); m_sbUnitPrice->setEnabled( false ); m_labelPosition->setEnabled( false ); m_teFloskel->setEnabled( false ); m_sumLabel->setEnabled( false ); m_cbUnit->setEnabled( false ); } else { m_sbAmount->setEnabled( true ); m_sbUnitPrice->setEnabled( true ); m_labelPosition->setEnabled( true ); m_teFloskel->setEnabled( true ); m_sumLabel->setEnabled( true ); m_cbUnit->setEnabled( true ); } } bool PositionViewWidget::priceValid() { bool isValid = true; if ( position()->type() == DocPosition::ExtraDiscount ) { isValid = mPositionPriceValid; } return isValid; } void PositionViewWidget::setCurrentPrice( Geld g ) { // do nothing for normal positions if ( position()->type() == DocPosition::ExtraDiscount ) { mPositionPrice = g; mPositionPriceValid = true; } } Geld PositionViewWidget::currentPrice() { Geld sum; if ( mKind == Normal ) { if ( position()->type() == DocPosition::ExtraDiscount ) { sum = mPositionPrice; if ( ! mPositionPriceValid ) { qWarning() << "Asking for price of Discount item, but invalid!"; } } else { double amount = m_sbAmount->value(); Geld g( m_sbUnitPrice->value() ); sum = g * amount; } } return sum; } Geld PositionViewWidget::unitPrice() { Geld p( m_sbUnitPrice->value() ); return p; } void PositionViewWidget::slotRefreshPrice() { const Geld sum = currentPrice(); slotSetOverallPrice( sum ); emit priceChanged( sum ); } void PositionViewWidget::slotSetOverallPrice( Geld g ) { // if ( mPositionPtr->type() == DocPosition::ExtraDiscount ) { // m_sumLabel->setText( "--" ); // } else { m_sumLabel->setText( g.toLocaleString() ); // } } void PositionViewWidget::slotModified( bool emitSignal ) { Q_UNUSED(emitSignal) if(m_skipModifiedSignal) return; // qDebug () << "Modified Position!"; mModified = true; m_labelPosition->setStyleSheet("font-weight: bold; color: red"); emit positionModified(); } PositionViewWidget::~PositionViewWidget() { } PositionViewWidgetList::PositionViewWidgetList() : QList() { // setAutoDelete( true ); } PositionViewWidget* PositionViewWidgetList::widgetFromPosition( DocPositionGuardedPtr ptr) { PositionViewWidgetListIterator it( *this ); while( it.hasNext() ) { PositionViewWidget *pvw = it.next(); if( pvw ->position() == ptr ) { return pvw; } } return 0; } Geld PositionViewWidgetList::nettoPrice() { Geld res; PositionViewWidgetListIterator it( *this ); while( it.hasNext() ) { PositionViewWidget *pvw = it.next(); res += pvw->currentPrice(); } return res; } QString PositionViewWidget::cleanKindString(const QString& src) { QString current {src}; if ( current.startsWith( kindLabel( Alternative ) ) ) { current.remove( 0, kindLabel(Alternative).length() ); } else if ( current.startsWith( kindLabel( Demand ) ) ) { current.remove( 0, kindLabel(Demand).length()); } return current; } void PositionViewWidget::slotSetPositionKind(Kind kind, bool alterText) { QString tt; QIcon icon; bool showLabel {false}; Kind oldKind = mKind; mKind = kind; if (kind == Kind::Normal) { } else if (kind == Kind::Demand) { tt = i18n( "This item is either completely optional or its " "amount varies depending on the needs.

            " "Use the item toolbox to change the item type." ); showLabel = true; icon = DefaultProvider::self()->icon("arrow-move-right"); } else if (kind == Kind::Alternative) { tt = i18n( "This is an alternative item.

            " " Use the position toolbox to change the item type." ); showLabel = true; icon = DefaultProvider::self()->icon("arrow-ramp-right"); } showLabel ? lKind->show() : lKind->hide(); lKind->setToolTip(tt); lKind->setPixmap(icon.pixmap(QSize(20,20))); if (alterText) { QString text = m_teFloskel->toPlainText(); if (oldKind == Kind::Normal) { QString pre; if (kind == Kind::Alternative) { pre = kindLabel(Kind::Alternative); } else if (kind == Kind::Demand) { pre = kindLabel(Kind::Demand); } if (!pre.isEmpty()) { m_teFloskel->setPlainText(pre + text); } } else { // from demand to normal or alternative for example if (kind == Kind::Normal) { text = cleanKindString(text); } else { text = kindLabel(kind) + cleanKindString(text); } m_teFloskel->setPlainText(text); } } } // The technical label // Do not QString PositionViewWidget::techKindString( Kind kind) { if ( kind == Invalid ) { qDebug() << "Invalid Kind set"; } if ( kind == Normal ) return QStringLiteral( "Normal" ); if ( kind == Demand ) return QStringLiteral( "Demand" ); if ( kind == Alternative ) return QStringLiteral( "Alternative" ); return QStringLiteral( "Invalid" ); } PositionViewWidget::Kind PositionViewWidget::techStringToKind( const QString& kindStr ) { if (kindStr == techKindString(Normal)) { return Kind::Normal; } else if (kindStr == techKindString(Demand)) { return Kind::Demand; } else if (kindStr == techKindString(Alternative)) { return Kind::Alternative; } return Kind::Invalid; } // The label that is prepended to a positions text QString PositionViewWidget::kindLabel( Kind k ) { Kind kind = k; QString re; if ( kind == Normal ) { re = KraftSettings::self()->normalLabel(); if ( re.isEmpty() ) re = i18n( "Normal" ); } if ( kind == Demand ) { re = KraftSettings::self()->demandLabel(); if ( re.isEmpty() ) re = i18n( "Demand" ); } if ( kind == Alternative ) { re = KraftSettings::self()->alternativeLabel(); if ( re.isEmpty() ) re = i18n( "Alternative" ); } if ( ! re.endsWith( ": " ) ) { re += QStringLiteral( ": " ); } return re; } void PositionViewWidget::paintEvent ( QPaintEvent*) { QScopedPointer painter(new QPainter( this )); // visualize the tags const QStringList taglist = tagList(); if ( taglist.count() ) { int share = ( height() - 24 ) / taglist.count(); int cnt = 0; for ( QStringList::ConstIterator it = taglist.begin(); it != taglist.end(); ++it ) { const QString tag(*it); TagTemplate tagTemplate = TagTemplateMan::self()->getTagTemplate( tag ); const QColor c = tagTemplate.color(); // qDebug() << "color: " << c.red() << ", " << c.green() << ", " << c.blue(); painter->setBrush( c ); int starty = 6+cnt*share; qDrawShadeLine( painter.data(), QPoint(3, starty), QPoint(3, starty+share-1), tagTemplate.palette(), false, 1, 4 ); cnt++; } } } kraft-1.1/src/positionviewwidget.h000066400000000000000000000106461450127457600174070ustar00rootroot00000000000000/*************************************************************************** postionviewwidget - inherited class for doc position views. ------------------- begin : 2006-02-20 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef POSITIONVIEWWIDGET_H #define POSITIONVIEWWIDGET_H #include #include #include #include #include #include "geld.h" #include "ui_positionwidget.h" #include "docposition.h" /** @author Klaas Freitag */ class KMenu; class QAction; class Geld; class QLocale; class DosPositionGuardedPtr; class PositionViewWidget : public QWidget, public Ui_positionWidget { Q_OBJECT public: enum State { Active, New, Deleted, Locked }; enum Kind { Normal, Demand, Alternative, Invalid }; PositionViewWidget( ); PositionViewWidget( int ); void setDocPosition(DocPositionBase*); virtual ~PositionViewWidget(); bool modified() { return mModified; } int ordNumber() { return mOrdNumber; } void setOrdNumber( int ); bool deleted() { return mToDelete; } DocPositionGuardedPtr position(){ return mPositionPtr; } State state() { return mState; } Kind kind() { return mKind; } static QString techKindString(Kind kind); static Kind techStringToKind( const QString& kindStr ); static QString kindLabel( Kind ); QString stateString( const State& state ) const; QString cleanKindString(const QString &src); Geld currentPrice(); bool priceValid(); void setCurrentPrice( Geld ); Geld unitPrice(); QStringList tagList() { return mTags; } QString extraDiscountTagRestriction(); DocPositionBase::TaxType taxType() const; public slots: void slotSetOverallPrice( Geld ); void slotRefreshPrice(); void slotModified( bool emitSignal = true ); void slotExecButtonPressed(); void slotTaggingButtonPressed(); void slotMenuAboutToHide(); void slotMenuAboutToShow(); void slotSetState( State ); void slotSetEnabled( bool ); void slotEnableKindMenu( bool ); void slotAllowIndividualTax( bool ); void slotSetTax( DocPosition::TaxType ); void slotShowPrice( bool show ); // hide the price entries for certain doc types. protected slots: void slotLockPosition(); void slotUnlockPosition(); void slotSetPositionKind(Kind kind, bool alterText); void slotUpdateTagToolTip(); void paintEvent ( QPaintEvent* ); void slotSetNilTax(); void slotSetReducedTax(); void slotSetFullTax(); signals: void positionModified(); void deletePosition(); void moveUp(); void moveDown(); void lockPosition(); void unlockPosition(); void priceChanged( const Geld& ); void positionStateNormal(); void positionStateAlternative(); void positionStateDemand(); private: bool mModified; bool m_skipModifiedSignal; bool mToDelete; int mOrdNumber; DocPositionGuardedPtr mPositionPtr; QMenu *mExecPopup; QMenu *mStateSubmenu; QMenu *mTaxSubmenu; QStringList mTags; QAction * mDeleteId; QAction * mLockId; QAction * mUnlockId; QAction * mNilTaxAction; QAction * mRedTaxAction; QAction * mFullTaxAction; Geld mPositionPrice; // only used for Discount items to store the result State mState; Kind mKind; bool mPositionPriceValid; QLocale *mLocale; DocPosition::TaxType mTax; }; class PositionViewWidgetList : public QList { public: PositionViewWidgetList(); PositionViewWidget* widgetFromPosition( DocPositionGuardedPtr ); Geld nettoPrice(); }; typedef QListIterator PositionViewWidgetListIterator; #endif kraft-1.1/src/positionwidget.ui000066400000000000000000000205521450127457600166770ustar00rootroot00000000000000 positionWidget 0 0 520 157 0 1 400 0 2 2 4 0 0 1. false true 0 0 25 16777215 false 0 0 25 16777215 false D Qt::AlignCenter false Qt::Vertical QSizePolicy::Expanding 22 5 D Qt::AlignCenter false 0 1 150 110 true 0 9999900.000000000000000 0.000000000000000 1 0.010000000000000 2 99999.000000000000000 0.000000000000000 0.100000000000000 -0.100000000000000 0.010000000000000 2 0 % of the sum of false Qt::Horizontal QSizePolicy::Expanding 28 21 75 true textLabel7 false Qt::Horizontal kraft-1.1/src/prefsdialog.cpp000066400000000000000000000726231450127457600163010ustar00rootroot00000000000000/*************************************************************************** prefsdialog.cpp - the preferences Dialog ------------------- begin : Sun Jul 3 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "prefsdialog.h" #include "prefswages.h" #include "prefsunits.h" #include "kraftsettings.h" #include "defaultprovider.h" #include "doctype.h" #include "doctypeedit.h" #include "taxeditdialog.h" #include "impviewwidgets.h" #include "texttemplate.h" #include "htmlview.h" #include "addressselectordialog.h" #include "addressprovider.h" #include "format.h" #include "positionviewwidget.h" #include "kcontacts/vcardconverter.h" // ################################################################################ PrefsDialog::PrefsDialog( QWidget *parent) :QDialog( parent ) { setModal( true ); setWindowTitle( i18n( "Configure Kraft" ) ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QHBoxLayout *mainLayout = new QHBoxLayout; _navigationBar = new QListWidget(this); _navigationBar->setViewMode(QListView::IconMode); _navigationBar->setIconSize(QSize(96, 64)); _navigationBar->setMovement(QListView::Static); //_navigationBar->setSpacing(6); _navigationBar->setCurrentRow(0); _navigationBar->setFixedWidth(195); setLayout(mainLayout); QVBoxLayout *vbox = new QVBoxLayout; _pagesWidget = new QStackedWidget(this); vbox->addWidget( _pagesWidget ); vbox->addWidget( buttonBox ); mainLayout->addWidget(_navigationBar); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addLayout(vbox); okButton->setDefault(true); setMinimumWidth(700); _maxNavBarTextWidth = 0; addDialogPage( docTab(), DefaultProvider::self()->icon( "copy"), i18n( "Document Defaults" )); addDialogPage( taxTab(), DefaultProvider::self()->icon( "receipt-tax" ), i18n("Taxes")); addDialogPage( doctypeTab(), DefaultProvider::self()->icon( "files"), i18n( "Document Types" )); mPrefsWages = new PrefsWages(this); addDialogPage(mPrefsWages, DefaultProvider::self()->icon( "cash-banknote" ), i18n( "Wages" )); mPrefsUnits = new PrefsUnits(this); addDialogPage(mPrefsUnits, DefaultProvider::self()->icon( "atom" ), i18n("Units")); addDialogPage( whoIsMeTab(), DefaultProvider::self()->icon( "id-badge-2" ), i18n( "Own Identity" )); readConfig(); connect( _navigationBar, &QListWidget::itemClicked, this, &PrefsDialog::changePage); } void PrefsDialog::changePage(QListWidgetItem *current) { if (!current) return; int indx = _navigationBar->row(current); _pagesWidget->setCurrentIndex(indx); } int PrefsDialog::addDialogPage( QWidget *w, const QIcon& icon, const QString& title) { QListWidgetItem *listWidgetItem = new QListWidgetItem(_navigationBar); listWidgetItem->setIcon(icon); listWidgetItem->setText(title); listWidgetItem->setTextAlignment(Qt::AlignCenter); listWidgetItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); listWidgetItem->setSizeHint( QSize(170, 100)); _navigationBar->addItem(listWidgetItem); QWidget *w_with_title = new QWidget; QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(new QLabel(QStringLiteral("

            ")+title+QStringLiteral("

            "))); w_with_title->setLayout(layout); layout->addWidget(w); int indx = _pagesWidget->addWidget(w_with_title); return indx; } QWidget* PrefsDialog::taxTab() { QWidget *topWidget = new QWidget; QVBoxLayout *vboxLay = new QVBoxLayout; // vboxLay->setSpacing( spacingHint() ); QLabel *label; label = new QLabel(i18n("Tax rates beginning at date:")); vboxLay->addWidget( label ); mTaxModel = new QSqlTableModel(this); mTaxModel->setTable("taxes"); mTaxModel->setSort(3, Qt::DescendingOrder); mTaxModel->setEditStrategy(QSqlTableModel::OnManualSubmit); mTaxModel->select(); mTaxModel->setHeaderData(0, Qt::Horizontal, i18n("ID")); mTaxModel->setHeaderData(1, Qt::Horizontal, i18n("Full Tax [%]")); mTaxModel->setHeaderData(2, Qt::Horizontal, i18n("Reduced Tax [%]")); mTaxModel->setHeaderData(3, Qt::Horizontal, i18n("Start Date")); mTaxTreeView = new ImpTreeView; vboxLay->addWidget( mTaxTreeView ); mTaxTreeView->setModel(mTaxModel); mTaxTreeView->setItemDelegate(new TaxItemDelegate()); mTaxTreeView->hideColumn(0); mTaxTreeView->header()->moveSection(3, 1); mTaxTreeView->header()->stretchLastSection(); mTaxTreeView->setColumnWidth(3, 200); mTaxTreeView->resizeColumnToContents(2); mTaxTreeView->resizeColumnToContents(1); connect( mTaxTreeView, SIGNAL(clicked(QModelIndex)), SLOT( slotTaxSelected(QModelIndex) ) ); QHBoxLayout *butLay = new QHBoxLayout; butLay->addStretch( 1 ); QPushButton *but = new QPushButton( DefaultProvider::self()->icon("plus"), i18n( "Add" )); connect( but, SIGNAL( clicked() ), SLOT( slotAddTax() ) ); butLay->addWidget( but ); mDelTax = new QPushButton( DefaultProvider::self()->icon("minus"), i18n( "Remove" ) ); connect( mDelTax, SIGNAL( clicked() ), SLOT( slotDeleteTax() ) ); butLay->addWidget( mDelTax ); mDelTax->setEnabled( false ); vboxLay->addLayout( butLay ); topWidget->setLayout( vboxLay ); return topWidget; } QWidget* PrefsDialog::whoIsMeTab() { QWidget *topWidget = new QWidget; QVBoxLayout *vboxLay = new QVBoxLayout; QLabel *label = new QLabel(i18n("Select the identity of the sending entity of documents. That's your companies address.")); label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); vboxLay->addWidget( label ); _tabWidget = new QTabWidget; vboxLay->addWidget(_tabWidget); // == Tab that displays the Addressbook widget QWidget *w = new QWidget; QVBoxLayout *t1Lay = new QVBoxLayout; mIdentityView = new HtmlView; mIdentityView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); t1Lay->addWidget(mIdentityView); QHBoxLayout *butLay = new QHBoxLayout; butLay->addStretch( 1 ); _pbChangeIdentity = new QPushButton(i18n("Select Identity...")); connect( _pbChangeIdentity, SIGNAL(clicked()), SLOT(slotChangeIdentity()) ); butLay->addWidget(_pbChangeIdentity); t1Lay->addLayout( butLay ); w->setLayout(t1Lay); _tabWidget->insertTab(0, w, i18n("From AddressBook")); // == Tab that displays the manual widget QWidget *w1 = new QWidget; ui.setupUi(w1); _tabWidget->insertTab(1, w1, QIcon(), i18n("Manual Entry")); ui.nameLabel->setText( KContacts::Addressee::formattedNameLabel() ); ui.orgLabel->setText( KContacts::Addressee::organizationLabel()); ui.streetLabel->setText(KContacts::Addressee::businessAddressStreetLabel()); ui.postCodeLabel->setText(KContacts::Addressee::businessAddressPostalCodeLabel()); ui.cityLabel->setText(KContacts::Addressee::businessAddressLocalityLabel()); ui.phoneLabel->setText(KContacts::Addressee::businessPhoneLabel()); ui.faxLabel->setText(KContacts::Addressee::businessFaxLabel()); ui.mobileLabel->setText(KContacts::Addressee::mobilePhoneLabel()); ui.emailLabel->setText(KContacts::Addressee::emailLabel()); ui.websiteLabel->setText(KContacts::Addressee::urlLabel()); _tabWidget->insertTab(1, w1, i18n("Manual Address")); // == Bank Account information QGroupBox *gbox = new QGroupBox(i18n("Bank Account Information"), this); QFormLayout *formLayout = new QFormLayout; _bacName = new QLineEdit(this); formLayout->addRow(tr("&Bank Account Holder:"), _bacName); _bacIBAN = new QLineEdit(this); formLayout->addRow(tr("&IBAN:"), _bacIBAN); _bacBIC = new QLineEdit(this); formLayout->addRow(tr("&BIC:"), _bacBIC); gbox->setLayout(formLayout); vboxLay->addWidget(gbox); topWidget->setLayout( vboxLay ); return topWidget; } void PrefsDialog::slotChangeIdentity() { AddressSelectorDialog dialog(this); if( dialog.exec() ) { _newIdentity = dialog.addressee(); if( ! _newIdentity.isEmpty() ) { setMyIdentity(_newIdentity, true); } } } void PrefsDialog::slotAddTax() { TaxEditDialog *dialog = new TaxEditDialog(mTaxModel, this); dialog->show(); } void PrefsDialog::slotDeleteTax() { if ( mTaxTreeView->currentIndex().isValid() ) { int row = mTaxTreeView->currentIndex().row(); //mTaxTreeView->setRowHidden( row, mTaxTreeView->rootIndex(), true ); mTaxModel->removeRows(row, 1); } } void PrefsDialog::slotTaxSelected(QModelIndex) { bool state = false; if ( mTaxTreeView->currentIndex().isValid() ) { state = true; } mDelTax->setEnabled( state ); } QWidget* PrefsDialog::docTab() { QLabel *label; QWidget *topWidget = new QWidget; QVBoxLayout *vboxLay = new QVBoxLayout; topWidget->setLayout( vboxLay ); QGridLayout *topLayout = new QGridLayout; vboxLay->addLayout( topLayout ); label = new QLabel(i18n("&Default document type on creation:"), this ); topLayout->addWidget(label, 0,0); mCbDocTypes = new QComboBox; label->setBuddy( mCbDocTypes ); mCbDocTypes->setToolTip( i18n( "New documents default to the selected type." ) ); topLayout->addWidget( mCbDocTypes, 0, 1 ); mCbDocTypes->insertItems(-1, DocType::allLocalised() ); QLabel *f = new QLabel(this); f->setFrameStyle( QFrame::HLine | QFrame::Sunken ); vboxLay->addWidget( f ); QHBoxLayout *butLay = new QHBoxLayout; QLabel *l = new QLabel( i18n( "Default &Tax for Documents:" ), this ); butLay->addWidget( l ); mCbDefaultTaxType = new QComboBox(this); butLay->addWidget( mCbDefaultTaxType ); l->setBuddy( mCbDefaultTaxType ); mCbDefaultTaxType->setToolTip( i18n( "The default tax setting for all documents." ) ); mCbDefaultTaxType->insertItem( 0, i18n("Display no tax at all")); mCbDefaultTaxType->insertItem( 1, i18n("Calculate reduced tax for all items" )); mCbDefaultTaxType->insertItem( 2, i18n("Calculate full tax for all items" ) ); // mCbDefaultTaxType->insertItem( 3, i18n("Calculate on individual item tax rate" )); vboxLay->addLayout( butLay ); f = new QLabel(this); f->setFrameStyle( QFrame::HLine | QFrame::Sunken ); vboxLay->addWidget( f ); butLay = new QHBoxLayout; l = new QLabel( i18n( "Document Date Format:" ), this ); butLay->addWidget( l ); mCbDateFormats = new QComboBox(this); butLay->addWidget( mCbDateFormats ); l->setBuddy( mCbDateFormats); const QDate d = QDate::currentDate(); mCbDateFormats->setToolTip( i18n( "The default date format for documents." ) ); QString formattedDate = d.toString(Qt::ISODate); mCbDateFormats->insertItem( 0, i18n("ISO-Format: %1", formattedDate)); formattedDate = d.toString(Qt::DefaultLocaleShortDate); mCbDateFormats->insertItem( 1, i18n("Short-Date: %1", formattedDate)); formattedDate = d.toString(Qt::DefaultLocaleLongDate); mCbDateFormats->insertItem( 2, i18n("Long-Date: %1", formattedDate)); formattedDate = d.toString(Qt::RFC2822Date); mCbDateFormats->insertItem( 3, i18n("RFC 2822-Format: %1", formattedDate)); formattedDate = d.toString("dd.MM.yyyy"); mCbDateFormats->insertItem( 4, i18n("\"German Format\": %1", formattedDate)); mCbDateFormats->insertItem( 5, i18n("Custom Setting in Settingsfile")); vboxLay->addLayout( butLay ); // ---- Alternative- and Demand Text f = new QLabel(this); f->setFrameStyle( QFrame::HLine | QFrame::Sunken ); vboxLay->addWidget( f ); auto gridLay = new QGridLayout; l = new QLabel(i18n("Prefix text for Demand items:"), this ); gridLay->addWidget(l, 0, 0); _lineEditDemandText = new QLineEdit(this); _lineEditDemandText->setText(PositionViewWidget::kindLabel(PositionViewWidget::Demand)); _lineEditDemandText->setToolTip(i18n("This text is automatically prepended to new 'on demand' items.")); gridLay->addWidget(_lineEditDemandText, 0, 1); l = new QLabel(i18n("Prefix text for Alternative items:"), this ); gridLay->addWidget(l, 1, 0); _lineEditAlternativeText = new QLineEdit(this); _lineEditAlternativeText->setText(PositionViewWidget::kindLabel(PositionViewWidget::Alternative)); _lineEditAlternativeText->setToolTip(i18n("This text is automatically prepended to new 'alternative' items.")); gridLay->addWidget(_lineEditAlternativeText, 1, 1); vboxLay->addLayout( gridLay ); // ---- XRechnung Template f = new QLabel(this); f->setFrameStyle( QFrame::HLine | QFrame::Sunken ); vboxLay->addWidget( f ); butLay = new QHBoxLayout; l = new QLabel(i18n("XRechnung Template File:"), this ); butLay->addWidget(l); _lineEditXRechnung = new QLineEdit(this); butLay->addWidget(_lineEditXRechnung); QPushButton *pbXRechTmpl = new QPushButton(i18n("Select..."), this); butLay->addWidget(pbXRechTmpl); const QIcon& icon = DefaultProvider::self()->icon("device-floppy"); if (!icon.isNull() ) { pbXRechTmpl->setIcon(icon); pbXRechTmpl->setText(""); } pbXRechTmpl->setToolTip(i18n("Select template file for XRechnung")); connect(pbXRechTmpl, &QPushButton::clicked, this, [this]() { const QString file = QFileDialog::getOpenFileName(this, i18n("Find Template File"), QDir::homePath(), i18n("XRechnung Templates (*.xrtmpl)")); if (!file.isEmpty()) { _lineEditXRechnung->setText(file); } }); vboxLay->addLayout( butLay ); // space eater QWidget *spaceEater = new QWidget; spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); vboxLay->addWidget( spaceEater ); return topWidget; } QWidget* PrefsDialog::doctypeTab() { QWidget *topWidget = new QWidget; QVBoxLayout *vboxLay = new QVBoxLayout; topWidget->setLayout(vboxLay); vboxLay->setSpacing( 0 ); // spacingHint() ); mDocTypeEdit = new DocTypeEdit; vboxLay->addWidget( mDocTypeEdit ); connect( mDocTypeEdit, SIGNAL( removedType( const QString& ) ), SLOT( slotDocTypeRemoved( const QString& ) ) ); return topWidget; } void PrefsDialog::slotDocTypeRemoved( const QString& type ) { // check if the default document type is still there QString currDefault = mCbDocTypes->currentText(); if ( currDefault == type ) { QMessageBox msgBox; msgBox.setText(i18n( "The old default doc type for new documents was just deleted." "Please check the setting in the Document Defaults in the " "Kraft preferences Dialog." )); msgBox.setInformativeText(i18n("Document Default Change")); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.exec(); } for ( int i=0; i < mCbDocTypes->count(); i++ ) { if ( mCbDocTypes->itemText( i ) == type ) { mCbDocTypes->removeItem( i ); continue; } } } void PrefsDialog::readConfig() { QString t = KraftSettings::self()->doctype(); if ( t.isEmpty() ) t = DefaultProvider::self()->docType(); mCbDocTypes->setCurrentIndex( mCbDocTypes->findText( t )); mCbDefaultTaxType->setCurrentIndex( KraftSettings::self()->defaultTaxType()-1 ); DocType dt(QStringLiteral("Rechnung")); // FIXME const auto tmpl = dt.xRechnungTemplate(); _lineEditXRechnung->setText(tmpl); // == Date format int index {5}; const QString dFormat = KraftSettings::self()->dateFormat(); if (dFormat == Format::DateFormatIso) { // iso index = 0; } else if (dFormat == Format::DateFormatShort) { // short index = 1; } else if (dFormat == Format::DateFormatLong) { // long index = 2; } else if (dFormat == Format::DateFormatRFC) { // RFC index = 3; } else if (dFormat == Format::DateFormatGerman) { // German index = 4; } if (index == 5 && dFormat.isEmpty()) { // default case - no entry // HACK: If it is german, choose the "german" format const QString ln = DefaultProvider::self()->locale()->name(); if( ln == QStringLiteral("de_DE")) { index = 4; } else { index = 1; // Short locale aware. } } mCbDateFormats->setCurrentIndex(index); // == Bank Account Information QString h = KraftSettings::self()->bankAccountName(); _bacName->setText(h); h = KraftSettings::self()->bankAccountBIC(); _bacBIC->setText(h); h = KraftSettings::self()->bankAccountIBAN(); _bacIBAN->setText(h); } void PrefsDialog::writeIdentity() { /* * Save either the manually added address, or the Addressbook-ID * If the user fills in the manual form, the addressbook ID is removed. * FIXME: The handling of the ownIdentity should be refactored to its * own class. */ if(_tabWidget->currentIndex() == 1 /* manually entered */ ) { KContacts::Addressee add; add.setFormattedName(ui.leName->text()); add.setOrganization(ui.leOrganization->text()); KContacts::Address workAddress; workAddress.setStreet(ui.leStreet->text()); workAddress.setPostalCode(ui.lePostcode->text()); workAddress.setLocality(ui.leCity->text()); workAddress.setType(KContacts::Address::Work); add.insertAddress(workAddress); add.insertPhoneNumber(PhoneNumber(ui.lePhone->text(), KContacts::PhoneNumber::Work)); add.insertPhoneNumber(PhoneNumber(ui.leFax->text(), KContacts::PhoneNumber::Fax)); add.insertPhoneNumber(PhoneNumber(ui.leMobile->text(), KContacts::PhoneNumber::Cell)); ResourceLocatorUrl resUrl; resUrl.setUrl(QUrl(ui.leWebsite->text())); add.setUrl(resUrl); add.insertEmail(ui.leEmail->text(), true /* prefered */ ); VCardConverter vcc; QByteArray vcard = vcc.createVCard(add); QString file = QStandardPaths::writableLocation( QStandardPaths::AppDataLocation ); file += "/myidentity.vcd"; QFile f ( file ); if (f.open(QIODevice::WriteOnly | QIODevice::Text)) { f.write(vcard); f.close(); qDebug() << "Saved own identity to " << file; KraftSettings::self()->setUserName( QString() ); KraftSettings::self()->setUserUid( QString() ); KraftSettings::self()->save(); } } else { /* AddressBook */ KraftSettings::self()->setUserName( _newIdentity.name() ); KraftSettings::self()->setUserUid( _newIdentity.uid() ); KraftSettings::self()->save(); } emit newOwnIdentity(_newIdentity.uid(), _newIdentity); } void PrefsDialog::writeConfig() { KraftSettings::self()->setDoctype( mCbDocTypes->currentText() ); KraftSettings::self()->setDefaultTaxType( 1+mCbDefaultTaxType->currentIndex() ); DocType dt(QStringLiteral("Rechnung")); // FIXME const auto newTmpl = _lineEditXRechnung->text(); if (newTmpl != dt.xRechnungTemplate()) { dt.setXRechnungTemplate(newTmpl); dt.save(); } const QString demandText = _lineEditDemandText->text(); KraftSettings::self()->setDemandLabel(demandText); const QString alterText = _lineEditAlternativeText->text(); KraftSettings::self()->setAlternativeLabel(alterText); int dateFormat = mCbDateFormats->currentIndex(); QString dateFormatString; if (dateFormat == 0) { // iso dateFormatString = Format::DateFormatIso; } else if (dateFormat == 1) { // short dateFormatString = Format::DateFormatShort; } else if (dateFormat == 2) { // long dateFormatString = Format::DateFormatLong; } else if (dateFormat == 3) { // RFC dateFormatString = Format::DateFormatRFC; } else if (dateFormat == 4) { // German dateFormatString = Format::DateFormatGerman; } if (dateFormatString.isEmpty()) { // do not touch! } else { KraftSettings::self()->setDateFormat(dateFormatString); } QString h = _bacName->text(); if (h != KraftSettings::self()->bankAccountName()) { KraftSettings::self()->setBankAccountName(h); } h = _bacBIC->text(); if (h != KraftSettings::self()->bankAccountBIC()) { KraftSettings::self()->setBankAccountBIC(h); } h = _bacIBAN->text(); if (h != KraftSettings::self()->bankAccountIBAN()) { KraftSettings::self()->setBankAccountIBAN(h); } KraftSettings::self()->save(); } void PrefsDialog::writeTaxes() { mTaxModel->submitAll(); } PrefsDialog::~PrefsDialog() { } void PrefsDialog::accept() { mDocTypeEdit->saveDocTypes(); mPrefsWages->save(); mPrefsUnits->save(); writeTaxes(); writeConfig(); writeIdentity(); QDialog::accept(); } #define IDENTITY_TAG(X) QLatin1String(X) #define QL1(X) QStringLiteral(X) void PrefsDialog::fillManualIdentityForm(const KContacts::Addressee& addressee) { ui.leName->setText(addressee.formattedName()); ui.leStreet->setText(addressee.address(Address::Work).street()); ui.leCity->setText(addressee.address(Address::Work).locality()); ui.lePostcode->setText(addressee.address(Address::Work).postalCode()); ui.leEmail->setText(addressee.preferredEmail()); ui.leFax->setText(addressee.phoneNumber(PhoneNumber::Fax).number()); ui.leOrganization->setText(addressee.organization()); ui.lePhone->setText(addressee.phoneNumber(PhoneNumber::Work).number()); ui.leMobile->setText(addressee.phoneNumber(PhoneNumber::Cell).number()); ui.leWebsite->setText(addressee.url().url().toDisplayString()); } void PrefsDialog::setMyIdentity( const KContacts::Addressee& addressee, bool backendUp ) { // Note: This code is stolen from DocDigestDetailView::slotShowDocDetails // It should be refactored. const QString tmplFile = DefaultProvider::self()->locateFile( "views/identity.thtml" ); TextTemplate tmpl; tmpl.setTemplateFileName(tmplFile); if( !tmpl.isOk() ) { return; } if( ! tmpl.errorString().isEmpty() ) { mIdentityView->displayContent( QString("

            Unable to find template identity.trml

            %1

            ") .arg(tmpl.errorString())); return; } QString addressBookInfo; _pbChangeIdentity->setEnabled(backendUp); QPalette p; QColor c = p.color(QPalette::Normal, QPalette::ToolTipBase); tmpl.setValue(IDENTITY_TAG("CSS_WARN_BACKGROUND_COLOR"), c.name()); c = p.color(QPalette::Normal, QPalette::QPalette::Base); tmpl.setValue(IDENTITY_TAG("CSS_IDENTITY_IMAGE_BACKGROUND"), "#ea4e1d"); // c.name()); if( !backendUp ) { addressBookInfo = i18n("The identity can not be found."); tmpl.createDictionary(QL1("NO_IDENTITY")); tmpl.setValue(QL1("NO_IDENTITY_WRN"), i18n("

            Kraft Addressbook Integration down.

            " "

            The address book backend is not up and running.

            " "

            Please check your addressbook integration setup.

            ")); } if( addressee.isEmpty() ) { addressBookInfo = i18n("The identity is not listed in an address book."); tmpl.createDictionary(QL1("NO_IDENTITY")); tmpl.setValue(QL1("NO_IDENTITY_WRN"), i18n("

            Kraft does not know your identity.

            " "

            Please pick one from the address books by clicking on the Button below.

            " "

            Not having an identity selected can make your documents look incomplete.

            ")); } else { const QString origin = addressee.custom( CUSTOM_ADDRESS_MARKER ); if( origin.isEmpty() || origin == "manual") { // it is an manually added address. fillManualIdentityForm(addressee); _tabWidget->setTabIcon(1, DefaultProvider::self()->icon("check")); _tabWidget->setTabIcon(0, QIcon()); _tabWidget->setCurrentIndex(1); } else { _tabWidget->setTabIcon(0, DefaultProvider::self()->icon("check")); _tabWidget->setTabIcon(1, QIcon()); _tabWidget->setCurrentIndex(0); // it is an address from the address book addressBookInfo = i18n("Your identity can be found in the address books."); tmpl.createDictionary(QL1("IDENTITY")); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG("IDENTITY_NAME"), addressee.realName() ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG("IDENTITY_ORGANISATION"), addressee.organization() ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG("IDENTITY_URL"), addressee.url().toString() ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG("IDENTITY_EMAIL"), addressee.preferredEmail() ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG("IDENTITY_WORK_PHONE"), addressee.phoneNumber(PhoneNumber::Work).number()); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG("IDENTITY_MOBILE_PHONE"), addressee.phoneNumber(PhoneNumber::Cell).number()); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG("IDENTITY_FAX"), addressee.phoneNumber(PhoneNumber::Fax).number()); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG("WORK_PHONE_LABEL"), i18n("Work Phone") ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG("FAX_LABEL"), i18n("Fax") ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG("MOBILE_PHONE_LABEL"), i18n("Cell Phone") ); KContacts::Address myAddress; myAddress = addressee.address( KContacts::Address::Pref ); QString addressType = i18n("preferred address"); if( myAddress.isEmpty() ) { myAddress = addressee.address( KContacts::Address::Home ); addressType = i18n("home address"); } if( myAddress.isEmpty() ) { myAddress = addressee.address( KContacts::Address::Work ); addressType = i18n("work address"); } if( myAddress.isEmpty() ) { myAddress = addressee.address( KContacts::Address::Postal ); addressType = i18n("postal address"); } if( myAddress.isEmpty() ) { myAddress = addressee.address( KContacts::Address::Intl ); addressType = i18n("international address"); } if( myAddress.isEmpty() ) { myAddress = addressee.address( KContacts::Address::Dom ); addressType = i18n("domestic address"); } if( myAddress.isEmpty() ) { addressType = i18n("unknown"); // qDebug () << "WRN: Address is still empty!"; } tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG( "IDENTITY_POSTBOX" ), myAddress.postOfficeBox() ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG( "IDENTITY_EXTENDED" ), myAddress.extended() ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG( "IDENTITY_STREET" ), myAddress.street() ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG( "IDENTITY_LOCALITY" ), myAddress.locality() ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG( "IDENTITY_REGION" ), myAddress.region() ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG( "IDENTITY_POSTCODE" ), myAddress.postalCode() ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG( "IDENTITY_COUNTRY" ), myAddress.country() ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG( "IDENTITY_REGION" ), myAddress.region() ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG( "IDENTITY_LABEL" ), myAddress.label() ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG( "IDENTITY_ADDRESS_TYPE" ), QL1("(")+addressType+QL1(")") ); tmpl.setValue( QL1("IDENTITY"), IDENTITY_TAG("ADDRESSBOOK_INFO"), addressBookInfo ); } } const QString ex = tmpl.expand(); mIdentityView->displayContent(ex); } TaxItemDelegate::TaxItemDelegate(QObject * parent) : QItemDelegate(parent) {} void TaxItemDelegate::paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const { if(index.column() == 1 || index.column() == 2) { double percentage = index.data(Qt::DisplayRole).toDouble(); // QString string = DefaultProvider::self()->locale()->formatNumber(QString::number(percentage), true, 1); QString string = DefaultProvider::self()->locale()->toString(percentage); drawDisplay(painter, option, option.rect, string); } else if(index.column() == 3) { QDate date = index.data(Qt::DisplayRole).toDate(); // QString string = DefaultProvider::self()->locale()->formatDate(date); QString string = DefaultProvider::self()->locale()->toString(date); drawDisplay(painter, option, option.rect, string); } else { QItemDelegate::paint(painter, option, index); } } kraft-1.1/src/prefsdialog.h000066400000000000000000000071561450127457600157450ustar00rootroot00000000000000/*************************************************************************** prefsdialog.h - the preferences Dialog ------------------- begin : Sun Jul 3 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef PREFSDIALOG_H #define PREFSDIALOG_H #include #include #include "ui_identity.h" #include "doctypeedit.h" #include "doctype.h" #include "taxeditdialog.h" class QLineEdit; class QLabel; class QPushButton; class QComboBox; class QCheckBox; class QSqlTableModel; class QTreeView; class QPainter; class QStyleOptionViewItem; class QStackedWidget; class QModelIndex; class ImpTreeView; class PrefsWages; class PrefsUnits; class HtmlView; // ################################################################################ class PrefsDialog : public QDialog { Q_OBJECT public: PrefsDialog(QWidget *parent); ~PrefsDialog(); void setMyIdentity(const KContacts::Addressee& , bool backendUp); int addPage( QWidget *w, const QIcon& icon, const QString& title); protected: void readConfig(); void writeConfig(); protected slots: void accept(); void slotAddTax(); void slotDeleteTax(); void slotTaxSelected(QModelIndex); void slotDocTypeRemoved( const QString& ); void slotChangeIdentity(); void changePage(QListWidgetItem *current); signals: void newOwnIdentity(const QString&, KContacts::Addressee); private: int addDialogPage( QWidget *w, const QIcon& icon, const QString& title); QWidget *docTab(); QWidget* doctypeTab(); QWidget *taxTab(); void writeTaxes(); void writeIdentity(); QWidget *whoIsMeTab(); void fillManualIdentityForm(const KContacts::Addressee& addressee); QComboBox *m_databaseDriver; QLineEdit *m_leHost; QLineEdit *m_leUser; QLineEdit *m_leName; QLineEdit *m_lePasswd; QLineEdit *_lineEditXRechnung; QLineEdit *_lineEditDemandText; QLineEdit *_lineEditAlternativeText; QLabel *m_statusLabel; QWidget *m_mysqlpart; QWidget *m_sqlitepart; QStackedWidget *m_databaseconfigparts; QComboBox *mCbDocTypes; QComboBox *mCbDefaultTaxType; QComboBox *mCbDateFormats; QPushButton *_pbChangeIdentity; DocTypeEdit *mDocTypeEdit; PrefsWages *mPrefsWages; PrefsUnits *mPrefsUnits; KContacts::Addressee _newIdentity; QPushButton *mDelTax; ImpTreeView *mTaxTreeView; QSqlTableModel *mTaxModel; HtmlView *mIdentityView; QListWidget *_navigationBar; QStackedWidget *_pagesWidget; QTabWidget *_tabWidget; Ui::manualOwnIdentity ui; QLineEdit *_bacName; QLineEdit *_bacIBAN; QLineEdit *_bacBIC; int _maxNavBarTextWidth; }; class TaxItemDelegate : public QItemDelegate { Q_OBJECT public: TaxItemDelegate(QObject * parent = 0); virtual void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; }; #endif kraft-1.1/src/prefsunits.cpp000066400000000000000000000147271450127457600162050ustar00rootroot00000000000000/*************************************************************************** prefsunits.cpp - the units tab in the prefs dialog ------------------- begin : Feb 26 2010 copyright : (C) 2010 by Thomas Richard email : thomas.richard@proan.be ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "defaultprovider.h" #include "impviewwidgets.h" #include "geld.h" #include "unitmanager.h" #include "prefsunits.h" PrefsUnits::PrefsUnits(QWidget* parent) : QWidget(parent) { QVBoxLayout *vboxLay = new QVBoxLayout; mUnitsModel = new QSqlTableModel(this); mUnitsModel->setTable("units"); mUnitsModel->setEditStrategy(QSqlTableModel::OnManualSubmit); mUnitsModel->select(); mUnitsModel->setHeaderData(0, Qt::Horizontal, i18n("ID")); mUnitsModel->setHeaderData(1, Qt::Horizontal, i18n("Short")); mUnitsModel->setHeaderData(2, Qt::Horizontal, i18n("Long")); mUnitsModel->setHeaderData(3, Qt::Horizontal, i18n("Short plural")); mUnitsModel->setHeaderData(4, Qt::Horizontal, i18n("Long plural")); mUnitsModel->setHeaderData(5, Qt::Horizontal, i18n("ECE20")); mProxyModel = new QSortFilterProxyModel(this); mProxyModel->setSourceModel(mUnitsModel); mUnitsTreeView = new ImpTreeView; vboxLay->addWidget( mUnitsTreeView ); mUnitsTreeView->setModel(mProxyModel); mUnitsTreeView->hideColumn(0); mUnitsTreeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); mUnitsTreeView->setEditTriggers(ImpTreeView::NoEditTriggers); connect( mUnitsTreeView, SIGNAL(clicked(QModelIndex)), SLOT( slotUnitSelected(QModelIndex) ) ); connect( mUnitsTreeView, SIGNAL(doubleClicked(QModelIndex)), SLOT(slotEditUnit(QModelIndex))); QHBoxLayout *butLay = new QHBoxLayout; butLay->addStretch( 1 ); QPushButton *but = new QPushButton( DefaultProvider::self()->icon("plus"), i18n( "Add" )); connect( but, SIGNAL( clicked() ), SLOT( slotAddUnit() ) ); butLay->addWidget( but ); mEditUnit = new QPushButton( DefaultProvider::self()->icon("pencil"), i18n( "Edit" )); connect( mEditUnit, SIGNAL( clicked() ), SLOT( slotEditUnit() ) ); butLay->addWidget( mEditUnit ); mEditUnit->setEnabled(false); mDelUnit = new QPushButton( DefaultProvider::self()->icon("minus"), i18n( "Remove" ) ); connect( mDelUnit, SIGNAL( clicked() ), SLOT( slotDeleteUnit() ) ); butLay->addWidget( mDelUnit ); mDelUnit->setEnabled( false ); vboxLay->addLayout( butLay ); this->setLayout( vboxLay ); } PrefsUnits::~PrefsUnits() { } void PrefsUnits::save() { bool ok = mUnitsModel->submitAll(); if( ! ok ) { QString err = mUnitsModel->lastError().text(); // qDebug () << "SQL Error: " << err; } } void PrefsUnits::slotAddUnit() { UnitsEditDialog *dialog = new UnitsEditDialog(mUnitsModel, -1, this); dialog->show(); } void PrefsUnits::slotEditUnit(QModelIndex /* index */ ) { if ( mUnitsTreeView->currentIndex().isValid() ) { int row = mUnitsTreeView->currentIndex().row(); UnitsEditDialog *dialog = new UnitsEditDialog(mUnitsModel, row, this); dialog->show(); } } void PrefsUnits::slotDeleteUnit() { if ( mUnitsTreeView->currentIndex().isValid() ) { int row = mUnitsTreeView->currentIndex().row(); mUnitsModel->removeRows(row, 1); } } void PrefsUnits::slotUnitSelected(QModelIndex) { bool state = false; if ( mUnitsTreeView->currentIndex().isValid() ) { state = true; } mEditUnit->setEnabled( state ); mDelUnit->setEnabled( state ); } UnitsEditDialog::UnitsEditDialog( QAbstractItemModel *model, int row, QWidget *parent ) : QDialog( parent ) { setObjectName( "UNITS_EDIT_DIALOG" ); setModal( true ); setWindowTitle( i18n( "Edit a unit" ) ); QWidget *mainWidget = new QWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(mainWidget); QWidget *w = new QWidget( this ); mainLayout->addWidget(w); mBaseWidget = new Ui::UnitsEditBase( ); mBaseWidget->setupUi( w ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(buttonBox); mModel = model; mapper = new QDataWidgetMapper(this); mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); mapper->setModel(model); mapper->addMapping(mBaseWidget->mUnitShort, 1); mapper->addMapping(mBaseWidget->mUnitLong, 2); mapper->addMapping(mBaseWidget->mUnitPluShort, 3); mapper->addMapping(mBaseWidget->mUnitPluLong, 4); mapper->addMapping(mBaseWidget->mUnitECE20, 5); if(row == -1) { //Insert a new row at the end int row = model->rowCount(); if( model->insertRow(row) ) { int indx = UnitManager::self()->nextFreeId(); model->setData( model->index(row, 0), indx ); mapper->toLast(); } } else { mBaseWidget->mLabel->setText(i18n("

            Edit unit

            ")); mapper->setCurrentIndex(row); } mRow = row; } void UnitsEditDialog::accept() { bool ok = mapper->submit(); if(!ok) { qDebug () << "UnitsEditDialog Mapper submit result: " << ok; } QDialog::accept(); deleteLater(); } void UnitsEditDialog::reject() { if(mRow == -1) mModel->removeRow(mModel->rowCount()-1); QDialog::reject(); deleteLater(); } kraft-1.1/src/prefsunits.h000066400000000000000000000041341450127457600156410ustar00rootroot00000000000000/*************************************************************************** prefsunits.h - the units tab in the prefs dialog ------------------- begin : Feb 28 2010 copyright : (C) 2010 by Thomas Richard email : thomas.richard@proan.be ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef PREFSUNITS_H #define PREFSUNITS_H #include #include #include #include "ui_unitseditbase.h" class QModelIndex; class QPushButton; class ImpTreeView; class QAbstractItemModel; class QDataWidgetMapper; class QSqlTableModel; class QSortFilterProxyModel; class PrefsUnits : public QWidget { Q_OBJECT public: PrefsUnits(QWidget* parent); ~PrefsUnits(); void save(); public slots: void slotAddUnit(); void slotEditUnit(QModelIndex index = QModelIndex()); void slotDeleteUnit(); void slotUnitSelected(QModelIndex); private: QPushButton *mDelUnit; QPushButton *mEditUnit; ImpTreeView *mUnitsTreeView; QSqlTableModel *mUnitsModel; QSortFilterProxyModel *mProxyModel; }; class UnitsEditDialog: public QDialog, protected Ui::UnitsEditBase { Q_OBJECT public: UnitsEditDialog( QAbstractItemModel *model, int row, QWidget *parent ); public slots: void accept(); void reject(); private: Ui::UnitsEditBase *mBaseWidget; QDataWidgetMapper *mapper; QAbstractItemModel *mModel; int mRow; }; #endif kraft-1.1/src/prefswages.cpp000066400000000000000000000206651450127457600161470ustar00rootroot00000000000000/*************************************************************************** prefswages.cpp - the wages tab in the prefs dialog ------------------- begin : Feb 26 2010 copyright : (C) 2010 by Thomas Richard email : thomas.richard@proan.be ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include "defaultprovider.h" #include "impviewwidgets.h" #include "geld.h" #include "defaultprovider.h" #include "prefswages.h" PrefsWages::PrefsWages(QWidget* parent) : QWidget(parent) { QVBoxLayout *vboxLay = new QVBoxLayout; mWagesModel = new QSqlTableModel(this); mWagesModel->setTable("stdSaetze"); mWagesModel->setSort(3, Qt::AscendingOrder); mWagesModel->setEditStrategy(QSqlTableModel::OnManualSubmit); mWagesModel->select(); mWagesModel->setHeaderData(0, Qt::Horizontal, i18n("ID")); mWagesModel->setHeaderData(1, Qt::Horizontal, i18n("Code")); mWagesModel->setHeaderData(2, Qt::Horizontal, i18n("Price")); mWagesModel->setHeaderData(3, Qt::Horizontal, i18n("Sortkey")); mProxyModel = new QSortFilterProxyModel(this); mProxyModel->setSourceModel(mWagesModel); mWagesTreeView = new ImpTreeView; vboxLay->addWidget( mWagesTreeView ); mWagesTreeView->setModel(mProxyModel); mWagesTreeView->setItemDelegate(new WagesItemDelegate()); mWagesTreeView->hideColumn(0); mWagesTreeView->hideColumn(3); mWagesTreeView->header()->stretchLastSection(); mWagesTreeView->setColumnWidth(1, 200); mWagesTreeView->resizeColumnToContents(2); mWagesTreeView->resizeColumnToContents(1); mWagesTreeView->setEditTriggers(ImpTreeView::NoEditTriggers); connect( mWagesTreeView, SIGNAL(clicked(QModelIndex)), SLOT( slotWageSelected(QModelIndex) ) ); connect( mWagesTreeView, SIGNAL(doubleClicked(QModelIndex)), SLOT(slotEditWage(QModelIndex))); QHBoxLayout *butLay = new QHBoxLayout; butLay->addStretch( 1 ); mUp = new QPushButton( DefaultProvider::self()->icon("arrow-up"), i18n( "Up" )); connect( mUp, SIGNAL( clicked() ), SLOT( slotUp() ) ); butLay->addWidget( mUp ); mUp->setEnabled(false); mDown = new QPushButton( DefaultProvider::self()->icon("arrow-down"), i18n( "Down" )); connect( mDown, SIGNAL( clicked() ), SLOT( slotDown() ) ); butLay->addWidget( mDown ); mDown->setEnabled(false); QPushButton *but = new QPushButton( DefaultProvider::self()->icon("plus"), i18n( "Add" )); connect( but, SIGNAL( clicked() ), SLOT( slotAddWage() ) ); butLay->addWidget( but ); mEditWage = new QPushButton( DefaultProvider::self()->icon("pencil"), i18n( "Edit" )); connect( mEditWage, SIGNAL( clicked() ), SLOT( slotEditWage() ) ); butLay->addWidget( mEditWage ); mEditWage->setEnabled(false); mDelWage = new QPushButton( DefaultProvider::self()->icon("minus"), i18n( "Remove" ) ); connect( mDelWage, SIGNAL( clicked() ), SLOT( slotDeleteWage() ) ); butLay->addWidget( mDelWage ); mDelWage->setEnabled( false ); vboxLay->addLayout( butLay ); this->setLayout( vboxLay ); } PrefsWages::~PrefsWages() { } void PrefsWages::save() { mWagesModel->submitAll(); } void PrefsWages::slotAddWage() { WagesEditDialog *dialog = new WagesEditDialog(mWagesModel, -1, this); dialog->show(); } void PrefsWages::slotEditWage(QModelIndex /* index */ ) { if ( mWagesTreeView->currentIndex().isValid() ) { int row = mWagesTreeView->currentIndex().row(); WagesEditDialog *dialog = new WagesEditDialog(mWagesModel, row, this); dialog->show(); } } void PrefsWages::slotDeleteWage() { if ( mWagesTreeView->currentIndex().isValid() ) { int row = mWagesTreeView->currentIndex().row(); mWagesModel->removeRows(row, 1); } } void PrefsWages::slotWageSelected(QModelIndex) { bool state = false; if ( mWagesTreeView->currentIndex().isValid() ) { state = true; } mEditWage->setEnabled( state ); mDelWage->setEnabled( state ); mUp->setEnabled( state ); mDown->setEnabled( state ); if(mWagesTreeView->currentIndex().row() == 0) mUp->setEnabled(false); if(mWagesTreeView->currentIndex().row() == (mProxyModel->rowCount() - 1)) mDown->setEnabled(false); } void PrefsWages::slotUp() { if ( mWagesTreeView->currentIndex().isValid() ) { int row = mWagesTreeView->currentIndex().row(); if(row != 0) { mProxyModel->setData(mProxyModel->index(row, 3), row, Qt::DisplayRole); mProxyModel->setData(mProxyModel->index(row, 3), row, Qt::EditRole); mProxyModel->setData(mProxyModel->index(row-1, 3), row + 1, Qt::DisplayRole); mProxyModel->setData(mProxyModel->index(row-1, 3), row + 1, Qt::EditRole); mProxyModel->sort(3, Qt::AscendingOrder); slotWageSelected(mWagesTreeView->currentIndex()); } } } void PrefsWages::slotDown() { if ( mWagesTreeView->currentIndex().isValid() ) { int row = mWagesTreeView->currentIndex().row(); if(row != (mProxyModel->rowCount() - 1)) { mProxyModel->setData(mProxyModel->index(row, 3), row + 2, Qt::DisplayRole); mProxyModel->setData(mProxyModel->index(row, 3), row + 2, Qt::EditRole); mProxyModel->setData(mProxyModel->index(row+1, 3), row + 1, Qt::DisplayRole); mProxyModel->setData(mProxyModel->index(row+1, 3), row + 1, Qt::EditRole); mProxyModel->sort(3, Qt::AscendingOrder); slotWageSelected(mWagesTreeView->currentIndex()); } } } WagesEditDialog::WagesEditDialog( QAbstractItemModel *model, int row, QWidget *parent ) : QDialog( parent ) { setObjectName( "WAGES_EDIT_DIALOG" ); setModal( true ); setWindowTitle( i18n( "Edit a wage group" ) ); QWidget *mainWidget = new QWidget; QVBoxLayout *mainLayout = new QVBoxLayout; QWidget *w = new QWidget; mainLayout->addWidget(w); mBaseWidget = new Ui::WagesEditBase( ); mBaseWidget->setupUi( w ); mBaseWidget->mWage->setSuffix( DefaultProvider::self()->currencySymbol() ); mBaseWidget->mWage->setMinimum( 0 ); mBaseWidget->mWage->setMaximum( 100000 ); mBaseWidget->mWage->setDecimals( 2 ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); setLayout(mainLayout); mainLayout->addWidget(mainWidget); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(buttonBox); mModel = model; mapper = new QDataWidgetMapper(this); mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); mapper->setModel(model); mapper->addMapping(mBaseWidget->mGroupName, 1); mapper->addMapping(mBaseWidget->mWage, 2); if(row == -1) { //Insert a new row at the end model->insertRow(model->rowCount()); mapper->toLast(); } else { mBaseWidget->mLabel->setText(i18n("

            Edit wage group

            ")); mapper->setCurrentIndex(row); } mRow = row; } void WagesEditDialog::accept() { mapper->submit(); QDialog::accept(); } void WagesEditDialog::reject() { if(mRow == -1) mModel->removeRow(mModel->rowCount()-1); QDialog::reject(); } WagesItemDelegate::WagesItemDelegate(QObject * parent) : QItemDelegate(parent) {} void WagesItemDelegate::paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const { if(index.column() == 2) { Geld wage = index.data(Qt::DisplayRole).toDouble(); QString string = wage.toLocaleString(); drawDisplay(painter, option, option.rect, string); } else { QItemDelegate::paint(painter, option, index); } } kraft-1.1/src/prefswages.h000066400000000000000000000046321450127457600156100ustar00rootroot00000000000000/*************************************************************************** prefswages.h - the wages tab in the prefs dialog ------------------- begin : Feb 26 2010 copyright : (C) 2010 by Thomas Richard email : thomas.richard@proan.be ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef PREFSWAGES_H #define PREFSWAGES_H #include #include #include #include "ui_wageseditbase.h" class QModelIndex; class QPushButton; class ImpTreeView; class QAbstractItemModel; class QDataWidgetMapper; class QSqlTableModel; class QSortFilterProxyModel; class PrefsWages : public QWidget { Q_OBJECT public: PrefsWages(QWidget* parent); ~PrefsWages(); void save(); public slots: void slotAddWage(); void slotEditWage(QModelIndex index = QModelIndex()); void slotDeleteWage(); void slotWageSelected(QModelIndex); void slotUp(); void slotDown(); private: QPushButton *mDelWage; QPushButton *mEditWage; QPushButton *mUp; QPushButton *mDown; ImpTreeView *mWagesTreeView; QSqlTableModel *mWagesModel; QSortFilterProxyModel *mProxyModel; }; class WagesEditDialog: public QDialog, protected Ui::WagesEditBase { Q_OBJECT public: WagesEditDialog( QAbstractItemModel *model, int row, QWidget *parent ); public slots: void accept(); void reject(); private: Ui::WagesEditBase *mBaseWidget; QDataWidgetMapper *mapper; QAbstractItemModel *mModel; int mRow; }; class WagesItemDelegate : public QItemDelegate { Q_OBJECT public: WagesItemDelegate(QObject * parent = 0); virtual void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; }; #endif kraft-1.1/src/reportgenerator.cpp000066400000000000000000000316111450127457600172140ustar00rootroot00000000000000/*************************************************************************** Report Generator based on Reportlab ------------------- begin : July 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "reportgenerator.h" #include "kraftdoc.h" #include "kraftdb.h" #include "unitmanager.h" #include "dbids.h" #include "kraftsettings.h" #include "docposition.h" #include "einheit.h" #include "archiveman.h" #include "archdoc.h" #include "documentman.h" #include "texttemplate.h" #include "defaultprovider.h" #include "doctype.h" #include "addressprovider.h" #include "grantleetemplate.h" #include "documenttemplate.h" #include "pdfconverter.h" namespace { QString saveToTempFile( const QString& doc ) { if ( ! doc.isEmpty() ) { QTemporaryFile temp; temp.setAutoRemove( false ); if ( temp.open() ) { QTextStream s(&temp); // The following explicit coding settings were needed for Qt 4.7.3, former Qt versions // seemed to default on UTF-8. Try to comment the following two lines for older Qt versions // if needed and see if the trml file on the disk still is UTF-8 encoded. QTextCodec *codec = QTextCodec::codecForName("UTF-8"); s.setCodec( codec ); s << doc; temp.close(); } else { // qDebug () << "ERROR: Could not open temporar file"; } qDebug () << "Wrote rml to " << temp.fileName(); return temp.fileName(); } return QString(); } } ReportGenerator::ReportGenerator() : _useGrantlee(true), mProcess(nullptr) { mAddressProvider = new AddressProvider(this); connect(mAddressProvider, &AddressProvider::lookupResult, this, &ReportGenerator::slotAddresseeFound); } ReportGenerator::~ReportGenerator() { // qDebug () << "ReportGen is destroyed!"; } /* * docID: document ID * dbId: database ID of the archived doc. * * This is the starting point of a report creation. */ void ReportGenerator::createDocument( ReportFormat format, const QString& docID, dbID archId ) { mDocId = docID; mArchId = archId; _requestedFormat = format; if( mProcess && mProcess->state() != QProcess::NotRunning ) { qDebug() << "===> WRN: Process still running, try again later."; emit failure(i18n("Document generation process is still running."), ""); return; } // now the addressee search through the address provider is finished. // Rendering can be started. _archDoc.loadFromDb(archId); // the next call also sets the watermark options const QString dt = _archDoc.docTypeStr(); _tmplFile = findTemplateFile( dt ); if ( _tmplFile.isEmpty() ) { qDebug () << "tmplFile is empty, exit reportgenerator!"; return; } else { qDebug () << "Using this template: " << _tmplFile; } lookupCustomerAddress(); } void ReportGenerator::lookupCustomerAddress() { const QString clientUid = _archDoc.clientUid(); KContacts::Addressee contact; if( ! clientUid.isEmpty() ) { AddressProvider::LookupState state = mAddressProvider->lookupAddressee( clientUid ); switch( state ) { case AddressProvider::LookupFromCache: contact = mAddressProvider->getAddresseeFromCache(clientUid); break; case AddressProvider::LookupNotFound: case AddressProvider::ItemError: case AddressProvider::BackendError: // set an empty contact break; case AddressProvider::LookupOngoing: case AddressProvider::LookupStarted: // Not much to do, just wait and let the addressprovider // hit the slotAddresseFound return; } } slotAddresseeFound(clientUid, contact); } void ReportGenerator::slotAddresseeFound( const QString&, const KContacts::Addressee& contact ) { mCustomerContact = contact; // now the three pillars archDoc, myContact and mCustomerContact are defined. QFileInfo fi(_tmplFile); if (!fi.exists()) { emit failure(i18n("Template file is not accessible."), ""); return; } const QString ext = fi.completeSuffix(); QScopedPointer templateEngine; QPointer converter; if (QString::compare(ext, QStringLiteral("trml"), Qt::CaseInsensitive) == 0) { // use the old ctemplate engine with reportlab. templateEngine.reset(new CTemplateDocumentTemplate(_tmplFile)); converter = new ReportLabPDFConverter; } else { // use Grantlee. templateEngine.reset(new GrantleeDocumentTemplate(_tmplFile)); converter = new WeasyPrintPDFConverter; } converter->setTemplatePath(fi.path()); // expand the template... const QString expanded = templateEngine->expand(&_archDoc, myContact, mCustomerContact); _cleanupFiles = templateEngine->tempFilesCreated(); if (expanded.isEmpty()) { emit failure(i18n("The template conversion failed."), templateEngine->error()); delete converter; return; } // ... and save to a tempoarary file const QString tempFile = saveToTempFile(expanded); if (tempFile.isEmpty()) { emit failure(i18n("Saving to temporar file failed."), ""); delete converter; return; } _cleanupFiles.append(tempFile); QString fullOutputFilePath = targetFileName(); if (mMergeIdent >= 0 && mMergeIdent < 5 ) { // check if the watermark file exists QFileInfo fi(mWatermarkFile); if (!mWatermarkFile.isEmpty() && fi.isReadable()) { QTemporaryFile tmpFile; tmpFile.open(); tmpFile.close(); // PDF merge is required. Write to temp file fullOutputFilePath = tmpFile.fileName() + QStringLiteral(".pdf"); } else { mMergeIdent = 0; qDebug() << "Can not read watermark file, generating without" << mWatermarkFile; } } // Now there is the completed, expanded document source. connect( converter, &PDFConverter::docAvailable, this, &ReportGenerator::slotPdfDocAvailable); connect( converter, &PDFConverter::converterError, this, &ReportGenerator::slotConverterError); converter->convert(tempFile, fullOutputFilePath); } void ReportGenerator::slotPdfDocAvailable(const QString& file) { QObject *s = sender(); qDebug() << "The document is finished!:" << file; s->deleteLater(); // Remove tmp files that might have been created during the template expansion, // ie. the EPC QR Code SVG file. #ifndef QT_DEBUG for (const auto &file : _cleanupFiles) { QFile::remove(file); } #endif _cleanupFiles.clear(); // check for the watermark requirements if (mMergeIdent > 0 && mMergeIdent < 5) { // check if the watermark file exists mergePdfWatermark(file); } else { emit docAvailable(_requestedFormat, file, mCustomerContact); } } void ReportGenerator::mergePdfWatermark(const QString& file) { mProcess = new QProcess(); connect(mProcess, QOverload::of(&QProcess::finished), this, &ReportGenerator::pdfMergeFinished); QStringList args; if (mMergeIdent > 0) { const QStringList prg = DefaultProvider::self()->locatePythonTool(QStringLiteral("watermarkpdf.py")); if (!prg.isEmpty() && !mWatermarkFile.isEmpty()) { mProcess->setProgram(prg.at(0)); args << prg.at(1); args << QStringLiteral("-m") << QString::number(mMergeIdent); args << QStringLiteral("-o") << targetFileName(); if (!mPdfAppendFile.isEmpty()) { args << QStringLiteral("-a") << mPdfAppendFile; } args << mWatermarkFile; args << file; qDebug() << "Merge PDF Watermark args:" << args; mProcess->setArguments(args); mProcess->start( ); } else { qDebug() << "Watermark err:" << (prg.isEmpty() ? "Program" : "watermark file") << "is empty"; } } else { // no watermark is wanted, copy the converted file over. args << file; mProcess->setArguments(args); const QString target = targetFileName(); if (QFile::copy(file, target)) { pdfMergeFinished(0, QProcess::ExitStatus::NormalExit); } else { qDebug() << "ERR: Failed to copy temporary file"; } } } void ReportGenerator::pdfMergeFinished(int exitCode, QProcess::ExitStatus exitStatus) { mWatermarkFile.clear(); mPdfAppendFile.clear(); mMergeIdent = 0; if (exitStatus == QProcess::ExitStatus::NormalExit && exitCode == 0) { const QString fileName = targetFileName(); // remove the temp file which comes as arg in any case, even if the watermark // tool was not called. if (mProcess->arguments().size() > 0) { const QString tmpFile = mProcess->arguments().last(); QFile::remove(tmpFile); } mProcess->deleteLater(); mProcess = nullptr; emit docAvailable(_requestedFormat, fileName, mCustomerContact); } else { slotConverterError(PDFConverter::ConvError::PDFMergerError); } } void ReportGenerator::slotConverterError(PDFConverter::ConvError err) { auto *converter = qobject_cast(sender()); const QString errors = converter->getErrors(); QString errMsg; switch(err) { case PDFConverter::ConvError::NoError: errMsg = i18n("No converter error."); break; case PDFConverter::ConvError::TrmlToolFail: errMsg = i18n("The ReportLab based converter script can not be executed."); break; case PDFConverter::ConvError::UnknownError: errMsg = i18n("An unknown error happened."); break; case PDFConverter::ConvError::NoReportLabMod: errMsg = i18n("The ReportLab python module is not installed."); break; case PDFConverter::ConvError::NoPyPDFMod: errMsg = i18n("The PyPDF2 python module is not installed."); break; case PDFConverter::ConvError::SourceFileFail: errMsg = i18n("The source file can not be read."); break; case PDFConverter::ConvError::TargetFileError: errMsg = i18n("The target can not be opened to write."); break; case PDFConverter::ConvError::TargetFileMissing: errMsg = i18n("The target file does not exist."); break; case PDFConverter::ConvError::WeasyPrintNotFound: errMsg = i18n("The WeasyPrint tool is not installed."); break; case PDFConverter::ConvError::PDFMergerError: errMsg = i18n("The PDF merger utility failed."); break; } emit failure(errMsg, errors); converter->deleteLater(); } QString ReportGenerator::targetFileName() const { ArchDocDigest dig = _archDoc.toDigest(); return dig.pdfArchiveFileName(); } QString ReportGenerator::findTemplateFile( const QString& type ) { DocType dType( type ); const QString tmplFile = dType.templateFile(); if ( tmplFile.isEmpty() ) { emit failure(i18n("There is not template defined for %1.").arg(dType.name()), ""); } else { // check if file exists QFileInfo fi(tmplFile); if (!fi.isFile()) { emit failure(i18n("The template file %1 for document type %2 does not exist.").arg(tmplFile).arg(dType.name()), ""); return QString(); } if (!fi.isReadable()) { emit failure(i18n("The template file %1 for document type %2 can not be read.").arg(tmplFile).arg(dType.name()), ""); return QString(); } } mMergeIdent = dType.mergeIdent().toInt(); mWatermarkFile = dType.watermarkFile(); mPdfAppendFile = dType.appendPDF(); return tmplFile; } void ReportGenerator::setMyContact( const KContacts::Addressee& contact ) { myContact = contact; } kraft-1.1/src/reportgenerator.h000066400000000000000000000065331450127457600166660ustar00rootroot00000000000000/*************************************************************************** reportgenerator.h - report generation ------------------- begin : July 2006 copyright : (C) 2006 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef REPORTGENERATOR_H #define REPORTGENERATOR_H #include #include #include #include #include #include "kraftdoc.h" #include "archdoc.h" #include "pdfconverter.h" class dbID; class KJob; class QFile; class AddressProvider; class TextTemplate; enum class ReportFormat { PDF, PDFMail, HTML }; class ReportGenerator : public QObject { Q_OBJECT public: ReportGenerator(); ~ReportGenerator(); signals: void docAvailable( ReportFormat, const QString& file, const KContacts::Addressee& customerContact); void failure(const QString&, const QString&); public slots: void createDocument(ReportFormat, const QString&, dbID ); void setMyContact( const KContacts::Addressee& ); private slots: void slotPdfDocAvailable(const QString& file); void slotConverterError(PDFConverter::ConvError err); void mergePdfWatermark(const QString &file); void pdfMergeFinished(int exitCode, QProcess::ExitStatus exitStatus); private: QString findTemplateFile( const QString& ); void lookupCustomerAddress(); QString _tmplFile; ArchDoc _archDoc; protected: QStringList _cleanupFiles; protected slots: void slotAddresseeFound( const QString&, const KContacts::Addressee& ); private: void convertTemplate( const QString& ); void fillupTemplateFromArchive( const dbID& ); void contactToTemplate( TextTemplate*, const QString&, const KContacts::Addressee& ); QString registerDictionary( const QString&, const QString& ) const; QString registerTag( const QString&, const QString& ) const; QString registerDictTag( const QString&, const QString&, const QString& ) const; QString targetFileName() const; QString escapeTrml2pdfXML( const QString& str ) const; QString rmlString( const QString& str, const QString& paraStyle = QString() ) const; bool _useGrantlee; QString mErrors; int mMergeIdent; bool mHavePdfMerge; QString mWatermarkFile; QString mPdfAppendFile; QString mDocId; dbID mArchId; long mOutputSize; KContacts::Addressee mCustomerContact; KContacts::Addressee myContact; QPointer mProcess; QFile mFile; QDataStream mTargetStream; AddressProvider *mAddressProvider; ReportFormat _requestedFormat; }; #endif kraft-1.1/src/setupassistant.cpp000066400000000000000000000731021450127457600170650ustar00rootroot00000000000000/*************************************************************************** setupassistant - assistant to setup kraft from scratch ------------------- begin : 2009-12-26 copyright : (C) 2009 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include "setupassistant.h" #include "databasesettings.h" #include "defaultprovider.h" #include "kraftdb.h" #include "addressselectorwidget.h" #include "kraftsettings.h" WelcomePage::WelcomePage(QWidget *parent) :QWizardPage(parent) { setTitle( i18n("Welcome to the Kraft Setup Assistant")); QVBoxLayout *vbox = new QVBoxLayout; setLayout( vbox ); QWidget *w = new QWidget; vbox->addWidget( w ); ui.setupUi(w); } void WelcomePage::setWelcomeText( const QString& txt ) { ui.mStatusText->setText( txt ); } // --------------------------------------------------------------------------- DbSelectPage::DbSelectPage(QWidget *parent) :QWizardPage(parent) { setTitle(i18n("Select the Database Backend")); QVBoxLayout *vbox = new QVBoxLayout; setLayout( vbox ); QWidget *w = new QWidget; vbox->addWidget( w ); ui.setupUi(w); registerField("SelectedDbDriverSqlite", ui.mRbSqlite3); registerField("SelectedDbDriverMySql", ui.mRbMySQL); } int DbSelectPage::nextId() const { if( ui.mRbSqlite3->isChecked() ) { return SetupAssistant::sqlitePageNo; } else { return SetupAssistant::mySqlPageNo; } } QString DbSelectPage::selectedDriver() const { QString re = "QSQLITE"; if( field("SelectedDbDriverMySql").toBool() ) { re = "QMYSQL"; } return re; } // --------------------------------------------------------------------------- SqLiteDetailsPage::SqLiteDetailsPage(QWidget *parent) :QWizardPage(parent) { setTitle(i18n("Sqlite File Name")); QVBoxLayout *vbox = new QVBoxLayout; setLayout(vbox); QWidget *w = new QWidget; vbox->addWidget( w ); ui.setupUi(w); // ui.mFileUrl->setText(DatabaseSettings::self()->dbFile()); registerField("DefaultSqliteStorage", ui.mRbDefault ); registerField("SqliteStorageFile", ui._fileName); // Preset the sqlite storage const QString fileName = DatabaseSettings::self()->dbFile(); if( ! fileName.isEmpty()) { ui.mRbCustom->setChecked(true); setField("SqliteStorageFile", fileName); } } QUrl SqLiteDetailsPage::url() { QString fileName; if( ui.mRbDefault->isChecked() ) { fileName = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); } else { fileName = ui._fileName->text(); } if( ! fileName.endsWith("/")) fileName += QLatin1String("/"); fileName += QLatin1String("kraft.db"); return QUrl::fromLocalFile(fileName); } bool SqLiteDetailsPage::validatePage() { return qobject_cast(wizard())->handleSqLiteDetails(); } int SqLiteDetailsPage::nextId() const { if( KraftDB::self()->databaseExists() ) { return SetupAssistant::upgradeDbPageNo; } else { return SetupAssistant::createDbPageNo; } } // --------------------------------------------------------------------------- MysqlDetailsPage::MysqlDetailsPage(QWidget *parent) :QWizardPage(parent) { setTitle(i18n("MySql Detail Information")); QVBoxLayout *vbox = new QVBoxLayout; setLayout( vbox ); QWidget *w = new QWidget; vbox->addWidget( w ); ui.setupUi(w); registerField("MySqlHost", ui.mMysqlHost); registerField("MySqlUser", ui.mMysqUser ); registerField("MySqlDbName", ui.mMysqlDbName); registerField("MySqlPwd", ui.mMysqlPwd ); reloadSettings(); } void MysqlDetailsPage::reloadSettings() { setField("MySqlHost", DatabaseSettings::self()->dbServerName()); setField("MySqlUser", DatabaseSettings::self()->dbUser()); setField("MySqlDbName", DatabaseSettings::self()->dbDatabaseName()); setField("MySqlPwd", DatabaseSettings::self()->dbPassword()); } int MysqlDetailsPage::nextId() const { if( KraftDB::self()->databaseExists() ) { return SetupAssistant::upgradeDbPageNo; } else { return SetupAssistant::createDbPageNo; } } bool MysqlDetailsPage::validatePage() { bool re = qobject_cast(wizard())->handleMysqlDetails(); return re; } // --------------------------------------------------------------------------- CreateDbPage::CreateDbPage(QWidget *parent) :QWizardPage(parent) { setTitle(i18n("Create Database")); QVBoxLayout *vbox = new QVBoxLayout; setLayout( vbox ); QWidget *w = new QWidget; vbox->addWidget( w ); ui.setupUi(w); registerField("CreateDbStatusText", ui.mCreateStatus); } void CreateDbPage::setStatusText( const QString& t ) { ui.mCreateStatus->setText( t ); } void CreateDbPage::setFillCmdsCount( int cnt ) { mFills = 0; ui.mFillProgress->setMaximum( cnt ); ui.mFillProgress->setValue( 0 ); ui.mFillCounter->setText( i18n("0/%1", cnt) ); } void CreateDbPage::setFillCmdsCurrent( int cnt ) { ui.mFillProgress->setValue( cnt ); } void CreateDbPage::setCreateCmdsCount( int cnt ) { mCreates = 0; ui.mCreateProgress->setMaximum( cnt ); ui.mCreateProgress->setValue( 0 ); ui.mCreateCounter->setText( i18n("0/%1", cnt)); } void CreateDbPage::setCreateCmdsCurrent( int cnt ) { ui.mCreateProgress->setValue( cnt ); } void CreateDbPage::slotStatusMessage( const QString& msg ) { // qDebug () << "############### success: " << msg; ui.mCreateStatus->setText( msg ); } void CreateDbPage::slotCountCreateProgress( bool res ) { if( res ) { mCreates++; ui.mCreateProgress->setValue( mCreates ); ui.mCreateCounter->setText( i18n("%1/%2", mCreates, ui.mCreateProgress->maximum() ) ); } } void CreateDbPage::slotCountFillProgress( bool res ) { if( res ) { mFills++; ui.mFillProgress->setValue( mFills ); ui.mFillCounter->setText( i18n("%1/%2", mFills, ui.mFillProgress->maximum() ) ); } } int CreateDbPage::nextId() const { return SetupAssistant::upgradeDbPageNo; } // --------------------------------------------------------------------------- UpgradeDbPage::UpgradeDbPage(QWidget *parent) :QWizardPage(parent) { setTitle(i18n("Upgrade the Database")); QVBoxLayout *vbox = new QVBoxLayout; setLayout( vbox ); QWidget *w = new QWidget; vbox->addWidget( w ); ui.setupUi(w); } void UpgradeDbPage::slotSetStatusText( const QString& txt ) { ui.mUpgradeStatus->setText( txt ); } void UpgradeDbPage::slotSetOverallCount( int cnt ) { mUpgrades = 0; ui.mUpgradeProgress->setMaximum( cnt ); ui.mUpgradeProgress->setValue( 0 ); updateCounter(); } void UpgradeDbPage::updateCounter() { ui.mUpgradeCounter->setText( i18n("%1/%2", mUpgrades, ui.mUpgradeProgress->maximum() )); } void UpgradeDbPage::slotCountFillProgress( bool res ) { if( res ) { mUpgrades++; ui.mUpgradeProgress->setValue( mUpgrades ); updateCounter(); } } int UpgradeDbPage::nextId() const { return SetupAssistant::ownAddressPageNo; } // --------------------------------------------------------------------------- OwnAddressPage::OwnAddressPage(QWidget *parent) :QWizardPage(parent), mAddresses(nullptr) { setTitle(i18n("Your Company Address")); QVBoxLayout *vbox = new QVBoxLayout; QTabWidget *tabWidget = new QTabWidget; QLabel *l = new QLabel; l->setText( i18n("Select your companies address either from the address book or enter it manually. It is set as a consigner on the documents.") ); vbox->addWidget( l ); vbox->addWidget(tabWidget); setLayout(vbox); // == The AddressSelector page #ifdef HAVE_AKONADI QWidget *w = new QWidget; tabWidget->addTab(w, i18n("Select from Addressbook")); QVBoxLayout *vbox1 = new QVBoxLayout; mAddresses = new AddressSelectorWidget(this); vbox1->addWidget( mAddresses ); w->setLayout( vbox1 ); connect( mAddresses, SIGNAL( addressSelected(KContacts::Addressee)), SLOT( gotMyAddress( KContacts::Addressee ) ) ); #endif // == The manual page QWidget *w1 = new QWidget; ui.setupUi(w1); int id = tabWidget->addTab(w1, i18n("Manual Entry")); ui.nameLabel->setText( KContacts::Addressee::formattedNameLabel() ); ui.orgLabel->setText( KContacts::Addressee::organizationLabel()); ui.streetLabel->setText(KContacts::Addressee::businessAddressStreetLabel()); ui.postCodeLabel->setText(KContacts::Addressee::businessAddressPostalCodeLabel()); ui.cityLabel->setText(KContacts::Addressee::businessAddressLocalityLabel()); ui.phoneLabel->setText(KContacts::Addressee::businessPhoneLabel()); ui.faxLabel->setText(KContacts::Addressee::businessFaxLabel()); ui.mobileLabel->setText(KContacts::Addressee::mobilePhoneLabel()); ui.emailLabel->setText(KContacts::Addressee::emailLabel()); ui.websiteLabel->setText(KContacts::Addressee::urlLabel()); if( mAddresses && !mAddresses->backendUp() ) { tabWidget->setCurrentIndex(id); } } OwnAddressPage::~OwnAddressPage() { } void OwnAddressPage::gotMyAddress(const KContacts::Addressee& addressee) { mMe = addressee; } void OwnAddressPage::saveOwnName() { if( ! mMe.isEmpty() ) { KraftSettings::self()->setUserName( mMe.name() ); KraftSettings::self()->setUserUid( mMe.uid() ); KraftSettings::self()->save(); } else { // check for the manual. KContacts::Addressee add; add.setFormattedName(ui.leName->text()); add.setOrganization(ui.leOrganization->text()); KContacts::Address workAddress; workAddress.setStreet(ui.leStreet->text()); workAddress.setPostalCode(ui.lePostcode->text()); workAddress.setLocality(ui.leCity->text()); workAddress.setType(KContacts::Address::Work); add.insertAddress(workAddress); add.insertPhoneNumber(PhoneNumber(ui.lePhone->text(), KContacts::PhoneNumber::Work)); add.insertPhoneNumber(PhoneNumber(ui.leFax->text(), KContacts::PhoneNumber::Fax)); add.insertPhoneNumber(PhoneNumber(ui.leMobile->text(), KContacts::PhoneNumber::Cell)); ResourceLocatorUrl resUrl; resUrl.setUrl(QUrl(ui.leWebsite->text())); add.setUrl(resUrl); add.insertEmail(ui.leEmail->text(), true /* prefered */ ); VCardConverter vcc; QByteArray vcard = vcc.createVCard(add); QString file = QStandardPaths::writableLocation( QStandardPaths::AppDataLocation ); file += "/myidentity.vcd"; QFile f ( file ); if (f.open(QIODevice::WriteOnly | QIODevice::Text)) { f.write(vcard); f.close(); qDebug() << "Saved own identity to " << file; } } } int OwnAddressPage::nextId() const { return SetupAssistant::finalStatusPageNo; } // --------------------------------------------------------------------------- FinalStatusPage::FinalStatusPage(QWidget *parent) :QWizardPage(parent) { setTitle(i18n("Final Status")); QVBoxLayout *vbox = new QVBoxLayout; setLayout( vbox ); //TODO PORT QT5 vbox->setSpacing( QDialog::spacingHint() ); //TODO PORT QT5 vbox->setMargin( QDialog::marginHint() ); QWidget *w = new QWidget; vbox->addWidget( w ); ui.setupUi(w); ui.mStatusText->setTextFormat( Qt::RichText ); } void FinalStatusPage::slotSetStatusText( const QString& txt ) { ui.mStatusText->setText( txt ); } int FinalStatusPage::nextId() const { return -1; // final page } // --------------------------------------------------------------------------- SetupAssistant::SetupAssistant( QWidget *parent ) :QWizard( parent ), mMode( Reinit ) { setPage( welcomePageNo, new WelcomePage); setPage( dbSelectPageNo, new DbSelectPage); setPage( mySqlPageNo, new MysqlDetailsPage); setPage( sqlitePageNo, new SqLiteDetailsPage); setPage( createDbPageNo, new CreateDbPage); setPage( upgradeDbPageNo, new UpgradeDbPage); setPage( ownAddressPageNo, new OwnAddressPage); setPage( finalStatusPageNo, new FinalStatusPage); connect( this, SIGNAL( currentIdChanged( int) ), this, SLOT( slotCurrentPageChanged( int) ) ); resize( QSize( 450, 260 ) ); } /* * Current Database Setup Wizard +----------------+ check if db already exists ----------------------------- > | MySQL Page ----------------------------------+ -/ +--------+-------+ v +------------+ +--------------/ | +----------------+ +---------------+ | Welcome --->| DB Select | +--->+---------> | create DB Page +--->| upgrade DB | +------------+ +--------------\ | +----------------+ +-----------+---+ -\ +---+------------+ ^ | > | SQLite Page ----------------------------------+ | +----------------+ | | +---------------+ +-----------v---+ | Final Status |<---+ Own Address | +---------------+ +---------------+ */ QString SetupAssistant::defaultSqliteFilename() const { const QString path = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); QFileInfo fi(path, "kraft.db"); if( !fi.dir().exists() ) { if (! fi.dir().mkpath(path) ) { qDebug() << "Failed to create directory "<< path << "for sqlite db"; return QString(); } } return fi.filePath(); } void SetupAssistant::slotCurrentPageChanged( int currId ) { qDebug() << "Page changed to " << currId; if( currId == dbSelectPageNo ) { } else if( currId == mySqlPageNo ) { // TODO: set the mysql datails } else if( currId == sqlitePageNo) { // TODO set the sqlite filename } else if( currId == createDbPageNo ) { if( mSqlBackendDriver == QLatin1String("QMYSQL") ) { const QString dbName = field("MySqlDbName").toString(); if(!KraftDB::self()->dbConnect( QLatin1String("QMYSQL"), dbName, field("MySqlUser").toString(), field("MySqlHost").toString(), field("MySqlPwd").toString() ) ) { setField("CreateDbStatusText", i18n( "

            Can't connect to your database. Are you sure your credentials are correct and the database exists?

            ") ); return; } } else { QString filename = field("SqliteStorageFile").toString(); if(filename.isEmpty()) { filename = defaultSqliteFilename(); setField("SqliteStorageFile", filename); } if( !KraftDB::self()->dbConnect( QLatin1String("QSQLITE"), filename, QString(), QString(), QString()) ) { setField("CreateDbStatusText", i18n("

            Can't open your database file, check the permissions and such.")); } } if( !KraftDB::self()->databaseExists() ) { // qDebug () << "Start to create the database"; startDatabaseCreation(); } else { // qDebug () << "CreateDB-Page: Database already existing"; setField("CreateDbStatusText", i18n( "

            The database is already existing, no action needs to be taken here.

            " "

            Please hit next to proceed.

            " ) ); } } if( currId == upgradeDbPageNo ) { if( KraftDB::self()->databaseExists() ) { // qDebug () << "start to update the database"; startDatabaseUpdate(); } else { // qDebug () << "Strange problem at dbupdate: DB does not exist"; } } if( currId == finalStatusPageNo ) { finalizePage(); } } void SetupAssistant::done( int result ) { if( result > 0 ) { // store the stakeholders own name for picking the sender address qobject_cast(page(ownAddressPageNo))->saveOwnName(); const QString selectedDriver = qobject_cast(page(dbSelectPageNo))->selectedDriver(); DatabaseSettings::self()->setDbDriver( selectedDriver ); if( selectedDriver == QLatin1String("QSQLITE") ) { const QString file = field("SqliteStorageFile").toString(); DatabaseSettings::self()->setDbFile(file); } if( selectedDriver == "QMYSQL" ) { DatabaseSettings::self()->setDbDatabaseName( field("MySqlDbName").toString() ); DatabaseSettings::self()->setDbUser( field("MySqlUser").toString() ); const QString host = field("MySqlHost").toString(); DatabaseSettings::self()->setDbServerName( host ); DatabaseSettings::self()->setDbPassword( field("MySqlPwd").toString() ); } DatabaseSettings::self()->save(); qDebug () << "Database backend config written"; } QWizard::done(result); } void SetupAssistant::finalizePage() { QString txt; if( mErrors.isEmpty() ) { txt = i18n( "

            The database setup was successfully completed.

            " ); txt += i18n("

            You can start to work with Kraft now. Please do not forget to

            "); txt += "
              "; txt += i18n("
            • adjust various settings in the Kraft Preferences dialog.
            • " ); txt += i18n("
            • Check the Catalog chapter list.
            • " ); txt += i18n("
            • Make your business and have fun.
            • " ); txt += "
            "; txt += i18n("

            If you press Finish now, the new database configuration is stored in Krafts configuration.

            "); } else { foreach( QString err, mErrors ) { txt += "

            " + err + "

            "; } } // qDebug() << "this is the status text: " << txt; qobject_cast(page(finalStatusPageNo))->slotSetStatusText( txt ); } void SetupAssistant::startDatabaseUpdate() { CreateDbPage *mCreateDbPage = qobject_cast(page(createDbPageNo)); UpgradeDbPage *mUpgradeDbPage = qobject_cast(page(upgradeDbPageNo)); if( ! KraftDB::self()->isOk() ) { mCreateDbPage->setStatusText( i18n("The Database can not be connected. Please check the database credentials.")); button(NextButton)->setEnabled(false); return; } if( !KraftDB::self()->databaseExists() ) { mCreateDbPage->setStatusText( i18n("The database core tables do not exist. Please check initial setup.")); button(NextButton)->setEnabled(false); return; } button(NextButton)->setEnabled(true); if( KraftDB::self()->currentSchemaVersion() == KraftDB::self()->requiredSchemaVersion() ) { mUpgradeDbPage->slotSetStatusText( i18n("Database is up to date. No upgrade is required.")); return; } // Database really needs update mUpgradeDbPage->slotSetStatusText( i18n("Parse Update Commands...")); int overallCmdCount = 0; QList commandLists; int currentVer = KraftDB::self()->currentSchemaVersion(); if( currentVer == -1 ) currentVer = 1; // set to initial version while ( currentVer < KraftDB::self()->requiredSchemaVersion() ) { ++currentVer; // qDebug () << "######### Reading " << migrateFilename; const SqlCommandList cmds = KraftDB::self()->parseCommandFile( currentVer ); commandLists.append(cmds); overallCmdCount += cmds.count(); qDebug() << "Appending" << cmds.count() << "commands for version" << currentVer; } mUpgradeDbPage->slotSetOverallCount( overallCmdCount ); // qDebug () << "4."; connect( KraftDB::self(), SIGNAL( statusMessage( const QString& ) ), mUpgradeDbPage, SLOT( slotSetStatusText( const QString& ) ) ); connect( KraftDB::self(), SIGNAL( processedSqlCommand( bool ) ), mUpgradeDbPage, SLOT( slotCountFillProgress( bool ) ) ); int doneOverallCmds = 0; bool errors = false; currentVer = KraftDB::self()->currentSchemaVersion(); for( SqlCommandList cmdList : commandLists ) { currentVer++; int goodCmds = KraftDB::self()->processSqlCommands( cmdList ); doneOverallCmds += goodCmds; if( goodCmds != cmdList.count() ) { qDebug () << "Only performned " << goodCmds << " out of " << cmdList.count(); errors = true; break; } else { qDebug () << goodCmds << " commands performed well, version is " << currentVer << ", listversion:" << cmdList.number(); KraftDB::self()->setSchemaVersion( QString::number( currentVer )); } } if( errors ) { mUpgradeDbPage->slotSetStatusText( i18n("The Upgrade failed!") );; } else { mUpgradeDbPage->slotSetStatusText( i18n("The Upgrade succeeded, the current schema version is %1!", KraftDB::self()->requiredSchemaVersion() ) );; } disconnect( mUpgradeDbPage, SLOT( slotSetStatusText( const QString& ))); } void SetupAssistant::startDatabaseCreation() { CreateDbPage *mCreateDbPage = qobject_cast(page(createDbPageNo)); if( ! KraftDB::self()->isOk() ) { mCreateDbPage->setStatusText( i18n("The Database can not be connected. Please check the database credentials!")); button(NextButton)->setEnabled(false); return; } button(NextButton)->setEnabled(true); mCreateDbPage->setStatusText( i18n("Parse Create Commands...") ); SqlCommandList createCommands = KraftDB::self()->parseCommandFile( "create_schema.sql"); QString dbFill( "fill_schema_en.sql" ); if ( DefaultProvider::self()->locale()->country() == QLocale::Germany ) { dbFill = "fill_schema_de.sql"; } mCreateDbPage->setStatusText( i18n( "Parse database fillup commands..." ) ); SqlCommandList fillCommands = KraftDB::self()->parseCommandFile( dbFill ); mCreateDbPage->setCreateCmdsCount( createCommands.count() ); mCreateDbPage->setCreateCmdsCurrent( 0 ); mCreateDbPage->setFillCmdsCount( fillCommands.count() ); mCreateDbPage->setFillCmdsCurrent( 0 ); connect( KraftDB::self(), SIGNAL( statusMessage( const QString& ) ), mCreateDbPage, SLOT( slotStatusMessage( const QString& ) ) ); connect( KraftDB::self(), SIGNAL( processedSqlCommand( bool ) ), mCreateDbPage, SLOT( slotCountCreateProgress( bool ) ) ); mCreateDbPage->setStatusText( i18n( "Processing database creation commands...") ); int creates = KraftDB::self()->processSqlCommands( createCommands ); bool res = true; if( creates != createCommands.count() ) { // qDebug () << "NOT all create commands succeeded!"; res = false; } else { // qDebug () << creates << "(=All) create commands succeeded!"; // lets do the fillup disconnect( KraftDB::self(), SIGNAL(processedSqlCommand(bool)),0,0 ); connect( KraftDB::self(), SIGNAL( processedSqlCommand( bool ) ), mCreateDbPage, SLOT( slotCountFillProgress( bool ) ) ); mCreateDbPage->setStatusText( i18n( "Process database fillup commands..." ) ); creates = KraftDB::self()->processSqlCommands( fillCommands ); if( creates != fillCommands.count() ) { qDebug() << "Could not execute all fill commands"; res = false; } } if( res ) { mCreateDbPage->setStatusText( i18n( "Successfully finished commands." ) ); } else { mCreateDbPage->setStatusText( i18n( "Failed to perform all commands." ) ); // FIXME: Disable next button } disconnect( KraftDB::self(), SIGNAL(statusMessage( const QString&)),0 ,0 ); disconnect( KraftDB::self(), SIGNAL(processedSqlCommand(bool)),0 ,0 ); } bool SetupAssistant::handleSqLiteDetails() { DbSelectPage *mDbSelectPage = qobject_cast(page(dbSelectPageNo)); QString file = field("SqliteStorageFile").toString(); qDebug () << "The SqlLite database file is " << file; mSqlBackendDriver = mDbSelectPage->selectedDriver(); // qDebug () << "The database driver is " << mSqlBackendDriver; bool re = KraftDB::self()->dbConnect( mSqlBackendDriver, file, QString(), QString(), QString() ); return re; } bool SetupAssistant::handleMysqlDetails() { DbSelectPage *mDbSelectPage = qobject_cast(page(dbSelectPageNo)); mSqlBackendDriver = mDbSelectPage->selectedDriver(); QString hostName = field("MySqlHost").toString(); QString databaseName = field("MySqlDbName").toString(); QString userName = field("MySqlUser").toString(); QString password = field("MySqlPwd").toString(); return KraftDB::self()->dbConnect( mSqlBackendDriver, databaseName, userName, hostName, password ); } bool SetupAssistant::init( Mode mode ) { bool startDialog = false; QString text; QString configOrigin; mMode = mode; text = QLatin1String("

            ") + i18n("This assistant guides you through the basic settings of your Kraft installation.") + QLatin1String("

            "); bool hitNextClosing = true; if( mMode == Reinit ) { startDialog = true; } else if( mode == Update ) { if( QStandardPaths::locate(QStandardPaths::GenericConfigLocation, "kraftdatabaserc" ).isEmpty() ) { // migration failed and we do not have a config file. All from scratch configOrigin = i18n("There was no database configuration found."); } else { configOrigin = i18n("A valid current database configuration file was found."); // qDebug () << "A standard KDE Platform 4.x database config file is there."; } const QString dbDriver = DatabaseSettings::self()->dbDriver().toUpper(); QString dbName = DatabaseSettings::self()->dbDatabaseName(); if( dbDriver == QLatin1String("QSQLITE")) { dbName = DatabaseSettings::self()->dbFile(); } if( KraftDB::self()->dbConnect( dbDriver, dbName, DatabaseSettings::self()->dbUser(), DatabaseSettings::self()->dbServerName(), DatabaseSettings::self()->dbPassword()) ) { // try to connect with default values // qDebug () << "The database can be opened!"; if( KraftDB::self()->databaseExists() ) { // qDebug () << "The database exists."; if( KraftDB::self()->currentSchemaVersion() < KraftDB::self()->requiredSchemaVersion() ) { // qDebug () << "Need a database schema update."; startDialog = true; configOrigin += QLatin1String(" ") + i18n("The database schema version is too low. " "It will be updated."); } else if( KraftDB::self()->currentSchemaVersion() > KraftDB::self()->requiredSchemaVersion() ) { configOrigin += QLatin1Char(' ') + i18n("The current database schema version is too high. Leaving untouched! "); // qDebug () << "Database Schema is OK. Nothing to do for StartupAssistant"; } } else { // qDebug () << "The database is not existing. It needs to be recreated."; startDialog = true; text = i18n( "

            The database can be opened, but does not contain valid content.

            " "

            A new database can be created automatically from scratch.

            "); } } else { // unable to connect to the database at all startDialog = true; hitNextClosing = false; text = i18n( "

            Kraft failed to connect to the configured database.

            " ); if( KraftDB::self()->qtDriver().toUpper() == "QMYSQL" ) { text += i18n( "

            Please check the database server setup and restart Kraft to connect." ); } else { text += i18n("

            Please check the database file."); } text += " " + i18n( "or create a new database by hitting next.

            " ); } } if( startDialog ) { WelcomePage *welcomePage = qobject_cast(page(welcomePageNo)); if( hitNextClosing ) text += i18n("

            Please hit next and follow the instructions.

            "); welcomePage->setWelcomeText( configOrigin + text ); } return startDialog ; } SetupAssistant::~SetupAssistant() { } kraft-1.1/src/setupassistant.h000066400000000000000000000120441450127457600165300ustar00rootroot00000000000000/*************************************************************************** setupassistant - assistant to setup kraft from scratch ------------------- begin : 2009-12-26 copyright : (C) 2009 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef SETUPASSISTANT_H #define SETUPASSISTANT_H #include #include #include #include "ui_statuspage.h" #include "ui_dbselect.h" #include "ui_mysqldetails.h" #include "ui_createdb.h" #include "ui_upgradedb.h" #include "ui_sqlitedetails.h" #include "ui_identity.h" #include "kraftcat_export.h" class QUrl; class AddressSelectorWidget; using namespace KContacts; class WelcomePage:public QWizardPage { Q_OBJECT public: WelcomePage( QWidget *parent = 0 ); void setWelcomeText( const QString& ); private: Ui::statusPage ui; }; // --------------------------------------------------------------------------- class DbSelectPage:public QWizardPage { Q_OBJECT public: DbSelectPage( QWidget *parent = 0 ); QString selectedDriver() const; int nextId() const; private: Ui::dbSelectForm ui; }; // --------------------------------------------------------------------------- class SqLiteDetailsPage:public QWizardPage { Q_OBJECT public: SqLiteDetailsPage( QWidget *parent = 0 ); QUrl url(); int nextId() const; bool validatePage(); private: Ui::sqLiteDetailsForm ui; }; // --------------------------------------------------------------------------- class MysqlDetailsPage:public QWizardPage { Q_OBJECT public: MysqlDetailsPage( QWidget *parent = 0 ); void reloadSettings(); int nextId() const; bool validatePage(); private: Ui::mySqlDetailsForm ui; }; // --------------------------------------------------------------------------- class CreateDbPage:public QWizardPage { Q_OBJECT public: CreateDbPage( QWidget *parent = 0 ); void setStatusText( const QString& ); void setCreateCmdsCount( int ); void setFillCmdsCount( int ); void setCreateCmdsCurrent( int ); void setFillCmdsCurrent( int ); int nextId() const; public slots: void slotStatusMessage( const QString& ); void slotCountCreateProgress( bool ); void slotCountFillProgress( bool ); private: Ui::createDbForm ui; int mCreates; int mFills; }; // --------------------------------------------------------------------------- class UpgradeDbPage:public QWizardPage { Q_OBJECT public: UpgradeDbPage( QWidget *parent = 0 ); int nextId() const; public slots: void slotSetStatusText( const QString& ); void slotSetOverallCount( int ); void slotCountFillProgress( bool ); private: void updateCounter(); Ui::upgradeDbForm ui; int mUpgrades; }; // --------------------------------------------------------------------------- class OwnAddressPage:public QWizardPage { Q_OBJECT public: OwnAddressPage( QWidget *parent=0 ); ~OwnAddressPage(); void saveOwnName(); int nextId() const; private: AddressSelectorWidget *mAddresses; KContacts::Addressee mMe; Ui::manualOwnIdentity ui; private slots: void gotMyAddress( const KContacts::Addressee& addressee); }; // --------------------------------------------------------------------------- class FinalStatusPage:public QWizardPage { Q_OBJECT public: FinalStatusPage( QWidget *parent = 0 ); int nextId() const; public slots: void slotSetStatusText( const QString& ); private: Ui::statusPage ui; }; // --------------------------------------------------------------------------- class SetupAssistant: public QWizard { Q_OBJECT public: enum { welcomePageNo, dbSelectPageNo, mySqlPageNo, sqlitePageNo, createDbPageNo, upgradeDbPageNo, finalStatusPageNo, ownAddressPageNo }; enum Mode{ Reinit, Update }; SetupAssistant( QWidget *parent = 0 ); bool init( Mode ); ~SetupAssistant(); bool handleSqLiteDetails(); bool handleMysqlDetails(); public slots: void done( int ); private slots: void slotCurrentPageChanged(int currId); private: void startDatabaseCreation(); void startDatabaseUpdate(); void finalizePage(); QString defaultSqliteFilename() const; Mode mMode; QStringList mErrors; QString mSqlBackendDriver; }; #endif // SETUPASSISTANT_H kraft-1.1/src/sqlitedetails.ui000066400000000000000000000041251450127457600164740ustar00rootroot00000000000000 sqLiteDetailsForm 0 0 421 245 Please enter the SQLite Database Settings. Pick a filename to name the SQLite database file or leave the default setting. true store the database file at default place. true buttonGroup select a file name: buttonGroup Qt::Vertical 20 107 kraft-1.1/src/statuspage.ui000066400000000000000000000015211450127457600160020ustar00rootroot00000000000000 statusPage 0 0 404 185 TextLabel Qt::RichText Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true kraft-1.1/src/stdsatzman.cpp000066400000000000000000000063751450127457600161730ustar00rootroot00000000000000/*************************************************************************** stdsatzman - ------------------- begin : 2004-13-09 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include #include #include // include files for KDE #include "stdsatzman.h" #include "kraftdb.h" Q_GLOBAL_STATIC(StdSatzMan, mSelf) StdSatz::StdSatz(): m_dbId(0) { } StdSatz::StdSatz( int id ): m_dbId(id) { } StdSatz::StdSatz( int id, const QString& name, Geld g ): m_dbId(id), m_name(name), m_value(g) { } /* * ********** Stundensatz Duration ********** */ StdSatzDuration::StdSatzDuration() :mDuration( -1 ) { } StdSatzDuration::StdSatzDuration( const StdSatz& std, int dur ) :StdSatz( std ), mDuration( dur ) { } /* * ********** Stundensatz Manager ********** */ StdSatzMan *StdSatzMan::self() { return mSelf; } StdSatzMan::StdSatzMan( ) { load(); } QStringList StdSatzMan::allStdSaetze() { QStringList list; load(); StdSatzVector::iterator it; for( it = mStdSaetze.begin(); it != mStdSaetze.end(); ++it ) { QString n = (*it).getName(); if( !n.isEmpty()) list << n; } return list; } StdSatz StdSatzMan::getStdSatz( const QString& name ) { load(); StdSatzVector::iterator it; for( it = mStdSaetze.begin(); it != mStdSaetze.end(); ++it ) { if( (*it).getName() == name ) return (*it); } return StdSatz(); } StdSatz StdSatzMan::getStdSatz( dbID id ) { load(); StdSatzVector::iterator it; for( it = mStdSaetze.begin(); it != mStdSaetze.end(); ++it ) { dbID dbid = (*it).getId(); if( dbid == id ) return (*it); } return StdSatz(); } StdSatzMan::~StdSatzMan( ) { } void StdSatzMan::load() { /* noetige Groesse rausfinden */ int max = -1; QSqlQuery q("SELECT count(*) from stdSaetze;"); if( q.isActive()) { q.next(); max = q.value(0).toInt(); } // qDebug () << "Groesse fuer Stundensatzliste: " << max; mStdSaetze.resize( max ); /* Daten laden */ q.prepare("SELECT stdSaetzeID, name, price FROM stdSaetze ORDER BY sortKey"); q.exec(); while( q.next() ) { int satzID = q.value(0).toInt(); // qDebug () << "Neue StdSatz ID " << satzID; // resize if index is to big. StdSatz ss( satzID, q.value(1).toString(), Geld( q.value(2).toDouble())); mStdSaetze.append(ss); } } /* END */ kraft-1.1/src/stdsatzman.h000066400000000000000000000045371450127457600156360ustar00rootroot00000000000000/*************************************************************************** stdsatzman - ------------------- begin : 2004-13-09 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _STDSATZMAN_H #define _STDSATZMAN_H /* * Hour rate management: There are different named hour rates such as Master * or helper with a different amount of euros. The cost per hour can be adjusted * document globally. */ // include files #include #include "geld.h" #include "dbids.h" class QString; /** * das Stundensatzobjekt: definiert durch id und namen */ class StdSatz { public: StdSatz(); /** * Konstruktur basierend auf der Datenbank id */ StdSatz(int id); StdSatz( int id, const QString& name, Geld g ); dbID getId() { return m_dbId; } QString getName() { return m_name; } Geld getPreis() { return m_value; } private: dbID m_dbId; QString m_name; Geld m_value; }; class StdSatzDuration : public StdSatz { public: StdSatzDuration(); StdSatzDuration( const StdSatz&, int ); int duration() { return mDuration; } void setDuration( int d ) { mDuration = d; } private: int mDuration; }; typedef QVector StdSatzVector; /** * der Stundensatzmanager */ class StdSatzMan { public: virtual ~StdSatzMan(); static StdSatzMan *self(); QStringList allStdSaetze(); StdSatz getStdSatz( const QString& name ); StdSatz getStdSatz( dbID id ); // static StdSatzMan *mSelf; StdSatzMan(); private: void load(); StdSatzVector mStdSaetze; }; #endif /* END */ kraft-1.1/src/stockmaterial.cpp000066400000000000000000000060501450127457600166330ustar00rootroot00000000000000/*************************************************************************** material - ------------------- begin : 2004-05-05 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include // include files for KDE #include #include #include "stockmaterial.h" #include "unitmanager.h" #include "materialsaverbase.h" #include "materialsaverdb.h" #include "defaultprovider.h" #include "format.h" #include "kraftsettings.h" StockMaterial::StockMaterial( ): CatalogTemplate(), m_amount( 0 ), m_dbid( -1 ) { } StockMaterial::StockMaterial( int dbid, int matChap, QString mat, int unitID, double perPack, Geld pIn, Geld pOut ): CatalogTemplate(), m_chapter(matChap), m_amount(perPack), m_dbid(dbid), m_ePrice(pIn), m_vPrice(pOut) { this->setUnitId(unitID); this->setText(mat); } StockMaterial::~StockMaterial( ) { } MaterialSaverBase* StockMaterial::getSaver() { return MaterialSaverDB::self(); } bool StockMaterial::save() { MaterialSaverBase *saver = getSaver(); if ( saver ) { saver->saveTemplate( this ); return true; } return false; } #if 0 QString StockMaterial::description() const { return m_descr; } void StockMaterial::setDescription( const QString& str ) { m_descr = str; } #endif double StockMaterial::getAmountPerPack() { return m_amount; } void StockMaterial::setAmountPerPack( double am ) { m_amount = am; } int StockMaterial::getID() { return m_dbid; } void StockMaterial::setID( int id ) { m_dbid = id; } KContacts::Addressee StockMaterial::getSupplier() { KContacts::Addressee a; return a; } void StockMaterial::setSupplier( KContacts::Addressee *a ) { if( a ) m_delivererUID = a->uid(); } Geld StockMaterial::purchPrice() { return m_ePrice; } Geld StockMaterial::salesPrice() { return m_vPrice; } Geld StockMaterial::unitPrice() { return salesPrice() / m_amount; } void StockMaterial::setPurchPrice( Geld g ) { m_ePrice = g; } void StockMaterial::setSalesPrice( Geld g ) { m_vPrice = g; } void StockMaterial::saveChapterId() { MaterialSaverBase *saver = getSaver(); if( saver ) { saver->saveTemplateChapter( this ); } } /* END */ kraft-1.1/src/stockmaterial.h000066400000000000000000000050761450127457600163070ustar00rootroot00000000000000/*************************************************************************** material - Material for calculations ------------------- begin : 2004-05-05 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _MATERIAL_H #define _MATERIAL_H // include files #include #include #include "kraftglobals.h" #include "einheit.h" #include "catalogtemplate.h" /** * */ class Einheit; class MaterialSaverBase; class QDate; class QDateTime; class StockMaterial : public CatalogTemplate { public: StockMaterial(); StockMaterial( int dbid, int matChap, QString mat, int unitID, double perPack, Geld pIn, Geld pOut ); ~StockMaterial(); #if 0 // currently not used. QString description() const; void setDescription( const QString& ); #endif double getAmountPerPack(); void setAmountPerPack( double am ); int getID(); void setID( int ); int chapter() { return m_chapter; } void setChapter( int c ) { m_chapter = c; } KContacts::Addressee getSupplier(); void setSupplier( KContacts::Addressee *supp ); Geld purchPrice(); Geld salesPrice(); Geld unitPrice(); void setPurchPrice( Geld ); void setSalesPrice( Geld ); bool save(); protected: MaterialSaverBase* getSaver(); void saveChapterId(); private: // QString m_descr; int m_chapter; // per package: double m_amount; int m_unit; int m_dbid; // FIXME: introduce supplier list QString m_delivererUID; Geld m_ePrice; // price for bying Geld m_vPrice; // price for selling QDate mLastModified; QDate mEnteredDate; }; class StockMaterialList : public QList { public: StockMaterialList() : QList() { } }; typedef QListIterator StockMaterialListIterator; #endif /* END */ kraft-1.1/src/stringutil.cpp000066400000000000000000000032331450127457600161750ustar00rootroot00000000000000/*************************************************************************** String helper functions ------------------- begin : July 2023 copyright : (C) 2023 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include "format.h" namespace StringUtil { QString replaceTagsInString( const QString& w, QMap& replaceMap ) { QString re{ w }; QMultiMap reMap; for(const QString& key : replaceMap.keys()) { reMap.insert(key.length(), key); } QList lens = reMap.keys(); std::sort(lens.begin(), lens.end(), [](const int& i1, const int& i2) -> bool { return i1 > i2; }); for (int len : lens) { const QStringList keys = reMap.values(len); for (const QString& k : keys) { re.replace(k, replaceMap[k]); } } return re; } } kraft-1.1/src/stringutil.h000066400000000000000000000026371450127457600156510ustar00rootroot00000000000000/*************************************************************************** String helper functions ------------------- begin : July 2023 copyright : (C) 2023 by Klaas Freitag email : kraft@freisturz.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef STRINGUTIL_H #define STRINGUTIL_H class QString; namespace StringUtil { /** * @brief replaceTagsInString. * @param w - the string that includes the %-prepended tags * @param replaceMap - a map containing key/values that replace the tags. * @return the string with tags replaced * */ QString replaceTagsInString( const QString& w, QMap& replaceMap ); } #endif // FORMAT_H kraft-1.1/src/tagman.cpp000066400000000000000000000113161450127457600152410ustar00rootroot00000000000000/*************************************************************************** TagTemplateManager - Manage the tag templates ------------------- begin : June 2008 copyright : (C) 2008 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include #include #include #include "tagman.h" #include "kraftdb.h" /* * ********** Tag Template ********** */ TagTemplate::TagTemplate() { } TagTemplate::TagTemplate( const dbID& id, const QString& name, const QString& desc, const QString& col ) : mId( id ), mName( name ), mDesc( desc ), mColor( col ) { } QPalette TagTemplate::palette() const { QPalette palette; palette.setColor( QPalette::Light, mColor.light() ); palette.setColor( QPalette::Dark, mColor.dark() ); palette.setColor( QPalette::Mid, mColor ); return palette; } bool TagTemplate::operator!= ( const TagTemplate& tt ) const { return !( mName == tt.mName && mDesc == tt.mDesc && mColor == tt.mColor ); } /* * ********** Tag Template Manager ********** */ Q_GLOBAL_STATIC(TagTemplateMan, mSelf) TagTemplateMan *TagTemplateMan::self() { return mSelf; } TagTemplateMan::TagTemplateMan( ) { load(); } QStringList TagTemplateMan::allTagTemplates() { QStringList list; TagTemplateValueVector::iterator it; for( it = mTagTmpl.begin(); it != mTagTmpl.end(); ++it ) { QString n = (*it).name(); if( !n.isEmpty()) list << n; } return list; } TagTemplate TagTemplateMan::getTagTemplate( const QString& name ) { TagTemplateValueVector::iterator it; for( it = mTagTmpl.begin(); it != mTagTmpl.end(); ++it ) { // FIXME: Case insensitive here !!! if( (*it).name() == name ) return (*it); } return TagTemplate(); } TagTemplate TagTemplateMan::getTagTemplateFromId( const QString& id ) { TagTemplateValueVector::iterator it; for( it = mTagTmpl.begin(); it != mTagTmpl.end(); ++it ) { if( (*it).dbId().toString() == id ) return (*it); } return TagTemplate(); } TagTemplateMan::~TagTemplateMan( ) { } bool TagTemplateMan::writeTemplate( const TagTemplate& tt ) { bool ret = true; int cnt = 0; if ( tt.dbId().isOk() ) { QSqlQuery q; q.prepare( "UPDATE tagTemplates SET name=:name, description=:desc, color=:col " "WHERE tagTmplID=:id" ); q.bindValue( ":name", tt.name() ); q.bindValue( ":desc", tt.description() ); q.bindValue( ":col", tt.color().name() ); q.bindValue( ":id", tt.dbId().toString() ); q.exec(); cnt = q.numRowsAffected(); } if ( cnt == -1 ) { qCritical() << "DB does not know the number of affected rows, poor!"; ret = false; } else if ( cnt == 0 ) { // qDebug () << "need to insert the tag template into db"; QSqlQuery qi; qi.prepare( "INSERT INTO tagTemplates (name, sortKey, description, color) VALUES " "( :name, :sortKey, :desc, :col )" ); qi.bindValue( ":sortKey", 0 ); qi.bindValue( ":name", tt.name() ); qi.bindValue( ":desc", tt.description() ); qi.bindValue( ":col", tt.color().name() ); qi.exec(); } if ( ret ) { load(); } return ret; } void TagTemplateMan::deleteTemplate( const dbID& id ) { if ( id.isOk() ) { QSqlQuery q; q.prepare( "DELETE FROM tagTemplates WHERE tagTmplID=:id" ); q.bindValue( ":id", id.toString() ); q.exec(); load(); } } void TagTemplateMan::load() { mTagTmpl.clear(); /* read tag templates from db */ /* FIXME: The sortKey sort is not working because the sortKey is not correctly set on write */ /* With the initial db setup come useful sortKeys, thats why we still sort for it. */ QSqlQuery q1( "SELECT tagTmplID, name, description, color FROM tagTemplates ORDER BY sortKey, name" ); while( q1.next()) { dbID id( q1.value(0).toInt() ); TagTemplate tt ( id, q1.value(1).toString(), q1.value(2).toString(), q1.value(3).toString() ); mTagTmpl.append( tt ); } } /* END */ kraft-1.1/src/tagman.h000066400000000000000000000044701450127457600147110ustar00rootroot00000000000000/*************************************************************************** tag manager - create, edit and remove tags. ------------------- begin : June 2008 copyright : (C) 2008 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _TAGMAN_H #define _TAGMAN_H // include files #include #include "geld.h" #include "dbids.h" class QString; class QColor; class QPalette; /** * das Stundensatzobjekt: definiert durch id und namen */ class TagTemplate { public: TagTemplate(); TagTemplate( const dbID&, const QString&, const QString&, const QString& ); QString name() const { return mName; } QColor color() const { return mColor; } QPalette palette() const; dbID dbId() const { return mId; } QString description() const { return mDesc; } void setName( const QString& n ) { mName = n; } void setDescription( const QString& d ) { mDesc = d; } void setColor( const QColor& c ) { mColor = c; } bool operator!= ( const TagTemplate& tt ) const; private: dbID mId; QString mName; QString mDesc; QColor mColor; }; typedef QVector TagTemplateValueVector; /** * Tag Template Manager */ class TagTemplateMan { public: ~TagTemplateMan(); static TagTemplateMan *self(); QStringList allTagTemplates(); TagTemplate getTagTemplate( const QString& ); TagTemplate getTagTemplateFromId( const QString& ); bool writeTemplate( const TagTemplate& ); void deleteTemplate( const dbID& ); TagTemplateMan(); private: void load(); TagTemplateValueVector mTagTmpl; }; #endif /* END */ kraft-1.1/src/tagtemplatesdialog.cpp000066400000000000000000000202271450127457600176450ustar00rootroot00000000000000/*************************************************************************** tagtemplatesdialog.h - Edit tag templates ------------------- begin : Sep 2008 copyright : (C) 2008 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tagtemplatesdialog.h" #include "defaultprovider.h" #include "tagman.h" TagTemplateEditor::TagTemplateEditor( QWidget *parent ) : QDialog( parent ) { setObjectName("TAG_TEMPLATES_EDITOR"); setModal( true ); setWindowTitle( i18n("Edit Tag Template" )); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QVBoxLayout *w = new QVBoxLayout( this ); w->addWidget(new QLabel( QString::fromLatin1( "

            " ) + i18n( "Edit a Tag Template" ) + QString::fromLatin1( "

            " ))); w->addWidget( new QLabel( i18n( "Adjust settings for name, color and description." ))); QHBoxLayout *h1 = new QHBoxLayout; h1->addWidget( new QLabel( i18n( "Name:" ) )); mNameEdit = new QLineEdit; h1->addWidget(mNameEdit); w->addLayout(h1); // QHBox *h2 = new QHBox( w ); w->addWidget(new QLabel( i18n( "Description:" ))); mDescriptionEdit = new QTextEdit; w->addWidget(mDescriptionEdit); QHBoxLayout *h2 = new QHBoxLayout; h2->addStretch(1); h2->addWidget(new QLabel( i18n( "Associated Color:" ))); mColorButton = new QPushButton; h2->addWidget(mColorButton); connect( mColorButton, SIGNAL(clicked(bool)), SLOT(slotColorSelect(bool))); w->addLayout(h2); mainLayout->addLayout(w); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); mOkButton = buttonBox->button(QDialogButtonBox::Ok); mOkButton->setDefault(true); mOkButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(buttonBox); } TagTemplateEditor::~TagTemplateEditor() { } void TagTemplateEditor::slotColorSelect(bool) { mColor = QColorDialog::getColor(mOrigTemplate.color(), this); setColorButton(); mOkButton->setFocus(); } void TagTemplateEditor::setColorButton() { QPixmap pix(32, 32); QPainter painter(&pix); painter.setBrush(QBrush(mColor)); painter.drawRect( QRect(0 ,0 , 32, 32)); mColorButton->setIcon(QIcon(pix)); } void TagTemplateEditor::setTemplate( const TagTemplate& tt ) { mOrigTemplate = tt; mNameEdit->setText( tt.name() ); mDescriptionEdit->setText( tt.description() ); mColor = tt.color(); setColorButton(); } TagTemplate TagTemplateEditor::currentTemplate() { TagTemplate tt = mOrigTemplate; tt.setName( mNameEdit->text() ); tt.setDescription( mDescriptionEdit->toPlainText() ); tt.setColor(mColor); return tt; } // ################################################################################ TagTemplatesDialog::TagTemplatesDialog( QWidget *parent ) : QDialog( parent ) { setObjectName( "TAG_TEMPLATES_DIALOG" ); setModal( true ); setWindowTitle( i18n("Edit Tag Templates" ) ); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(new QLabel( QString::fromLatin1( "

            " ) + i18n( "Edit Tag Templates" ) + QString::fromLatin1( "

            " ))); mainLayout->addWidget(new QLabel( i18n( "Add, edit and remove tag templates for use in the documents." ))); mListView = new QTreeWidget; // mListView->setItemMargin( 3 ); // mListView->setAlternateBackground( QColor( "#dffdd0" ) ); // mListView->headerItem()->hide(); mListView->setRootIsDecorated( false ); mListView->setSelectionMode( QAbstractItemView::SingleSelection ); QStringList headers; headers << i18n( "Tag" ); headers << i18n( "Color" ); headers << i18n( "Description" ); mListView->setHeaderLabels( headers ); mListView->setAllColumnsShowFocus( true ); mListView->setSelectionMode( QAbstractItemView::SingleSelection ); connect( mListView, SIGNAL( itemSelectionChanged() ), this, SLOT( slotSelectionChanged() ) ); mainLayout->addWidget(mListView); setTags(); QHBoxLayout *buttBox = new QHBoxLayout; mAddButton = new QPushButton( i18n( "Add..." )); buttBox->addWidget(mAddButton); mEditButton = new QPushButton( i18n( "Edit..." )); buttBox->addWidget(mEditButton); mEditButton->setEnabled( false ); mDeleteButton = new QPushButton( i18n( "Delete..." )); buttBox->addWidget(mDeleteButton); mDeleteButton->setEnabled( false ); mainLayout->addLayout(buttBox); connect( mAddButton, SIGNAL( clicked() ), SLOT( slotAddTemplate() ) ); connect( mEditButton, SIGNAL( clicked() ), SLOT( slotEditTemplate() ) ); connect( mDeleteButton, SIGNAL( clicked() ), SLOT( slotDeleteTemplate() ) ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(buttonBox); setLayout(mainLayout); slotSelectionChanged(); } TagTemplatesDialog::~TagTemplatesDialog() { } void TagTemplatesDialog::slotAddTemplate() { TagTemplateEditor dia( this ); if ( dia.exec() ) { TagTemplateMan::self()->writeTemplate( dia.currentTemplate() ); setTags(); } } void TagTemplatesDialog::slotEditTemplate() { TagTemplateEditor dia( this ); TagTemplate curr = currentTemplate(); dia.setTemplate( curr ); if ( dia.exec() ) { TagTemplate tt = dia.currentTemplate(); if ( tt != curr ) { TagTemplateMan::self()->writeTemplate( tt ); setTags(); } } } void TagTemplatesDialog::slotDeleteTemplate() { QMessageBox msgBox; msgBox.setText(i18n( "Do you really want to delete the template?")); msgBox.setStandardButtons(QMessageBox::Yes| QMessageBox::No); msgBox.setDefaultButton(QMessageBox::Yes); int ret = msgBox.exec(); if ( ret == QMessageBox::Yes) { TagTemplateMan::self()->deleteTemplate( currentTemplate().dbId() ); setTags(); } } void TagTemplatesDialog::slotSelectionChanged() { bool state = false; if ( mListView->selectedItems().size() ) { state = true; } mEditButton->setEnabled( state ); mDeleteButton->setEnabled( state ); } TagTemplate TagTemplatesDialog::currentTemplate() { QTreeWidgetItem *item = mListView->currentItem(); if ( item ) { QString templName = mItemMap[item]; return TagTemplateMan::self()->getTagTemplate( templName ); } return TagTemplate(); } void TagTemplatesDialog::setTags() { mListView->clear(); QStringList tags = TagTemplateMan::self()->allTagTemplates(); foreach( const QString t, tags ) { TagTemplate templ = TagTemplateMan::self()->getTagTemplate( t ); // TagItem *item = new QListViewItem( mListView, templ.name(), QCheckListItem::CheckBox ); QTreeWidgetItem *item = new QTreeWidgetItem( mListView ); item->setText( 1, templ.name() ); QPixmap pix( 16, 12 ); pix.fill( templ.color() ); item->setIcon( 0, pix ); // item->setColorGroup( templ.colorGroup() ); item->setText( 2, templ.description() ); mItemMap[item] = t; } } kraft-1.1/src/tagtemplatesdialog.h000066400000000000000000000041251450127457600173110ustar00rootroot00000000000000/*************************************************************************** tagtemplatedit.h - Edit tag templates ------------------- begin : Sep 2008 copyright : (C) 2008 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef TAGTEMPLATESDIALOG_H #define TAGTEMPLATESDIALOG_H #include #include #include "tagman.h" class QWidget; class QTreeWidget; class QTreeWidgetItem; class QStringList; class QPushButton; class QLineEdit; class QTextEdit; class TagTemplateEditor: public QDialog { Q_OBJECT public: TagTemplateEditor( QWidget* ); ~TagTemplateEditor(); void setTemplate( const TagTemplate& ); TagTemplate currentTemplate(); private slots: void slotColorSelect(bool); void setColorButton(); private: TagTemplate mOrigTemplate; QLineEdit *mNameEdit; QTextEdit *mDescriptionEdit; QPushButton *mColorButton; QPushButton *mOkButton; QColor mColor; }; class TagTemplatesDialog: public QDialog { Q_OBJECT public: TagTemplatesDialog( QWidget* ); ~TagTemplatesDialog( ); TagTemplate currentTemplate(); protected slots: void slotSelectionChanged(); void slotAddTemplate(); void slotEditTemplate(); void slotDeleteTemplate(); protected: void setTags( ); private: QTreeWidget *mListView; QMap mItemMap; QPushButton *mAddButton; QPushButton *mEditButton; QPushButton *mDeleteButton; }; #endif kraft-1.1/src/taxeditbase.ui000066400000000000000000000050651450127457600161260ustar00rootroot00000000000000 TaxEditBase 0 0 348 158 <h2>Add a Tax Rate</h2> false Start-Date: false Qt::Horizontal QSizePolicy::Expanding 71 20 &Reduced Tax Rate: false mReducedTax &Full Tax Rate: false mFullTax kraft-1.1/src/taxeditdialog.cpp000066400000000000000000000070471450127457600166220ustar00rootroot00000000000000/*************************************************************************** taxeditdialog.h - edit tax rates ------------------- begin : Apr 9 2009 copyright : (C) 2009 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include "taxeditdialog.h" TaxEditDialog::TaxEditDialog( QSqlTableModel *taxModel, QWidget *parent ) : QDialog( parent ) { setObjectName( "TAX_EDIT_DIALOG" ); setModal( true ); setWindowTitle( i18n( "Edit Tax Rates" ) ); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QWidget *w = new QWidget; mainLayout->addWidget(w); mBaseWidget = new Ui::TaxEditBase( ); mBaseWidget->setupUi( w ); mBaseWidget->mDateWidget->setDate( QDate::currentDate() ); mBaseWidget->mFullTax->setSuffix( "%" ); mBaseWidget->mReducedTax->setSuffix( "%" ); mBaseWidget->mFullTax->setRange( 0,100.0 ); mBaseWidget->mFullTax->setDecimals( 1 ); mBaseWidget->mReducedTax->setRange( 0, 100.0 ); mBaseWidget->mReducedTax->setDecimals( 1 ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); mainLayout->addWidget(buttonBox); this->model = taxModel; mapper = new QDataWidgetMapper(this); mapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit); mapper->setModel(taxModel); mapper->addMapping(mBaseWidget->mFullTax, 1); mapper->addMapping(mBaseWidget->mReducedTax, 2); mapper->addMapping(mBaseWidget->mDateWidget, 3); model->insertRow(model->rowCount()); mapper->toLast(); } void TaxEditDialog::accept() { mapper->submit(); //Check if the inserted date already exists, if so update the existing record and delete this record for(int i = 0; i < model->rowCount() - 1; ++i) { if (model->index(i, 3).data(Qt::DisplayRole).toDate() == mBaseWidget->mDateWidget->date() ) { //Check if the row isn't removed QString headerdata = model->headerData(i, Qt::Vertical, Qt::DisplayRole).toString(); if(headerdata != "!") { model->setData(model->index(i, 1, QModelIndex()), mBaseWidget->mFullTax->value(), Qt::EditRole); model->setData(model->index(i, 2, QModelIndex()), mBaseWidget->mReducedTax->value(), Qt::EditRole); model->removeRow(model->rowCount()-1); } } } QDialog::accept(); } void TaxEditDialog::reject() { model->removeRow(model->rowCount()-1); QDialog::reject(); } kraft-1.1/src/taxeditdialog.h000066400000000000000000000031061450127457600162570ustar00rootroot00000000000000/*************************************************************************** taxeditdialog.h - edit tax rates ------------------- begin : Apr 9 2009 copyright : (C) 2009 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef TAXEDITDIALOG_H #define TAXEDITDIALOG_H #include #include #include #include #include "ui_taxeditbase.h" /** * @author Klaas Freitag */ // ################################################################################ class TaxEditDialog: public QDialog, protected Ui::TaxEditBase { Q_OBJECT public: TaxEditDialog( QSqlTableModel *taxModel, QWidget *parent ); public slots: void accept(); void reject(); private: Ui::TaxEditBase *mBaseWidget; QDataWidgetMapper *mapper; QSqlTableModel *model; }; #endif kraft-1.1/src/templateprovider.cpp000066400000000000000000000030621450127457600173570ustar00rootroot00000000000000/*************************************************************************** templateprovider - base class for the template provider classes. ------------------- begin : 2007-05-02 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "templateprovider.h" #include "doctext.h" #include "textselection.h" TemplateProvider::TemplateProvider( QWidget *parent ) : QObject(), mParent( parent ), mTextSelection(nullptr) { } TemplateProvider::~TemplateProvider() { } void TemplateProvider::slotSetDocType( const QString& str ) { mDocType = str; } void TemplateProvider::setSelection( TextSelection *sel ) { mTextSelection = sel; } DocText TemplateProvider::currentText() { DocText dt; if ( mTextSelection ) { return mTextSelection->currentDocText(); } return dt; } kraft-1.1/src/templateprovider.h000066400000000000000000000032721450127457600170270ustar00rootroot00000000000000/*************************************************************************** templateprovider - base class for the template provider classes. ------------------- begin : 2007-05-02 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef TEMPLATEPROVIDER_H #define TEMPLATEPROVIDER_H #include class QWidget; class TextSelection; class DocText; class TemplateProvider : public QObject { Q_OBJECT public: TemplateProvider( QWidget* ); ~TemplateProvider(); virtual void setSelection( TextSelection* ); virtual DocText currentText(); public slots: virtual void slotNewTemplate() = 0; virtual void slotEditTemplate() = 0; virtual void slotDeleteTemplate() = 0; virtual void slotTemplateToDocument() = 0; virtual void slotInsertTemplateToDocument() = 0; void slotSetDocType( const QString& ); protected: QWidget *mParent; QString mDocType; TextSelection *mTextSelection; }; #endif kraft-1.1/src/templates/000077500000000000000000000000001450127457600152625ustar00rootroot00000000000000kraft-1.1/src/templates/cpp_template000066400000000000000000000024441450127457600176660ustar00rootroot00000000000000/*************************************************************************** |FILENAME| - ------------------- begin : |DATE| copyright : (C) |YEAR| by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef |HEADER_DEF| #define |HEADER_DEF| #ifdef HAVE_CONFIG_H #include #endif // include files for Qt // include files for KDE #include #include class |CLASSNAME| : public _what_ { Q_OBJECT public: |CLASSNAME|(); ~|CLASSNAME|(); private: } #endif /* END */ kraft-1.1/src/templates/header_template000066400000000000000000000017271450127457600203370ustar00rootroot00000000000000/*************************************************************************** |FILENAME| - ------------------- begin : |DATE| copyright : (C) |YEAR| by |AUTHOR| email : |EMAIL| ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ kraft-1.1/src/templatesaverbase.cpp000066400000000000000000000027101450127457600174770ustar00rootroot00000000000000/*************************************************************************** templatesaverbase - ------------------- begin : 2005-20-01 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt // include files for KDE #include #include "templatesaverbase.h" TemplateSaverBase::TemplateSaverBase( ) { } bool TemplateSaverBase::saveTemplate(FloskelTemplate*) { return false; } void TemplateSaverBase::saveTemplateChapter( FloskelTemplate* ) { // do nothing } TemplateSaverBase::~TemplateSaverBase( ) { } CalculationsSaverBase::CalculationsSaverBase() { } CalculationsSaverBase::CalculationsSaverBase( TargetType ) { } /* END */ kraft-1.1/src/templatesaverbase.h000066400000000000000000000032161450127457600171460ustar00rootroot00000000000000/*************************************************************************** templatesaverbase - Base class of a template save class ------------------- begin : 2005-20-00 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _TEMPLATESAVERBASE_H #define _TEMPLATESAVERBASE_H // include files #include /** * */ class FloskelTemplate; class dbID; class CalcPartList; class TemplateSaverBase { public: TemplateSaverBase(); virtual ~TemplateSaverBase(); virtual bool saveTemplate( FloskelTemplate* ); virtual void saveTemplateChapter( FloskelTemplate* ); private: }; class CalculationsSaverBase { public: enum TargetType { Template, Document }; CalculationsSaverBase(); virtual ~CalculationsSaverBase() { } CalculationsSaverBase( TargetType ); virtual bool saveCalculations( CalcPartList, dbID ) = 0; }; #endif /* END */ kraft-1.1/src/templatesaverdb.cpp000066400000000000000000000301151450127457600171520ustar00rootroot00000000000000/*************************************************************************** templatesaverdb - ------------------- begin : 2005-20-00 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include // include files for KDE #include #include "kraftdb.h" #include "kraftglobals.h" #include "dbids.h" #include "templatesaverdb.h" #include "calcpart.h" #include "floskeltemplate.h" #include "timecalcpart.h" #include "fixcalcpart.h" #include "materialcalcpart.h" #include "stockmaterial.h" bool CalculationsSaverDB::saveFixCalcPart( FixCalcPart *cp, dbID parentID ) { bool result = true; QSqlTableModel model; model.setTable(mTableFixCalc); int cpId = cp->getDbID().toInt(); model.setFilter("FCalcID=" + QString::number( cpId )); model.select(); // qDebug () << "CalcFix calcpart-ID is " << cpId; if( cpId < 0 ) { // no db entry yet => INSERT if( !cp->isToDelete() ) { QSqlRecord buffer = model.record(); fillFixCalcBuffer( &buffer, cp ); buffer.setValue( "TemplID", parentID.toInt() ); model.insertRecord(-1, buffer); model.submitAll(); dbID id = KraftDB::self()->getLastInsertID(); // qDebug () << "Setting db-ID " << id.toString(); cp->setDbID(id); } else { // qDebug () << "new element, but set to delete"; } } else { if( cp->isToDelete() ) { // qDebug () << "deleting fix calc part " << cpId; // delete this calcpart. if ( model.rowCount() > 0 ) { int cnt = model.rowCount(); model.removeRows(0, cnt); model.submitAll(); // qDebug () << "Amount of deleted entries: " << cnt; } } else { // der Datensatz ist bereits in der Datenbank => UPDATE if( model.rowCount() > 0 ) { QSqlRecord buffer = model.record(0); buffer.setValue( "modDate", KraftDB::self()->currentTimeStamp() ); fillFixCalcBuffer(& buffer, cp ); model.setRecord(0, buffer); model.submitAll(); } else { qCritical() << "Can not select FCalcID, corrupt data!"; } } } return result; } void CalculationsSaverDB::fillFixCalcBuffer( QSqlRecord *buffer, FixCalcPart *cp ) { if( ! (buffer && cp )) return; buffer->setValue( "name", cp->getName() ); buffer->setValue( "amount", cp->getMenge() ); buffer->setValue( "price", cp->unitPreis().toDouble() ); buffer->setValue( "percent", cp->getProzentPlus() ); buffer->setValue( "modDate", KraftDB::self()->currentTimeStamp() ); } bool CalculationsSaverDB::saveMaterialCalcPart( MaterialCalcPart *cp, dbID parentID ) { bool result = true; if( !cp ) return result; QSqlTableModel model; model.setTable( mTableMatCalc ); model.setEditStrategy(QSqlTableModel::OnManualSubmit); int cpId = cp->getDbID().toInt(); model.setFilter("MCalcID=" + QString::number( cpId )); model.select(); // qDebug () << "Saving material calcpart id=" << cpId; if( cpId < 0 ) { // no entry in database yet, need to insert QSqlRecord buffer = model.record(); fillMatCalcBuffer( &buffer, cp ); buffer.setValue( "TemplID", parentID.toInt() ); model.insertRecord(-1, buffer); model.submitAll(); dbID id = KraftDB::self()->getLastInsertID(); cp->setDbID(id); } else { // there is an db entry, update needed if(cp->isToDelete()) { // This calcpart must be deleted if( model.rowCount() > 0) { model.removeRow(0); model.submitAll(); } } else { // don't delete, update! if( model.rowCount() > 0) { QSqlRecord buffer = model.record(0); buffer.setValue( "modDate", KraftDB::self()->currentTimeStamp() ); fillMatCalcBuffer( &buffer, cp ); model.setRecord(0, buffer); model.submitAll(); } else { qCritical() << "Can not select MCalcID, corrupt data!"; } } } return result; } void CalculationsSaverDB::fillMatCalcBuffer( QSqlRecord *buffer, MaterialCalcPart *cp ) { if( !(buffer && cp)) return; buffer->setValue("materialID", cp->getMaterial()->getID()); buffer->setValue("amount", cp->getCalcAmount()); buffer->setValue("TemplID", cp->getTemplID().toInt()); buffer->setValue("percent", cp->getProzentPlus() ); } CalculationsSaverDB::CalculationsSaverDB( ) : CalculationsSaverBase(), mTableTimeCalc( "CalcTime" ), mTableFixCalc( "CalcFixed" ), mTableMatCalc( "CalcMaterials" ), mTableMatDetailCalc( "CalcMaterialDetails" ) { } CalculationsSaverDB::CalculationsSaverDB( TargetType tt ) : CalculationsSaverBase( tt ), mTableTimeCalc( "CalcTime" ), mTableFixCalc( "CalcFixed" ), mTableMatCalc( "CalcMaterials" ), mTableMatDetailCalc( "CalcMaterialDetails" ) { if ( tt == Document ) { mTableTimeCalc = "DocCalcTime"; mTableFixCalc = "DocCalcFixed"; mTableMatCalc = "DocCalcMaterials"; mTableMatDetailCalc = "DocCalcMaterialDetails"; } } bool CalculationsSaverDB::saveCalculations( CalcPartList parts, dbID parentID ) { bool res = true; CalcPartListIterator it( parts ); while( it.hasNext()) { CalcPart *cp = it.next(); if( cp->isDirty() ) { if( cp->getType() == KALKPART_TIME ) { res = saveTimeCalcPart( static_cast(cp), parentID ); Q_ASSERT( res ); } else if( cp->getType() == KALKPART_FIX ) { res = saveFixCalcPart( static_cast(cp), parentID ); Q_ASSERT( res ); } else if( cp->getType() == KALKPART_MATERIAL ) { res = saveMaterialCalcPart( static_cast(cp), parentID ); Q_ASSERT( res ); } else { // qDebug () << "ERROR: Unbekannter Kalkulations-Anteil-Typ!"; } } } return res; } bool CalculationsSaverDB::saveTimeCalcPart( TimeCalcPart *cp, dbID parentId ) { bool result = true; if( !cp ) return result; int cpId = cp->getDbID().toInt(); QSqlTableModel model; model.setTable( mTableTimeCalc ); model.setFilter( "TCalcID="+QString::number(cpId) ); model.select(); // qDebug () << "Models last error: " << model.lastError() << model.rowCount(); if( cpId < 0 ) { // no entry in db yet => INSERT if( ! cp->isToDelete() ) { QSqlRecord buffer = model.record(); fillTimeCalcBuffer( &buffer, cp ); buffer.setValue( "TemplID", parentId.toInt() ); model.insertRecord(-1, buffer); dbID id = KraftDB::self()->getLastInsertID(); cp->setDbID(id); } else { // qDebug () << "delete flag is set -> skip saving."; } } else { if( cp->isToDelete() ) { // delete this calcpart. if ( model.rowCount() > 0 ) { model.removeRow(0); model.submitAll(); } } else { // Update needed, record is already in the database if( model.rowCount() > 0 ) { QSqlRecord buffer = model.record(0); buffer.setValue( "modDate", KraftDB::self()->currentTimeStamp() ); fillTimeCalcBuffer( &buffer, cp ); model.setRecord(0, buffer); model.submitAll(); } else { qCritical() << "Unable to select TCalcID, corrupt data!"; } } } return result; } void CalculationsSaverDB::fillTimeCalcBuffer( QSqlRecord *buffer, TimeCalcPart *cp ) { if( ! (buffer && cp )) return; buffer->setValue( "name", cp->getName() ); buffer->setValue( "minutes", cp->duration() ); buffer->setValue( "timeUnit", cp->timeUnitIndex()); buffer->setValue( "percent", cp->getProzentPlus() ); StdSatz std = cp->getStundensatz(); buffer->setValue( "stdHourSet", std.getId().toInt() ); buffer->setValue( "allowGlobal", cp->globalStdSetAllowed() ? 1 : 0 ); } /* =========================================================================== */ TemplateSaverDB::TemplateSaverDB( ) : TemplateSaverBase() { } TemplateSaverDB::~TemplateSaverDB( ) { } bool TemplateSaverDB::saveTemplate( FloskelTemplate *tmpl ) { bool res = true; // Transaktion ? QSqlTableModel model; model.setEditStrategy(QSqlTableModel::OnManualSubmit); model.setTable("Catalog"); QString templID = QString::number(tmpl->getTemplID()); model.setFilter("TemplID=" + templID); model.select(); QSqlRecord buffer; if( model.rowCount() > 0) { // qDebug () << "Updating template " << tmpl->getTemplID(); // mach update buffer = model.record(0); fillTemplateBuffer( &buffer, tmpl, false ); buffer.setValue( "modifyDatum", KraftDB::self()->currentTimeStamp() ); model.setRecord(0, buffer); model.submitAll(); } else { // insert // qDebug () << "Creating new database entry"; buffer = model.record(); fillTemplateBuffer( &buffer, tmpl, true ); model.insertRecord(-1, buffer); model.submitAll(); /* Jetzt die neue Template-ID selecten */ dbID id = KraftDB::self()->getLastInsertID(); // qDebug () << "New Database ID=" << id.toInt(); if( id.isOk() ) { tmpl->setTemplID(id.toInt() ); templID = id.toString(); } else { // qDebug () << "ERROR: Kann AUTOINC nicht ermitteln"; res = false; } } if( res ) { /* Nun die einzelnen Calcparts speichern */ CalcPartList parts = tmpl->getCalcPartsList(); CalculationsSaverDB calculationSaver; res = calculationSaver.saveCalculations( parts, tmpl->getTemplID() ); } return res; } void TemplateSaverDB::fillTemplateBuffer( QSqlRecord *buffer, FloskelTemplate *tmpl, bool isNew ) { buffer->setValue( "chapterID", tmpl->chapterId().toInt() ); buffer->setValue( "unitID", tmpl->unit().id()); buffer->setValue( "Floskel", tmpl->getText() ); buffer->setValue( "Gewinn", tmpl->getBenefit() ); buffer->setValue( "zeitbeitrag", tmpl->hasTimeslice() ); QDateTime dt = QDateTime::currentDateTime(); QString dtString = KraftDB::self()->currentTimeStamp(dt); if( isNew ) { buffer->setValue( "enterDatum", dtString); tmpl->setEnterDate( dt ); } buffer->setValue("modifyDatum", dtString ); tmpl->setModifyDate( dt ); int ctype = 2; // Calculation type Calculation if( tmpl->calcKind() == CatalogTemplate::ManualPrice ) { ctype = 1; } buffer->setValue( "Preisart", ctype ); buffer->setValue( "EPreis", tmpl->manualPrice().toDouble() ); } void TemplateSaverDB::saveTemplateChapter( FloskelTemplate* tmpl ) { if( tmpl ) { dbID id = tmpl->getTemplID(); dbID chapId = tmpl->chapterId(); QSqlQuery qUpdate; // qDebug () << "Updating Chapter to chapter id " << chapId.toInt() << " of id " << id.toString(); QString sql = "UPDATE Catalog SET chapterID=:chap WHERE TemplID=:id"; qUpdate.prepare( sql ); qUpdate.bindValue( ":chap", chapId.toInt() ); qUpdate.bindValue( ":id", id.toInt() ); qUpdate.exec(); // qDebug () << "setting template chapter sql: " << qUpdate.lastError().text(); } } /* END */ kraft-1.1/src/templatesaverdb.h000066400000000000000000000043611450127457600166230ustar00rootroot00000000000000/*************************************************************************** templatesaverdb - ------------------- begin : 2005-20-00 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _TEMPLATESAVERDB_H #define _TEMPLATESAVERDB_H #include "templatesaverbase.h" /** * */ class FloskelTemplate; class QSqlRecord; class QString; class TimeCalcPart; class FixCalcPart; class MaterialCalcPart; class StockMaterial; class TemplateSaverDB : public TemplateSaverBase { public: TemplateSaverDB(); virtual ~TemplateSaverDB(); virtual bool saveTemplate( FloskelTemplate* ); virtual void saveTemplateChapter( FloskelTemplate* ); private: void fillTemplateBuffer( QSqlRecord*, FloskelTemplate*, bool ); QString sqlWhereFromRecord( QSqlRecord * ) const; }; class CalculationsSaverDB:public CalculationsSaverBase { public: CalculationsSaverDB(); CalculationsSaverDB( TargetType tt ); virtual ~CalculationsSaverDB() { } bool saveCalculations( CalcPartList, dbID ); private: bool saveFixCalcPart( FixCalcPart *cp, dbID ); bool saveMaterialCalcPart( MaterialCalcPart *cp, dbID ); bool saveTimeCalcPart( TimeCalcPart*, dbID ); void fillFixCalcBuffer( QSqlRecord *buffer, FixCalcPart *cp ); void fillMatCalcBuffer( QSqlRecord *buffer, MaterialCalcPart *cp ); void fillTimeCalcBuffer( QSqlRecord*, TimeCalcPart* ); QString mTableTimeCalc; QString mTableFixCalc; QString mTableMatCalc; QString mTableMatDetailCalc; }; #endif /* END */ kraft-1.1/src/templkatalog.cpp000066400000000000000000000264211450127457600164610ustar00rootroot00000000000000/*************************************************************************** flostempllist.cpp - ------------------- begin : Son Feb 8 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "floskeltemplate.h" #include "dbids.h" #include "templkatalog.h" #include "kraftdb.h" #include "unitmanager.h" #include "timecalcpart.h" #include "fixcalcpart.h" #include "materialcalcpart.h" #include "geld.h" #include "katalog.h" /** constructor of a katalog, which is only a list of Floskel templates. * A name must be given, which is displayed for the root element in the * */ TemplKatalog::TemplKatalog( const QString& name ) : Katalog( name ) { } TemplKatalog::~TemplKatalog() { } void TemplKatalog::reload( dbID id) { FloskelTemplate *templ=0; //Find the template we want to reload in the templatelist for(int i=0; i < m_flosList.count(); ++i) { templ = m_flosList[i]; if(templ->getTemplID() == id.toInt()) break; } if(templ) { QSqlQuery q("SELECT unitID, TemplID, chapterID, Preisart, EPreis, modifyDatum, enterDatum, Floskel, Gewinn, zeitbeitrag FROM Catalog WHERE TemplID=:TemplID"); q.bindValue(":TemplID", id.toInt()); q.exec(); if(q.next()) { //templ->setEinheitId(q.value(0).toInt()); // qDebug() << "Reloading template number " << q.value(1); templ->setChapterId(dbID( q.value(2).toInt()), false ); //templ->setCalculationType(q.value(3).toInt()); templ->setManualPrice(q.value(4).toDouble()); templ->setText( q.value(7).toString() ); templ->setBenefit( q.value(8).toDouble()); templ->setHasTimeslice( q.value(9).toBool() ); templ->clearCalcParts(); loadCalcParts( templ ); } } } int TemplKatalog::load() { Katalog::load(); int cnt = 0; if (mChapters.isEmpty()) getKatalogChapters(true); QString chapIdList {"0"}; for( const CatalogChapter& chap : mChapters ) { chapIdList.append(","); chapIdList.append(chap.id().toString()); } // qDebug () << "The chapterIdList: " << chapIdList; QSqlQuery q("SELECT unitID, TemplID, chapterID, Preisart, EPreis, modifyDatum, enterDatum, " "Floskel, Gewinn, zeitbeitrag FROM Catalog WHERE chapterID IN( " + chapIdList + ") " "ORDER BY chapterID, sortKey" ); q.exec(); m_flosList.clear(); while ( q.next() ) { cnt++; int einheit = q.value(0).toInt(); int templID = q.value(1).toInt(); // qDebug () << "Loading template number " << templID; int chapID = q.value(2).toInt(); // int sortID = cur.value( "sortKey" ).toInt(); int calcKind = q.value(3).toInt(); double g = q.value(4).toDouble(); Geld preis(g); /* Only for debugging: */ if( templID == 272 ) { // qDebug () << "Geld ist " << preis.toString( *( &mLocale ) ) << " from g-value " << g; } QDateTime modDt = q.value(5).toDateTime(); QDateTime enterDt = q.value(6).toDateTime(); // qDebug() << "Chapter ID is " << chapID; FloskelTemplate *flos = new FloskelTemplate( templID, q.value(7).toString(), einheit, chapID, calcKind ); flos->setEnterDate( enterDt ); flos->setModifyDate( modDt ); // flos->setSortKey( sortID ); flos->setBenefit( q.value(8).toDouble()); flos->setManualPrice( preis ); bool tslice = q.value(9).toInt() > 0; flos->setHasTimeslice( tslice ); auto usage = usageCount(templID); flos->setLastUsedDate(usage.second); flos->setUseCounter(usage.first); loadCalcParts( flos ); m_flosList.append(flos); } return cnt; } int TemplKatalog::addNewTemplate( FloskelTemplate *tmpl ) { int re = -1; if ( tmpl ) { m_flosList.append( tmpl ); re = m_flosList.count(); } return re; } void TemplKatalog::deleteTemplate( int id ) { // Remove entry from the m_flosList FloskelTemplateListIterator it(m_flosList); FloskelTemplate *tmpl; int cnt = 0; while( it.hasNext() ) { tmpl = it.next(); if( tmpl->getTemplID() == id ) { break; } cnt++; } if( cnt < m_flosList.size()) { m_flosList.removeAt( cnt ); } QStringList tables; tables << "Catalog" << "CalcFixed" << "CalcMaterials" << "CalcTime"; for(const QString& table : tables ) { QSqlQuery q; q.prepare( "DELETE FROM " + table + " WHERE TemplID=:Id"); q.bindValue( ":Id", id ); q.exec(); // qDebug () << "SQL Delete Success: " << q.lastError().text(); } deleteUsageRecord(id); } int TemplKatalog::loadCalcParts( FloskelTemplate *flos ) { int cnt = 0; cnt = loadTimeCalcParts( flos ); cnt += loadFixCalcParts( flos ); cnt += loadMaterialCalcParts(flos); return cnt; } int TemplKatalog::loadTimeCalcParts( FloskelTemplate *flos ) { if( ! flos ) return(0); int cnt = 0; QSqlQuery q; q.prepare("SELECT TCalcID, TemplID, name, minutes, percent, stdHourSet, allowGlobal, timeUnit" " FROM CalcTime WHERE TemplID=:TemplID"); q.bindValue(":TemplID", QString::number( flos->getTemplID())); q.exec(); while( q.next() ) { cnt++; int tcalcid = q.value(0).toInt(); int templid = q.value(1).toInt(); const QString name = q.value(2).toString(); int minutes = q.value(3).toInt(); int prozent = q.value(4).toInt(); int hourSet = q.value(5).toInt(); bool globAllowed = q.value(6).toInt() > 0; int timeUnit = q.value(7).toInt(); TimeCalcPart::TimeUnit unit = TimeCalcPart::timeUnitFromInt(timeUnit); TimeCalcPart *zcp = new TimeCalcPart( name, minutes, unit, prozent ); zcp->setGlobalStdSetAllowed( globAllowed ); zcp->setStundensatz( StdSatzMan::self()->getStdSatz(hourSet) ); zcp->setDbID( dbID(tcalcid)); zcp->setTemplID( dbID(templid)); zcp->setDirty( false ); flos->addCalcPart( zcp ); } return cnt; } int TemplKatalog::loadMaterialCalcParts( FloskelTemplate *flos ) { if( ! flos ) return(0); int cnt = 0; QSqlQuery q; q.prepare("SELECT MCalcID, TemplID, materialID, percent, amount FROM CalcMaterials WHERE TemplID=:TemplID"); q.bindValue(":TemplID", QString::number( flos->getTemplID())); q.exec(); while( q.next() ) { cnt++; long mcalcID = q.value(0).toLongLong(); int templid = q.value(1).toInt(); long matID = q.value(2).toLongLong(); int procent = q.value(3).toInt(); double amount = q.value(4).toDouble(); MaterialCalcPart *mPart = new MaterialCalcPart( mcalcID, matID, procent, amount ); mPart->setDbID( dbID(mcalcID)); mPart->setTemplID( dbID(templid)); mPart->setDirty( false ); flos->addCalcPart( mPart ); } return cnt; } int TemplKatalog::loadFixCalcParts( FloskelTemplate *flos ) { if( ! flos ) return(0); int cnt = 0; QSqlQuery q; q.prepare("SELECT name, amount, percent, FCalcID, TemplID, price FROM CalcFixed WHERE TemplID=:TemplID"); q.bindValue(":TemplID", QString::number( flos->getTemplID())); q.exec(); while( q.next() ) { cnt++; QString name = q.value(0).toString(); double amount = q.value(1).toDouble(); int percent = q.value(2).toInt(); int tcalcid = q.value(3).toInt(); int templid = q.value(4).toInt(); double g = q.value(5).toDouble(); Geld price(g); // = (int) g; // FIXME: proper handling of money here. FixCalcPart *fcp = new FixCalcPart( name, price, percent ); fcp->setMenge( amount ); fcp->setDbID( dbID(tcalcid)); fcp->setTemplID( dbID(templid)); fcp->setDirty( false ); flos->addCalcPart( fcp ); } return cnt; } FloskelTemplateList TemplKatalog::getFlosTemplates(int chapId) { FloskelTemplateList resultList; if( m_flosList.count() == 0 ) { // qDebug () << "Empty katalog list - loading!"; load(); } FloskelTemplateListIterator it(m_flosList); FloskelTemplate *tmpl; while( it.hasNext() ) { tmpl = it.next(); int haveChap = tmpl->chapterId().toInt(); // qDebug() << "Searching for chapter " << chapter << " with ID " << chap << " and have " << haveChap; if( haveChap == chapId ) { resultList.append( tmpl ); } } return resultList; } int TemplKatalog::load( const QString& /* chapter */ ) { return 0; } void TemplKatalog::writeXMLFile() { QString filename = QFileDialog::getSaveFileName(0, QString(), QDir::homePath(), QString()); // "*.xml", 0, i18n("Export XML Katalog")); if(filename.isEmpty()) return; QDomDocument doc = toXML(); QFile file( filename ); if( file.open( QIODevice::WriteOnly ) ) { QTextStream ts( &file ); ts << doc.toString(); file.close(); } } QDomDocument TemplKatalog::toXML() { QDomDocument doc("catalog"); QDomElement root = doc.createElement("catalog"); doc.appendChild(root); QDomElement elem = doc.createElement("catalogname"); QDomText text = doc.createTextNode(m_name); elem.appendChild(text); root.appendChild(elem); QStringList allSets = StdSatzMan::self()->allStdSaetze(); for ( QStringList::Iterator it = allSets.begin(); it != allSets.end(); ++it ) { QDomElement set = doc.createElement("hourset"); QDomElement elem = doc.createElement("name"); QDomText tname = doc.createTextNode(*it); elem.appendChild(tname); set.appendChild(elem); QDomElement rateelem = doc.createElement("rate"); StdSatz satz = StdSatzMan::self()->getStdSatz(*it); Geld g = satz.getPreis(); QDomText rname = doc.createTextNode(g.toLocaleString()); rateelem.appendChild(rname); set.appendChild(rateelem); root.appendChild(set); } QList chaps = getKatalogChapters(); foreach( CatalogChapter theChapter, chaps ) { QString chapter = theChapter.name(); QDomElement chapElem = doc.createElement("chapter"); QDomElement chapName = doc.createElement("chaptername"); text = doc.createTextNode(chapter); chapName.appendChild(text); chapElem.appendChild(chapName); root.appendChild(chapElem); FloskelTemplateList templs = getFlosTemplates(theChapter.id().toInt()); FloskelTemplateListIterator it(templs); // FIXME: XML export! } return doc; } int TemplKatalog::getEntriesPerChapter( const CatalogChapter& chapter) { int cnt = 0; QString q( QString("SELECT count(*) FROM katalog WHERE chapterID=%1" ).arg( chapter.id().toInt() ) ); QSqlQuery query( q ); while ( query.next() ) { cnt = query.value(0).toInt(); } return cnt; } kraft-1.1/src/templkatalog.h000066400000000000000000000040671450127457600161300ustar00rootroot00000000000000/*************************************************************************** katalog.h - ------------------- begin : Son Feb 8 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef TEMPLKATALOG_H #define TEMPLKATALOG_H #include #include "floskeltemplate.h" #include "katalog.h" #include "dbids.h" /** *@author Klaas Freitag */ class MaterialCalcPart; class QDomDocument; class TemplKatalog : public Katalog { public: TemplKatalog(const QString& name); ~TemplKatalog(); int load(const QString&); int load() override; void reload( dbID ) override; /** No descriptions */ FloskelTemplateList getFlosTemplates( int ); KatalogType type() override { return TemplateCatalog; } QDomDocument toXML() override; /** get the amount of entries in a chapter or the entire catalog */ int getEntriesPerChapter( const CatalogChapter& ) override; int addNewTemplate( FloskelTemplate *tmpl ); public slots: void writeXMLFile() override; void deleteTemplate( int ); private: int loadCalcParts( FloskelTemplate* ); int loadTimeCalcParts( FloskelTemplate* ); int loadFixCalcParts( FloskelTemplate* ); int loadMaterialCalcParts( FloskelTemplate * ); FloskelTemplateList m_flosList; }; #endif kraft-1.1/src/templkataloglistview.cpp000066400000000000000000000206411450127457600202460ustar00rootroot00000000000000 /*************************************************************************** templkataloglistview - template katalog listview. ------------------- begin : 2005-07-09 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include "templkataloglistview.h" #include "portal.h" #include "kraftglobals.h" #include "katalog.h" #include "katalogman.h" #include "kataloglistview.h" #include "materialcalcpart.h" #include "stockmaterial.h" #include "templkatalog.h" #include "timecalcpart.h" #include "docposition.h" #include "defaultprovider.h" #include "kraftsettings.h" TemplKatalogListView::TemplKatalogListView(QWidget *w) : KatalogListView(w), mShowCalcParts( true ) { QStringList labels; labels << i18n("Template"); labels << i18n("Price"); labels << i18n("Calc. Type"); setHeaderLabels(labels); QByteArray headerState = QByteArray::fromBase64( KraftSettings::self()->templateCatViewHeader().toLatin1() ); header()->restoreState(headerState); contextMenu()->setTitle( i18n("Template Catalog")); } /* * This class adds a complete catalog and fills the view. It gets the * catalog from KatalogMan, iterates over the catalog chapters and * fills in the templates. */ void TemplKatalogListView::addCatalogDisplay( const QString& katName ) { KatalogListView::addCatalogDisplay(katName); TemplKatalog* catalog = static_cast(KatalogMan::self()->getKatalog(katName)); if ( !catalog ) { qCritical() << "Could not load catalog " << katName; return; } setupChapters(); const QList chapters = catalog->getKatalogChapters(); foreach( CatalogChapter chap, chapters ) { if( mChapterDict.contains( chap.id().toInt() ) ) { int chapId = chap.id().toInt(); QTreeWidgetItem *katItem = mChapterDict[chapId]; FloskelTemplateList katList = catalog->getFlosTemplates(chapId); FloskelTemplateListIterator flosIt( katList ); while( flosIt.hasNext() ) { FloskelTemplate *tmpl = flosIt.next(); /* create a ew item as the child of katalog entry */ addFlosTemplate( katItem, tmpl ); if ( mShowCalcParts ) addCalcParts( tmpl ); } } } // ... and all what is zero is going to the top level FloskelTemplateList katList = catalog->getFlosTemplates(0); for( FloskelTemplate *tmpl : katList) { addFlosTemplate(nullptr, tmpl); if ( mShowCalcParts ) addCalcParts( tmpl ); } } /* * add a single template to the view with setting icon etc. */ QTreeWidgetItem* TemplKatalogListView::addFlosTemplate( QTreeWidgetItem *parentItem, FloskelTemplate *tmpl ) { if( ! parentItem ) parentItem = m_root; QTreeWidgetItem *listItem = new QTreeWidgetItem( parentItem ); slFreshupItem( listItem, tmpl); tmpl->setListViewItem( listItem ); if( tmpl->calcKind() == CatalogTemplate::ManualPrice ) { listItem->setIcon(0, DefaultProvider::self()->icon( "dice" ) ); } else { listItem->setIcon(0, DefaultProvider::self()->icon("calculator")); } if ( mCheckboxes ) { listItem->setCheckState(0, Qt::Unchecked); } // store the connection between the listviewitem and the template in a dict. m_dataDict.insert( listItem, tmpl ); return listItem; } void TemplKatalogListView::slFreshupItem( QTreeWidgetItem *item, FloskelTemplate *tmpl, bool remChildren ) { if( !(item && tmpl) ) return; Geld g = tmpl->unitPrice(); const QString ck = tmpl->calcKindString(); const QString t = Portal::textWrap(tmpl->getText(), 72, 4); item->setText( 0, t ); if( t.endsWith(QStringLiteral("..."))) { item->setToolTip(0, Portal::textWrap(tmpl->getText(), 72, 22)); } QString h; h = QString( "%1 / %2" ).arg( g.toLocaleString() ) .arg( tmpl->unit().einheitSingular() ); item->setText( 1, h ); item->setText( 2, ck ); // item->setText( 4, QString::number(tmpl->getTemplID())); if( remChildren ) { /* remove all children and insert them again afterwards. * That updates the view */ for( int i = 0; i < item->childCount(); i++ ) { QTreeWidgetItem *it = item->child(i); if( it ) { item->removeChild( it ); delete it; } } addCalcParts(tmpl); // Insert to update the view again. } } void TemplKatalogListView::addCalcParts( FloskelTemplate *tmpl ) { QTreeWidgetItem *item = tmpl->getListViewItem(); if( ! item ) return; CalcPartList parts = tmpl->getCalcPartsList(); CalcPartListIterator it(parts); while( it.hasNext() ) { CalcPart *cp = it.next(); QString title = cp->getName(); QString type = cp->getType(); // qDebug () << "Type is " << type; if( type == KALKPART_TIME ) { TimeCalcPart *zcp = static_cast(cp); StdSatz stdsatz = zcp->getStundensatz(); title = QString( "%1, %2 %3 %4" ) .arg( cp->getName() ) .arg( QString::number(zcp->duration())) .arg( TimeCalcPart::timeUnitString(zcp->timeUnit())) .arg( stdsatz.getName() ); } QStringList list; list << title; list << cp->basisKosten().toLocaleString(); list << cp->getType(); QTreeWidgetItem *cpItem = new QTreeWidgetItem( item, list ); cpItem->setDisabled(true); } } void TemplKatalogListView::setShowCalcParts( bool on ) { mShowCalcParts = on; } bool TemplKatalogListView::showCalcParts() { return mShowCalcParts; } TemplKatalogListView::~TemplKatalogListView() { } DocPosition TemplKatalogListView::itemToDocPosition( QTreeWidgetItem *it ) { DocPosition pos; if ( ! it ) { it = currentItem(); } if ( ! it ) return pos; FloskelTemplate *flos = static_cast( m_dataDict[ it ] ); if ( flos ) { pos.setText( flos->getText() ); pos.setUnit( flos->unit() ); pos.setUnitPrice( flos->unitPrice() ); } else { // qDebug () << "Can not find a template for the item"; } return pos; } CalcPartList TemplKatalogListView::itemsCalcParts( QTreeWidgetItem* it ) { CalcPartList cpList; if ( ! it ) { it = currentItem(); } if ( ! it ) return cpList; FloskelTemplate *flos = static_cast( m_dataDict[ it ] ); if ( flos ) { // qDebug () << "We have calc parts: " << flos->getCalcPartsList().count(); cpList = flos->getCalcPartsList(); } return cpList; } // Updates the sequence of items below a parent item stored in the inherited // variable mSortChapterItem void TemplKatalogListView::startUpdateItemSequence() { Q_ASSERT(_query == nullptr); _query = new QSqlQuery; _query->prepare("UPDATE Catalog SET sortKey=? WHERE TemplID=?"); } void TemplKatalogListView::updateItemSequence(QTreeWidgetItem *item, int seqNo) { FloskelTemplate *flos = static_cast( itemData(item) ); // qDebug () << "Updating item " << flos->getTemplID() << " to sort key " << sequenceCnt; if( _query && flos ) { _query->bindValue( 0, seqNo ); _query->bindValue( 1, flos->getTemplID() ); _query->exec(); } } void TemplKatalogListView::saveState() { const QByteArray state = this->header()->saveState(); KraftSettings::self()->setTemplateCatViewHeader(state.toBase64()); KraftSettings::self()->save(); } kraft-1.1/src/templkataloglistview.h000066400000000000000000000040301450127457600177050ustar00rootroot00000000000000/*************************************************************************** templkataloglistview - template katalog listview. ------------------- begin : 2005-07-09 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef TEMPLKATALOGLISTVIEW_H #define TEMPLKATALOGLISTVIEW_H #include #include #include "floskeltemplate.h" /** @author Klaas Freitag */ class DocPosition; class TemplKatalogListView : public KatalogListView { Q_OBJECT public: TemplKatalogListView(QWidget*); ~TemplKatalogListView(); FloskelTemplate *currentTemplate(); /* create a listview entry for a floskel template */ QTreeWidgetItem *addFlosTemplate( QTreeWidgetItem*, FloskelTemplate* ); void addCatalogDisplay( const QString&); void setShowCalcParts( bool ); bool showCalcParts(); DocPosition itemToDocPosition( QTreeWidgetItem* it = 0 ); CalcPartList itemsCalcParts( QTreeWidgetItem* it = 0 ); public slots: void slFreshupItem( QTreeWidgetItem*, FloskelTemplate*, bool remChildren = false ); void saveState(); protected: virtual void startUpdateItemSequence(); virtual void updateItemSequence(QTreeWidgetItem *item, int seqNo); private: bool mShowCalcParts; void addCalcParts( FloskelTemplate* ); }; #endif kraft-1.1/src/templkatalogview.cpp000066400000000000000000000205101450127457600173450ustar00rootroot00000000000000/*************************************************************************** templkatalogview.cpp ------------------- begin : 2005-07-09 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for QT #include #include #include #include #include // application specific includes #include "katalogview.h" #include "templkatalogview.h" #include "floskeltemplate.h" #include "kataloglistview.h" #include "flostempldialog.h" #include "templkatalog.h" #include "templkataloglistview.h" #include "katalogman.h" #include "documentman.h" #include "kraftsettings.h" #define ID_STATUS_MSG 1 TemplKatalogView::TemplKatalogView(QWidget* parent, const char* name) : KatalogView(parent, name), m_flosDialog(nullptr), m_listview(nullptr) { } TemplKatalogView::~TemplKatalogView() { slotSaveState(); delete m_flosDialog; } Katalog* TemplKatalogView::getKatalog( const QString& name ) { Katalog *k = KatalogMan::self()->getKatalog( name ); if( ! k ) { k = new TemplKatalog( name ); KatalogMan::self()->registerKatalog( k ); } return k; } ///////////////////////////////////////////////////////////////////// // SLOT IMPLEMENTATION ///////////////////////////////////////////////////////////////////// void TemplKatalogView::slEditTemplate() { TemplKatalogListView* listview = static_cast(getListView()); if( listview ) { QTreeWidgetItem *item = listview->currentItem(); if( listview->isChapter(item) ) { // check if the chapter is empty. If so, switch to slNewTempalte() // if there others, open the chapter. if( !listview->isRoot( item ) && item->childCount() == 0 ) { slNewTemplate(); } else { // do nothing. } } else { // the clicked item is not a chapter FloskelTemplate *currTempl = static_cast (listview->currentItemData()); if( currTempl ) { QTreeWidgetItem *item = (QTreeWidgetItem*) listview->currentItem(); openDialog( item, currTempl, false ); } } } } void TemplKatalogView::slNewTemplate() { KatalogListView *listView = getListView(); if( !listView ) return; // create new template object FloskelTemplate *flosTempl = new FloskelTemplate(); flosTempl->setText( i18n( "" ) ); // find the corresponding parent (==chapter) item QTreeWidgetItem *parentItem = static_cast(listView->currentItem()); if( parentItem ) { // if it is not a chapter nor root, take the parent if( ! (listView->isRoot(parentItem) || listView->isChapter(parentItem)) ) { parentItem = (QTreeWidgetItem*) parentItem->parent(); } } if( parentItem ) { // try to find out which catalog is open/current CatalogChapter *chap = static_cast( listView->itemData( parentItem ) ); if( chap ) { flosTempl->setChapterId( chap->id().toInt(), true ); } } TemplKatalogListView *templListView = static_cast(listView); QTreeWidgetItem *item = templListView->addFlosTemplate(parentItem, flosTempl); listView->scrollToItem( item ); listView->setCurrentItem( item ); openDialog( item, flosTempl, true ); } void TemplKatalogView::slDeleteTemplate() { // qDebug () << "delete template hit"; TemplKatalogListView* listview = static_cast(getListView()); if( listview ) { FloskelTemplate *currTempl = static_cast (listview->currentItemData()); if( currTempl ) { int id = currTempl->getTemplID(); QMessageBox msgBox; msgBox.setText(i18n( "Do you really want to delete the template from the catalog?" )); msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Ok); int result = msgBox.exec(); if( result == QMessageBox::Ok) { // qDebug () << "Delete item with id " << id; TemplKatalog *k = static_cast( getKatalog( m_katalogName ) ); if( k ) { k->deleteTemplate( id ); listview->removeTemplateItem( listview->currentItem()); } } } } } bool TemplKatalogView::currentItemToDocPosition( DocPosition& pos ) { TemplKatalogListView* listview = static_cast(getListView()); bool res = false; if( listview ) { FloskelTemplate *currTempl = static_cast (listview->currentItemData()); if( currTempl ) { // create a new position and offer it to the document manager pos.setText( currTempl->getText() ); pos.setUnit( currTempl->unit() ); pos.setUnitPrice( currTempl->unitPrice() ); pos.setAmount( 1.0 ); res = true; } } return res; } CalcPartList TemplKatalogView::currentItemsCalcParts() { TemplKatalogListView* listview = static_cast(getListView()); CalcPartList cpList; if( listview ) { FloskelTemplate *currTempl = static_cast (listview->currentItemData()); if ( currTempl ) { cpList = currTempl->getCalcPartsList(); } } return cpList; } void TemplKatalogView::openDialog( QTreeWidgetItem *listitem, FloskelTemplate *tmpl, bool isNew ) { if( ! m_flosDialog ) { m_flosDialog = new FlosTemplDialog(this, false); connect( m_flosDialog, SIGNAL(editAccepted( FloskelTemplate* )), this, SLOT( slEditOk(FloskelTemplate*))); connect( m_flosDialog, SIGNAL(editRejected( )), this, SLOT( slEditRejected())); } m_flosDialog->setTemplate( tmpl, m_katalogName, isNew ); m_editListViewItem = listitem; m_flosDialog->refreshPrices(); m_flosDialog->show(); } void TemplKatalogView::slEditOk(FloskelTemplate* templ) { // the dialog saves the template in its accept-slot. KatalogListView *listview = getListView(); if( !listview ) return; TemplKatalogListView *templListView = static_cast(listview); if(m_flosDialog ){ if ( m_flosDialog->templateIsNew() ) { TemplKatalog *k = static_cast( getKatalog( m_katalogName ) ); if ( k ) k->addNewTemplate( templ ); } } if( templListView && m_editListViewItem ) { // qDebug () << "Edit was ok, refreshing item in list " << m_editListViewItem; templListView->setCurrentItem( m_editListViewItem ); templListView->slFreshupItem( m_editListViewItem, templ, true ); templListView->scrollToItem( m_editListViewItem ); } m_editListViewItem = nullptr; } void TemplKatalogView::slEditRejected() { // qDebug () << "Rejecting Edit!"; if ( m_editListViewItem ) { delete m_editListViewItem; m_editListViewItem = nullptr; } } void TemplKatalogView::createCentralWidget(QBoxLayout*box, QWidget *w) { // qDebug () << "Creating new Listview"; m_listview = new TemplKatalogListView( w ); box->addWidget(m_listview); KatalogView::createCentralWidget( box, w ); } void TemplKatalogView::saveWindowState( const QByteArray& arr ) { KraftSettings::self()->setTemplateCatViewState(arr); } QByteArray TemplKatalogView::windowState() { const QByteArray re = QByteArray::fromBase64( KraftSettings::self()->templateCatViewState().toLatin1() ); return re; } void TemplKatalogView::saveWindowGeo( const QByteArray& arr ) { KraftSettings::self()->setTemplateCatViewGeo( QString::fromLatin1(arr) ); } QByteArray TemplKatalogView::windowGeo() { const QByteArray re = QByteArray::fromBase64( KraftSettings::self()->templateCatViewGeo().toLatin1() ); return re; } kraft-1.1/src/templkatalogview.h000066400000000000000000000052141450127457600170160ustar00rootroot00000000000000/*************************************************************************** templkatalogview.h ------------------- begin : 2005-07-09 copyright : (C) 2005 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef TEMPLKATALOGVIEW_H #define TEMPLKATALOGVIEW_H // include files for Qt #include #include "katalogview.h" #include "templkataloglistview.h" class TemplKatalog; class KatalogListView; class FloskelTemplate; class FlosTemplDialog; class QBoxLayout; /** * The base class for Kraft katalog view. * @author Klaas Freitag * @version $Id$ */ class TemplKatalogView: public KatalogView { Q_OBJECT public: /** construtor of KraftApp, calls all init functions to create the application. */ TemplKatalogView(QWidget* parent=0, const char* name=0); TemplKatalogView(const QString& katToShow, QWidget* parent=0, const char* name=0); ~TemplKatalogView(); // virtual KatalogListView *createListView(QWidget*); /** opens a file specified by commandline option */ void createCentralWidget(QBoxLayout*, QWidget*); KatalogListView* getListView(){return m_listview;} protected: Katalog* getKatalog( const QString& ); bool currentItemToDocPosition( DocPosition& ); CalcPartList currentItemsCalcParts(); void saveWindowState( const QByteArray& arr ); QByteArray windowState(); void saveWindowGeo( const QByteArray& arr ); QByteArray windowGeo(); public slots: /* Editing of templates -> open edit dialog */ void slEditTemplate(); void slNewTemplate(); void slDeleteTemplate(); /* selected Ok in the template editor */ void slEditOk(FloskelTemplate*); void slEditRejected(); private: // opens the edit dialog. void openDialog( QTreeWidgetItem*, FloskelTemplate *, bool ); // editing dialog for templates FlosTemplDialog *m_flosDialog; TemplKatalogListView *m_listview; }; #endif // TEMPLKATALOGVIEW_H kraft-1.1/src/templtopositiondialogbase.cpp000066400000000000000000000045611450127457600212620ustar00rootroot00000000000000/*************************************************************************** templtopositiondialogbase.cpp - base dialog template to doc ------------------- begin : Mar 2007 copyright : (C) 2007 Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include "templtopositiondialogbase.h" #include "docposition.h" TemplToPositionDialogBase::TemplToPositionDialogBase( QWidget *w ) : QDialog( w ) { setObjectName( "TEMPL_DIALOG" ); setWindowTitle( i18n("Create Item from Template" ) ); setModal( true ); } TemplToPositionDialogBase::~TemplToPositionDialogBase() { } void TemplToPositionDialogBase::setPositionList( DocPositionList list, int intendedPos ) { if ( ! getPositionCombo() ) { qCritical() << "Can not get a ptr to the position combo"; return; } QStringList strList; strList << i18n( "the Header of the Document as first item" ); DocPositionListIterator it( list ); while( it.hasNext() ) { DocPosition *dp = static_cast( it.next() ); QString h = QString( "%1. %2" ).arg( list.posNumber( dp ) ).arg( dp->text() ); if ( h.length() > 50 ) { h = h.left( 50 ); h += i18n( "..." ); } strList.append( h ); } getPositionCombo()->insertItems( -1, strList ); getPositionCombo()->setCurrentIndex( intendedPos ); } int TemplToPositionDialogBase::insertAfterPosition() { int itemPos = getPositionCombo()->currentIndex(); // qDebug () << "Current item selected: " << itemPos; return itemPos; } kraft-1.1/src/templtopositiondialogbase.h000066400000000000000000000036171450127457600207300ustar00rootroot00000000000000/*************************************************************************** templtopositiondialogbase.h - base dialog template to doc ------------------- begin : Mar 2007 copyright : (C) 2007 Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef TEMPLTOPOSITIONDIALOGBASE #define TEMPLTOPOSITIONDIALOGBASE #include #include class QWidget; class DocPosition; class DocPositionList; class QComboBox; class TemplToPositionDialogBase: public QDialog { Q_OBJECT public: TemplToPositionDialogBase( QWidget* ); ~TemplToPositionDialogBase( ); virtual void setDocPosition( DocPosition*, bool, bool ) = 0; virtual void setCatalogChapters( const QList&, const QString& ) = 0; virtual QString chapter() const = 0; void setPositionList( DocPositionList, int ); int insertAfterPosition(); virtual DocPosition docPosition() = 0; protected: /** * Needs to be reimplemented to return a pointer to a * combobox which can be filled with the current list * of positions to let the user select where the new * pos should go to. */ virtual QComboBox* getPositionCombo() = 0; }; #endif kraft-1.1/src/texteditbase.ui000066400000000000000000000154211450127457600163130ustar00rootroot00000000000000 TextEditBase 0 0 481 286 0 0 11 75 true Edit Document Text Template Qt::PlainText false QFrame::HLine QFrame::Sunken &Name: false mEditName Qt::AlignTop false 0 0 displayed as false 0 0 75 true textLabel2 false 0 0 in doc type false 0 0 75 true textLabel3 false Qt::Horizontal QSizePolicy::Expanding 65 16 &Text: Qt::AlignTop false mEditText true Qt::Horizontal QSizePolicy::Expanding 212 16 mEditName mEditText kraft-1.1/src/texteditdialog.cpp000066400000000000000000000067011450127457600170060ustar00rootroot00000000000000/*************************************************************************** texteditdialog.cpp - Edit document text templates ------------------- begin : Apr 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "templtopositiondialogbase.h" #include "texteditdialog.h" #include "doctext.h" #include "defaultprovider.h" TextEditDialog::TextEditDialog( QWidget *parent, KraftDoc::Part docPart ) : QDialog( parent ) { setObjectName( "TEMPL_DIALOG" ); setModal( true ); setWindowTitle( i18n("Edit Text Templates" )); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QWidget *mainWidget = new QWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(mainWidget); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); //PORTING: Verify that widget was added to mainLayout: //PORTING: Verify that widget was added to mainLayout: setMainWidget( mainWidget ); // Add mainLayout->addWidget(mainWidget); if necessary // Add mainLayout->addWidget(mainWidget); if necessary mBaseWidget = new Ui::TextEditBase; mBaseWidget->setupUi( mainWidget ); mBaseWidget->mDocTypeLabel->setText( DocText::textTypeToString( docPart ) ); QString h = i18n( "Edit %1 Template", DocText::textTypeToString( docPart ) ); mBaseWidget->dmHeaderText->setText( h ); mainLayout->addWidget(buttonBox); } TextEditDialog::~TextEditDialog() { } void TextEditDialog::setDocText( DocText dt ) { QString name = i18n( "Template" ); if ( ! dt.name().isEmpty() ) { name = dt.name(); } mBaseWidget->mEditName->setText( name ); // mBaseWidget->mEditDescription->setText( dt.description() ); mBaseWidget->mEditText->setText( dt.text() ); mBaseWidget->mDocPartLabel->setText( dt.textTypeString() ); mBaseWidget->mDocTypeLabel->setText( dt.docType() ); mOriginalText = dt; } DocText TextEditDialog::docText() { DocText dt; dt = mOriginalText; dt.setName( mBaseWidget->mEditName->text() ); dt.setDescription( QString() ); // mBaseWidget->mEditDescription->text() ); dt.setText( mBaseWidget->mEditText->toPlainText() ); // dt.setDocType( mBaseWidget->mCbDocType->currentText() ); // dt.setTextType( DocText::stringToTextType( mBaseWidget->mCbTextType->currentText() ) ); return dt; } kraft-1.1/src/texteditdialog.h000066400000000000000000000026311450127457600164510ustar00rootroot00000000000000/*************************************************************************** texteditdialog.h - Edit document text templates ------------------- begin : Apr 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef TEXTEDITDIALOG_H #define TEXTEDITDIALOG_H #include #include "ui_texteditbase.h" #include "doctext.h" #include "kraftdoc.h" class QWidget; class QComboBox; class DocText; class TextEditBase; class TextEditDialog: public QDialog { Q_OBJECT public: TextEditDialog( QWidget*, KraftDoc::Part ); ~TextEditDialog( ); virtual void setDocText( DocText ); DocText docText(); private: Ui::TextEditBase *mBaseWidget; DocText mOriginalText; }; #endif kraft-1.1/src/textselection.cpp000066400000000000000000000172341450127457600166710ustar00rootroot00000000000000/*************************************************************************** textselection - widget to select header- and footer text data for the doc ------------------- begin : 2007-06-01 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "textselection.h" #include "filterheader.h" #include "defaultprovider.h" #include "kraftdoc.h" #include "doctype.h" #include "doctext.h" #include #include #include #include #include #include #include #include #include #include #include #include TextSelection::TextSelection( QWidget *parent, KraftDoc::Part part ) :QWidget( parent ), mPart( part ) { mGroupBox = new QGroupBox(i18n("Template Collection")); QVBoxLayout *layout = new QVBoxLayout; setLayout(layout); layout->addWidget( mGroupBox ); /* a view for the entry text repository */ QVBoxLayout *vbox = new QVBoxLayout; vbox->setMargin(0); mTextNameView = new QListView; vbox->addWidget(mTextNameView); mTextNameView->setSelectionMode( QAbstractItemView::SingleSelection ); mTextNameView->setMaximumHeight(120 ); mTextNameView->setEditTriggers( QAbstractItemView::NoEditTriggers ); connect( mTextNameView, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(editCurrentTemplate())); mTextDisplay = new QTextEdit; mTextDisplay->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken ); mTextDisplay->setLineWidth( 1 ); mTextDisplay->setReadOnly(true); QPalette p = mTextDisplay->palette(); p.setColor( QPalette::Active, QPalette::Base, p.color(QPalette::Window)); p.setColor( QPalette::Inactive, QPalette::Base, p.color(QPalette::Window)); mTextDisplay->setPalette(p); vbox->addWidget( mTextDisplay, 3 ); mHelpDisplay = new QLabel; mHelpDisplay->setStyleSheet("background-color: #ffcbcb;"); mHelpDisplay->setAutoFillBackground(true); mHelpDisplay->setWordWrap( true ); QFontMetrics fm( mHelpDisplay->font() ); int minHeight = 1.5 * fm.height(); mHelpDisplay->setMinimumHeight( minHeight ); mHelpDisplay->setAlignment( Qt::AlignCenter | Qt::AlignVCenter ); mHelpDisplay->hide(); vbox->addWidget( mHelpDisplay ); mGroupBox->setLayout( vbox ); mTemplNamesModel = new QStringListModel; mTextNameView->setModel( mTemplNamesModel ); connect( mTextNameView->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ), this, SLOT( slotTemplateNameSelected( const QModelIndex&, const QModelIndex& ) ) ); #if 0 connect( mTextsView, SIGNAL( currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*) ), this, SLOT( slotSelectionChanged( QTreeWidgetItem* ) ) ); connect( mTextsView, SIGNAL(doubleClicked(QModelIndex) ), this, SLOT( slotSelectionChanged( QTreeWidgetItem* ) ) ); #endif // Context Menu mMenu = new QMenu( this ); mMenu->setTitle( i18n("Template Actions") ); #if 0 mTextsView->setContextMenuPolicy(Qt::CustomContextMenu); connect( mTextsView, SIGNAL(customContextMenuRequested(QPoint) ), this, SLOT( slotRMB( QPoint ) ) ); #endif initActions(); } /* selected the name of a template in the listview of template names */ void TextSelection::slotTemplateNameSelected( const QModelIndex& current, const QModelIndex& ) { if( current.isValid() ) { mCurrTemplateName = mTemplNamesModel->data( current, Qt::DisplayRole ).toString(); // qDebug () << "New selected template name: " << mCurrTemplateName; showHelp(); DocText dt = currentDocText(); showDocText( dt ); } else { mCurrTemplateName.clear(); } emit validTemplateSelected( ); } void TextSelection::showDocText( DocText dt ) { if( dt.type() != KraftDoc::Unknown && dt.isStandardText() ) { showHelp(i18n("This is the standard text used in new documents.")); } mTextDisplay->setText( dt.text() ); } void TextSelection::slotSelectDocType( const QString& doctype ) { QString partStr = KraftDoc::partToString( mPart ); QString t = QString( i18n( "%1 Templates for %2", partStr, doctype) ); mGroupBox->setTitle( t ); mDocType = doctype; DocTextList dtList = DefaultProvider::self()->documentTexts( doctype, mPart ); QStringList templNames; if( dtList.count() == 0 ) { showHelp( i18n("There is no %1 template text available for document type %2.
            " "Click the add-button below to create one.", partStr, doctype ) ); } else { foreach( DocText dt, dtList ) { templNames << dt.name(); } showHelp(); } mTemplNamesModel->setStringList( templNames ); mTextDisplay->clear(); } void TextSelection::addNewDocText( const DocText& dt ) { slotSelectDocType( mDocType ); // update the list of available texts QModelIndexList newItems = mTemplNamesModel->match( mTemplNamesModel->index(0), Qt::DisplayRole, dt.name() ); if( newItems.size() > 0 ) { QModelIndex selected = newItems[0]; mTextNameView->selectionModel()->setCurrentIndex( selected, QItemSelectionModel::Select); } else { // qDebug () << "Unable to find the new item named " << dt.name(); } emit validTemplateSelected(); } /* requires the QListViewItem set as a member in the doctext */ void TextSelection::updateDocText( const DocText& ) { QModelIndex selected = mTextNameView->selectionModel()->currentIndex(); if( selected.isValid() ) { slotSelectDocType( mDocType ); mTextNameView->selectionModel()->setCurrentIndex( selected, QItemSelectionModel::Select ); } } bool TextSelection::validSelection() const { return mTextNameView->selectionModel()->currentIndex().isValid(); } void TextSelection::deleteCurrentText() { slotSelectDocType( mDocType ); } TextSelection::~TextSelection() { } void TextSelection::initActions() { mAcMoveToDoc = new QAction(DefaultProvider::self()->icon( "arrow-narrow-left" ), i18n("&Use in Document"), this); connect(mAcMoveToDoc, SIGNAL(triggered()), this, SIGNAL(actionCurrentTextToDoc())); mMenu->addAction( mAcMoveToDoc ); } /* if the help string is empty, the help widget disappears. */ void TextSelection::showHelp( const QString& help ) { mHelpDisplay->setText( help ); if( help.isEmpty() ) { mHelpDisplay->hide(); } else { mHelpDisplay->show(); #if 0 // qDebug () << "Displaying help text: " << help; QPropertyAnimation *ani = new QPropertyAnimation( mHelpDisplay, "geometry" ); QRect r2 = r1; r2.setHeight( 200 ); ani->setDuration( 2000 ); ani->setStartValue( r1 ); ani->setEndValue( r2 ); ani->start(); #endif } } DocText TextSelection::currentDocText() const { DocTextList dtList = DefaultProvider::self()->documentTexts( mDocType, mPart ); foreach( DocText dt, dtList ) { if( dt.name() == mCurrTemplateName ) { return dt; } } DocText dt; return dt; } QString TextSelection::currentText() const { return currentDocText().text(); } void TextSelection::slotRMB(QPoint ) { // mMenu->popup( mTextsView->mapToGlobal(point) ); } kraft-1.1/src/textselection.h000066400000000000000000000055001450127457600163270ustar00rootroot00000000000000/*************************************************************************** textselection - widget to select header- and footer text data for the doc ------------------- begin : 2007-06-01 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef FOOTERSELECTION_H #define FOOTERSELECTION_H #include #include #include #include "kraftdoc.h" class QTreeWidget; class QTreeWidgetItem; class QString; class QPoint; class QMenu; class DocText; class QAction; class QListView; class QStringListModel; class QTextEdit; class QLabel; class QModelIndex; class QGroupBox; class TextSelection : public QWidget { Q_OBJECT public: TextSelection( QWidget*, KraftDoc::Part ); ~TextSelection(); QString currentText() const; DocText currentDocText() const; bool validSelection() const; signals: void actionCurrentTextToDoc(); void currentTextChanged( const QString& ); void validTemplateSelected(); void editCurrentTemplate(); public slots: void addNewDocText( const DocText& ); void deleteCurrentText(); void updateDocText( const DocText& ); void slotSelectDocType( const QString& ); void slotRMB( QPoint ); protected: void initActions(); void buildTextList( KraftDoc::Part ); void showDocText( DocText ); protected slots: // void slotSelectionChanged( QTreeWidgetItem* ); void slotTemplateNameSelected( const QModelIndex&, const QModelIndex& ); void showHelp( const QString& help = QString() ); private: QListView *mTextNameView; QStringListModel *mTemplNamesModel; QTextEdit *mTextDisplay; QLabel *mHelpDisplay; KraftDoc::Part mPart; QString mDocType; QString mCurrTemplateName; QMap mTextMap; QMap mDocTypeItemMap; QMap mStandardItemMap; QMenu *mMenu; QGroupBox *mGroupBox; QAction *mAcMoveToDoc; }; #endif kraft-1.1/src/texttemplate.cpp000066400000000000000000000072271450127457600165200ustar00rootroot00000000000000/*************************************************************************** texttemplate.cpp - fill a template with text tags ------------------- begin : Sep 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "texttemplate.h" #include "ctemplate/template.h" #include "klocalizedstring.h" #include #include TextTemplate::TextTemplate() :TextTemplateInterface(), mStandardDict( nullptr ) { } TextTemplate::~TextTemplate() { if (mStandardDict) delete mStandardDict; } bool TextTemplate::createSubDictionary( const QString& parent, const QString& name ) { Dictionary ttd; bool re = false; if ( mDictionaries.contains( parent ) ) { ttd.mDict = mDictionaries[parent]->AddSectionDictionary( name.toLatin1().data() ); ttd.mParent = parent; ttd.mName = name; mDictionaries[name] = ttd.mDict; re = true; } return re; } void TextTemplate::createDictionary( const QString& dictName ) { if ( mStandardDict ) { mDictionaries[dictName] = mStandardDict->AddSectionDictionary( dictName.toLatin1().data() ); mStandardDict->ShowSection( dictName.toLatin1().data() ); } } void TextTemplate::setValue( const QString& dictName, const QString& key, const QString& val ) { TemplateDictionary *dict = nullptr; if ( mDictionaries.contains( dictName ) ) { dict = mDictionaries[dictName]; } else { if( mStandardDict ) { dict = mStandardDict->AddSectionDictionary( dictName.toLatin1().data() ); mDictionaries[dictName] = dict; mStandardDict->ShowSection( dictName.toLatin1().data() ); } } if ( dict ) dict->SetValue( key.toLatin1().data(), val.toStdString() ); // std::string( val.toUtf8() ) ); } void TextTemplate::setValue( const QString& key, const QString& val ) { if ( mStandardDict ) { mStandardDict->SetValue( key.toLatin1().data(), val.toStdString() ); } } void TextTemplate::setValue( Dictionary ttd, const QString& key, const QString& val ) { if ( ttd.mDict ) { ( ttd.mDict )->SetValue( key.toLatin1().data(), val.toStdString() ); } } bool TextTemplate::initialize() { Template *tmpl = Template::GetTemplate(fileName().toStdString(), ctemplate::DO_NOT_STRIP ); if ( !tmpl || tmpl->state() != ctemplate::TS_READY ) { setError( i18n( "Failed to open template source" ) ); return false; } tmpl->ReloadAllIfChanged(); if (mStandardDict) delete mStandardDict; mStandardDict = new TemplateDictionary( "TopLevel" ); return true; } QString TextTemplate::expand() { std::string output; if ( mStandardDict) { bool errorFree = ExpandTemplate( fileName().toStdString(), ctemplate::DO_NOT_STRIP ,mStandardDict, &output ); QString qout = QString::fromStdString(output); qout.remove(QChar(0)); if ( errorFree ) { return qout; } } return QStringLiteral("Unable to expand template"); } kraft-1.1/src/texttemplate.h000066400000000000000000000051341450127457600161600ustar00rootroot00000000000000/*************************************************************************** texttemplate.h - fill a template with text tags ------------------- begin : Sep 2007 copyright : (C) 2007 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef TEXTTEMPLATE_H #define TEXTTEMPLATE_H #include #include #include "texttemplateinterface.h" #include #include using ctemplate::Template; using ctemplate::TemplateDictionary; class TextTemplate : public TextTemplateInterface { private: struct Dictionary { QString mParent; QString mName; TemplateDictionary *mDict; }; public: TextTemplate(); ~TextTemplate() override; /** * set a value in the default dictionary */ void setValue( const QString&, const QString& ) override; /** * set a value in the named dictionary * Parameters: * the parameter group name * the key name * the value */ void setValue( const QString&, const QString&, const QString& ); void setValue( Dictionary, const QString& , const QString& ); void createDictionary( const QString& ); /** * creates a sub dictionary to a given dictionary. * Parameter 1 is the parent dict, Param 2 the sub dictionary name. */ bool createSubDictionary( const QString& , const QString& ); /** * creates a dictionary with the name given in parameter two nested * in the parent dictionary given in the first parameter. * * The dictionary struck is given back to use with setValue. */ // Dictionary createSubDictionary( Dictionary, const QString& ); /** * get the expanded output */ QString expand() override; protected: virtual bool initialize() override; private: TemplateDictionary *mStandardDict; QMap mDictionaries; }; #endif kraft-1.1/src/texttemplateinterface.cpp000066400000000000000000000025701450127457600203750ustar00rootroot00000000000000#include "texttemplateinterface.h" #include "defaultprovider.h" #include #include #include namespace { QString findTemplateFile(const QString &filename) { QString tmplFile; if( ! filename.isEmpty() ) { const QString templFileName = QStringLiteral("kraft/")+filename; tmplFile = DefaultProvider::self()->locateFile(templFileName); } return tmplFile; } } // end of anonym namespace TextTemplateInterface::TextTemplateInterface() { } TextTemplateInterface::~TextTemplateInterface() { } QString TextTemplateInterface::fileName() const { return _fileName; } bool TextTemplateInterface::setTemplateFileName( const QString& name ) { _errorString.clear(); _fileName = name; QFileInfo info( _fileName ); if ( info.isAbsolute() ) { // assume it is a absolute path } else { _fileName = findTemplateFile(_fileName); if ( _fileName.isEmpty() ) { _errorString = i18n( "No file name given for template" ); return false; } info.setFile( _fileName ); } if ( ! ( info.isFile() && info.isReadable() ) ) { _errorString = i18n( "Could not find template file %1", info.absoluteFilePath() ); return false; } qDebug () << "Loading template source file: " << _fileName; return initialize(); } bool TextTemplateInterface::isOk() { return _errorString.isEmpty(); } kraft-1.1/src/texttemplateinterface.h000066400000000000000000000027661450127457600200510ustar00rootroot00000000000000#ifndef TextTemplateInterface_H #define TextTemplateInterface_H #include class TextTemplateInterface { public: TextTemplateInterface(); virtual ~TextTemplateInterface(); /** * take the template absolute filename of the template source and * load it immediately. * returns true if successful. Otherwise check errorString() for * error messages */ bool setTemplateFileName(const QString& file); QString fileName() const; /** * @brief isOk - returns true if the TextTemplate is ok and can be used. * @return true if the text template can be used. */ virtual bool isOk(); /** * return a describing string if something went wrong when opening * the template. */ QString errorString() const { return _errorString; } /** * set a value in the default dictionary */ virtual void setValue( const QString&, const QString& ) = 0; /** * get the expanded output */ virtual QString expand() = 0; protected: /** * @brief initialize - use for basic initialization * @return true if successful * * This method can assume that the filename member var points to * a valid file. */ virtual bool initialize() = 0; /** * @brief overwrites the error message * @param the error string */ void setError(const QString& msg) { _errorString = msg; } private: QString _fileName; QString _errorString; }; #endif // TextTemplateInterface_H kraft-1.1/src/timecalcdialog.cpp000066400000000000000000000057201450127457600167350ustar00rootroot00000000000000/*************************************************************************** Timecalcdialog - ------------------- begin : 2004-23-09 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // include files for Qt #include #include #include #include #include "timecalcdialog.h" #include "timecalcpart.h" #include "stdsatzman.h" TimeCalcDialog::TimeCalcDialog(QWidget *parent) : CalcDialogBase( parent ), _timeWidget(new Ui::calcdetailTime), _part(0) { _timeWidget->setupUi(_centralWidget); _timeWidget->m_hourSets->insertItems(-1, StdSatzMan::self()->allStdSaetze()); _timeWidget->_cbTimeUnit->addItems(TimeCalcPart::timeUnitStrings()); } void TimeCalcDialog::setTimeCalcPart(TimeCalcPart *cp) { _part = cp; if( ! cp ) return; _timeWidget->m_nameEdit->setText( cp->getName()); _timeWidget->m_dauer->setValue( cp->duration()); _timeWidget->_cbTimeUnit->setCurrentText( TimeCalcPart::timeUnitString(cp->timeUnit())); _timeWidget->m_stdGlobal->setChecked(cp->globalStdSetAllowed()); StdSatz std = cp->getStundensatz(); _timeWidget->m_hourSets->setCurrentIndex(_timeWidget->m_hourSets->findText( std.getName() )); } void TimeCalcDialog::accept() { if( _part ) { _part->setGlobalStdSetAllowed(_timeWidget->m_stdGlobal->isChecked()); _part->setDuration(_timeWidget->m_dauer->value(), _timeWidget->_cbTimeUnit->currentText()); _part->setName(_timeWidget->m_nameEdit->text()); QString selHourSet = _timeWidget->m_hourSets->currentText(); StdSatz stdsatz = StdSatzMan::self()->getStdSatz(selHourSet); _part->setStundensatz(stdsatz); } if( _part && _part->isDirty() ) { emit timeCalcPartChanged(_part); } CalcDialogBase::accept(); } QString TimeCalcDialog::getName() { return _timeWidget->m_nameEdit->text(); } int TimeCalcDialog::getDauer() { return _timeWidget->m_dauer->value(); } bool TimeCalcDialog::allowGlobal() { return _timeWidget->m_stdGlobal->isChecked(); } QString TimeCalcDialog::getStundensatzName() { return _timeWidget->m_hourSets->currentText(); } QString TimeCalcDialog::unitStr() const { return _timeWidget->_cbTimeUnit->currentText(); } /* END */ kraft-1.1/src/timecalcdialog.h000066400000000000000000000031321450127457600163750ustar00rootroot00000000000000/*************************************************************************** Timecalcdialog - ------------------- begin : 2004-23-09 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _TimeCALCDIALOG_H #define _TimeCALCDIALOG_H // include files #include "calcdialogbase.h" #include "ui_timepart.h" /** * */ class TimeCalcPart; class TimeCalcDialog : public CalcDialogBase { Q_OBJECT public: TimeCalcDialog(QWidget *parent=0); void setTimeCalcPart(TimeCalcPart *cp); QString getName(); QString getStundensatzName(); int getDauer(); bool allowGlobal(); QString unitStr() const; signals: void timeCalcPartChanged(TimeCalcPart*); protected slots: void accept(); private: Ui_calcdetailTime *_timeWidget; TimeCalcPart *_part; }; #endif /* END */ kraft-1.1/src/timecalcpart.cpp000066400000000000000000000101341450127457600164370ustar00rootroot00000000000000/*************************************************************************** timecalcpart.cpp - ------------------- begin : Don Jan 1 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include "klocalizedstring.h" #include "timecalcpart.h" TimeCalcPart::TimeCalcPart() :CalcPart(), _duration( 0 ), m_allowGlobalStundensatz(false), _timeUnit(Minutes) { } TimeCalcPart::TimeCalcPart(const QString& name, int minutes, TimeUnit unit, int prozent) :CalcPart( name, prozent ), _duration( minutes ), m_allowGlobalStundensatz(true), _timeUnit( unit ) { } TimeCalcPart::~TimeCalcPart() { } StdSatz& TimeCalcPart::getStundensatz() { return m_stundensatz; } /** Write property of Geld m_stundensatz. */ void TimeCalcPart::setStundensatz( const StdSatz& _newVal) { // qDebug() << "stundensatz gesetzt: " << _newVal.toString(); m_stundensatz = _newVal; setDirty(true); } void TimeCalcPart::setGlobalStdSetAllowed( bool s ) { if( m_allowGlobalStundensatz != s ) { m_allowGlobalStundensatz = s; setDirty(true); } } void TimeCalcPart::setDuration( int duration, const QString& unitStr ) { if( _duration != duration || timeUnitString(_timeUnit) != unitStr ) { _duration = duration; _timeUnit = timeUnitFromString(unitStr); setDirty(true); } } QString TimeCalcPart::timeUnitString( const TimeUnit& unit ) { if( unit == Minutes ) { return i18n("Minutes"); } else if( unit == Hours) { return i18n("Hours"); } return i18n("Seconds"); } QStringList TimeCalcPart::timeUnitStrings() { // When adding something here make sure to adjust other places in the file return QStringList() << timeUnitString(Minutes) << timeUnitString(Seconds) << timeUnitString(Hours); } TimeCalcPart::TimeUnit TimeCalcPart::timeUnitFromString( const QString& unit) { const QStringList li = timeUnitStrings(); int pos = li.indexOf(unit); return timeUnitFromInt(pos); } TimeCalcPart::TimeUnit TimeCalcPart::timeUnitFromInt( int index ) { // the static_cast here need to be updated if new enums are added if( index > -1 && index <= static_cast(Hours)) { switch (index) { case static_cast(Minutes): case static_cast(Seconds): case static_cast(Hours): return static_cast(index); default: // this is actually an error case, forgot to add a pot. new enum... return Minutes; } } return Minutes; } int TimeCalcPart::timeUnitIndex() const { // Make sure to adopt this if a new unit is added! if( _timeUnit == Hours ) return 2; else if( _timeUnit == Seconds ) return 1; else return 0; } qint32 TimeCalcPart::durationToSeconds() const { if( _timeUnit == Minutes ) { return _duration * 60; } else if( _timeUnit == Hours ) { return 60*60*_duration; } // seconds is default return _duration; } Geld TimeCalcPart::basisKosten() { StdSatz stdSatz = getStundensatz(); const Geld g( (stdSatz.getPreis().toLong() * durationToSeconds()) / 360000.0); return g; } QString TimeCalcPart::getType() const { return KALKPART_TIME; } kraft-1.1/src/timecalcpart.h000066400000000000000000000044551450127457600161150ustar00rootroot00000000000000/*************************************************************************** Timecalcpart.h - ------------------- begin : Don Jan 1 2004 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef TIMECALCPART_H #define TIMECALCPART_H #include #include "stdsatzman.h" /** *@author Klaas Freitag */ class TimeCalcPart : public CalcPart { public: enum TimeUnit {Minutes, Seconds, Hours}; TimeCalcPart( const QString& name, int minutes, TimeUnit unit, int prozent = 0); TimeCalcPart(); ~TimeCalcPart(); bool globalStdSetAllowed() { return m_allowGlobalStundensatz; } void setGlobalStdSetAllowed( bool s ); void setDuration(int duration, const QString &unitStr ); static QStringList timeUnitStrings(); static QString timeUnitString( const TimeUnit& unit ); static TimeCalcPart::TimeUnit timeUnitFromString( const QString& unit); static TimeCalcPart::TimeUnit timeUnitFromInt(int index); qint32 durationToSeconds() const; qint32 duration() const { return _duration; } TimeUnit timeUnit() const { return _timeUnit; } int timeUnitIndex() const; virtual Geld basisKosten(); /** Write property of Geld m_stundensatz. */ virtual void setStundensatz( const StdSatz& _newVal); /** Read property of Geld m_stundensatz. */ virtual StdSatz& getStundensatz(); virtual QString getType() const; private: qint32 _duration; /** */ StdSatz m_stundensatz; bool m_allowGlobalStundensatz; TimeUnit _timeUnit; }; #endif kraft-1.1/src/timepart.ui000066400000000000000000000076321450127457600154600ustar00rootroot00000000000000 calcdetailTime 0 0 432 275 Calculation Item Time <h1>Calculation Part 'Time'</h1> false Calculate time efforts here for one unit of the template. <br/>Note that the costs may depend on a global hourly rate. Qt::RichText Qt::AlignVCenter false &Label: false m_nameEdit Work &Time Effort: false m_dauer 5 0 10000 &Hourly Rate: false m_hourSets 0 0 Apply the &global hourly rate m_nameEdit m_dauer m_hourSets m_stdGlobal kraft-1.1/src/unitmanager.cpp000066400000000000000000000062701450127457600163070ustar00rootroot00000000000000/*************************************************************************** unitmanager - ------------------- begin : 2004-05-05 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include // include files for KDE #include #include #include "unitmanager.h" #include "einheit.h" Q_GLOBAL_STATIC(UnitManager, mSelf) UnitManager* UnitManager::self() { return mSelf; } UnitManager::UnitManager( ) { } void UnitManager::load() { QSqlQuery q( "SELECT unitID, unitShort, unitLong, unitPluShort, unitPluLong, ec20 FROM units"); while( q.next()) { int unitID = q.value(0).toInt(); Einheit e( unitID, q.value(1).toString(), q.value(2).toString(), q.value(3).toString(), q.value(4).toString(), q.value(5).toString()); mUnits.append(e); } } int UnitManager::nextFreeId() { int id = 0; if( mUnits.size() == 0 ) { load(); } foreach( Einheit u, mUnits ) { if( u.id() > id ) { id = u.id(); } } return id+1; } QStringList UnitManager::allUnits() { QStringList list; if(mUnits.size() == 0 ) load(); foreach( Einheit e, mUnits ) { QString uSing = e.einheitSingular(); if( !uSing.isEmpty()) list << uSing; } return list; } Einheit UnitManager::getPauschUnit() { int id = getUnitIDSingular(QStringLiteral("pausch.")); if (id > -1) return getUnit(id); return Einheit(); } Einheit UnitManager::getUnit( int id ) { if( mUnits.size() == 0 ) load(); // qDebug() << "Searching unit ID " << id; foreach( Einheit e, mUnits ) { if( e.id() == id ) return e; } return Einheit(); } int UnitManager::getUnitIDSingular( const QString& einheitStr ) { if( mUnits.size() == 0 ) load(); foreach( Einheit tmp, mUnits ) { if( tmp.einheitSingular() == einheitStr || tmp.einheitPlural() == einheitStr ) { // qDebug() << "Thats it, returning " << tmp.id(); return tmp.id(); } } return -1; } QString UnitManager::getECE20(const QString& einheitStr) { if( mUnits.size() == 0 ) load(); for( Einheit tmp: mUnits ) { if( tmp.einheitSingular() == einheitStr || tmp.einheitPlural() == einheitStr ) { // qDebug() << "Thats it, returning " << tmp.id(); return tmp.ec20(); } } return QString(); } UnitManager::~UnitManager( ) { } /* END */ kraft-1.1/src/unitmanager.h000066400000000000000000000032371450127457600157540ustar00rootroot00000000000000/*************************************************************************** unitmanager - ------------------- begin : 2004-05-05 copyright : (C) 2004 by Klaas Freitag email : freitag@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _UNITMANAGER_H #define _UNITMANAGER_H #include "einheit.h" /** * */ // FIXME: How to identify the unit for piece? #define PIECE_UNIT_ID 6 class UnitManager { public: UnitManager(); virtual ~UnitManager(); static UnitManager* self(); Einheit getUnit( int id ); Einheit getPauschUnit(); QStringList allUnits(); int getUnitIDSingular( const QString& einheit ); QString getECE20(const QString& einheitStr); // Workaround: since the unit table does not have an auto update id coloum, // this function calculates the next free unit id to save a new one. int nextFreeId(); private: Einheit::List mUnits; void load(); }; #endif /* END */ kraft-1.1/src/unitseditbase.ui000066400000000000000000000052731450127457600164750ustar00rootroot00000000000000 UnitsEditBase 0 0 319 241 <h1>Add a unit</h1> false Unit short mUnitShort Unit long mUnitLong Unit plural short mUnitPluShort Unit plural long mUnitPluLong Unit ECE20 mUnitPluLong kraft-1.1/src/upgradedb.ui000066400000000000000000000052711450127457600155650ustar00rootroot00000000000000 upgradeDbForm 0 0 420 186 This step checks if the database schema version is sufficient for this version of Kraft. In case it is not, the schema is updated automatically. true 0 0 / 129 30 0 X Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Status: Upgrade not yet started true Qt::Vertical 20 101 kraft-1.1/src/version.h.in000066400000000000000000000012721450127457600155310ustar00rootroot00000000000000#pragma once namespace Kraft { namespace Version { // Static content. Maintain values here. inline QString number() { return QStringLiteral("1.1"); } inline QString codeName() { return QStringLiteral("Lynoel"); } inline int dbSchemaVersion() { return 24; } // dynamic content. These values get defined at build time in the top CMakeLists.txt inline QString gitSha() { return QStringLiteral("@GIT_SHA1@"); } inline QString gitBranch() { return QStringLiteral("@GIT_BRANCH@"); } inline QString buildHost() { return QStringLiteral("@BUILD_HOST_NAME@"); } inline QString buildHostDistro() { return QStringLiteral("@BUILD_HOST_DISTRI@"); } } } kraft-1.1/src/wageseditbase.ui000066400000000000000000000025551450127457600164410ustar00rootroot00000000000000 WagesEditBase 0 0 348 123 <h1>Add a Wage group</h1> false Group name Wage kraft-1.1/src/xrechnung.ui000066400000000000000000000050741450127457600156320ustar00rootroot00000000000000 XRechnungDialog 0 0 343 169 Dialog <html><head/><body><p><span style=" font-size:14pt; font-weight:600;">XRechnung Additional Data</span></p></body></html> false Due Date: Buyer Reference: Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() XRechnungDialog accept() 248 254 157 274 buttonBox rejected() XRechnungDialog reject() 316 260 286 274 kraft-1.1/styles/000077500000000000000000000000001450127457600140205ustar00rootroot00000000000000kraft-1.1/styles/CMakeLists.txt000066400000000000000000000004421450127457600165600ustar00rootroot00000000000000########### install files ############### add_subdirectory(pics) install(FILES templcatalog.style DESTINATION ${DATA_INSTALL_DIR}/kraft/styles) install(FILES docdigestview.css docoverview.css docoverview_ro.css catalogview.css systemview.css DESTINATION ${DATA_INSTALL_DIR}/kraft/styles) kraft-1.1/styles/catalogview.css000066400000000000000000000005751450127457600170460ustar00rootroot00000000000000 * { font-family: sans-serif; margin-left: 10px; margin-top: 10px; } h2 { padding-top: 20px; margin-left: 20px; margin-bottom: 10px; } tr { } td.bigfont { font-size: x-large; color: #323432; font-weight: bold; background: #dffdd0; padding-right: 20px; } td.sub { margin-bottom: 20px; padding-left: 20px; padding-bottom: 30px; font-size: small; } kraft-1.1/styles/docdigestview.css000066400000000000000000000000351450127457600173700ustar00rootroot00000000000000 h2 { color: #64ad24; } kraft-1.1/styles/docoverview.css000066400000000000000000000016171450127457600170730ustar00rootroot00000000000000 body { background-image:url(pics/docoverviewbg.png); font-family: 'Source Sans Pro', sans-serif; } td { vertical-align:top; } div { padding: 1px; color: #898989; } a:link { text-decoration: none; color: #00008b; } a:visited { text-decoration: none; color: #00008b; } a:hover { color: #00008b; text-decoration: none; } a:active { color: #00008b; text-decoration: underline; } .headerlink { background: #8ddbe9; } .headerlink_selected { background: #9af0ff; font-weight: bold; } .bodylink { background: #8de99a; } .bodylink_selected { background: #9affaa; font-weight: bold; } .footerlink { background: #dbe98d; } .footerlink_selected { background: #f0ff9a; font-weight: bold; } .negative { color: #800040; } .head_selected { } .body_selected { } .foot_selected { } td.baseline { } td.itemnums { } td.itemtexts { } td.prices { } kraft-1.1/styles/docoverview_ro.css000066400000000000000000000007101450127457600175640ustar00rootroot00000000000000body { margin:20px; background-image:url(pics/docoverviewbg.png); color: #4e4e4e; font-size:x-small; font-family: 'Source Sans Pro', sans-serif; } td { vertical-align:top; } div { border-style:none; border-width:0px; border-color:#00008B; margin: 1px 0px 1px 0px; padding: 1px; } .negative { color: #800040; } .positive { } div.header { margin-top: 120; margin-bottom: 20px; vertical-align:bottom; } kraft-1.1/styles/pics/000077500000000000000000000000001450127457600147565ustar00rootroot00000000000000kraft-1.1/styles/pics/Blank_Calendar_page_icon.svg000066400000000000000000000203621450127457600223260ustar00rootroot00000000000000 image/svg+xml blank calendar 20071204 Jackaranga GFDL kraft-1.1/styles/pics/CMakeLists.txt000066400000000000000000000002651450127457600175210ustar00rootroot00000000000000########### install files ############### install(FILES docoverviewbg.png kraftapp_logo_trans.png kraft_customer.png postit.png DESTINATION ${DATA_INSTALL_DIR}/kraft/styles/pics) kraft-1.1/styles/pics/Calendar_page.png000066400000000000000000000050701450127457600201730ustar00rootroot00000000000000PNG  IHDR|ZbKGD pHYs B(xtIME 3qx IDATxkl[c؉\΅6IeҎ)C ! e~ V VƘШ[XۥTHEcem^HMԎ9ѬMb[ct~|w,M}>'н^2ޯ{>w)q9ssX@?80f5'EFɿm۶M̈́jEW EǞmڔ)‡+ l;g,VJ㨦Wl3!ɴ p'W4A;Xu}sBx͙n+… DpA "\D .pA 2[Ͱ%(PoVQ_8zh^YO)tgR6<'Ex8$EL(r78 ǽ(M%F4-mrHj"R d~l&?e /&3KƵ':%&5gR40( 2jLDrUOP53<7iSx(,Li/w9iu8ŋTZ!\`' FAYYv7XCWaF"_pӟBYj=TXFFdA뫪R]2߃+[MUwRUC3??%gw]M|ԁ-_\U`^g8 G5[R]>-BZ-C!Px=J K^Ӷ62pL v#_{n2%v)#/N*M&ye^Y <FAx?5 N]g:OB$<[T8~ !qX-^LYS'y[ɟB7@i,_ҝxjȉp_Ql$Qn膝^>V+'U{ApdhIa!IUE4IqN8wGcσޢcx$.%J:a^C=~ VAD́FNn 8Z\ïǂqx<|2rF~Z/-ȗ(*yjnvXjɇMu#'jBR Ň`nTxvS}iGRo"wnM.K[%9 ,;7bܿsFbOµG,&@.;\.nn ϭ).6AmB`pҥeJu[&Szn!k6ٖ=\fH˶L 6| [^\D .pA "\D ..pA "\D .pA "\K D .pA "\D .pApA "\D .pA "\DD .pA "\D …/i&i t]LD"& xDK6rh45b===  ~#fhh)w9/)n]]]o[[[$ٷo/6|KVp8LWWW;7xw&;y:;;_+'m:'2$v BG MMMx2v5~ ,\'N$u!+Bz]]݁D뽱XLlݺfq xGejܹ>oD"tMV^.{HSSSsGGdz_3 Z穪z+$sDm]P͟@ [qEQ$Ϋھ}[^򫡺S@@VAJ$~ ,L Omm/Ri bϞ=e˖xrOv=([74M߻wotÆ 'jjj`&NƬTTTSYYX}} u֭3M8G՚Ϸ2i᪨vr:EEE%eee6iq8VEQ)D  A0{ٷsSĤDIENDB`kraft-1.1/styles/pics/docoverviewbg.png000066400000000000000000000003171450127457600203320ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIME  !%*dtEXtCommentCreated with The GIMPd%n3IDAT8c !?+8A&dEh^^^3d4 ̀MBTIENDB`kraft-1.1/styles/pics/kraft_customer.png000066400000000000000000000114401450127457600205140ustar00rootroot00000000000000PNG  IHDR00WtEXtSoftwareAdobe ImageReadyqe<IDATxZi]Y~wx;;N8iRph46 TЖPAS "AT@-E~T]( ޔiK8x6sG 1f sMpw<ව ꋏc~]` ю8QSuyh=R[=3`;6LY< W3 }<<_4d, ~?e^!]hi;2Fɑ4Lv729/֔,{a<'{;l+dz}:sdǂ0XVV+ô_mdO XӴˤ]-)3U`Q?+eOM^4%@7ip9<ݹGN{_ ĽKjٖ-"K;ô]:!ycFXyGEᑇnŁr o=VTݿ^z= ɛb$ftc?:d7l?sMC?KLDy׆\HBE(v:]ty;?{|6[q YSs]سK.Y• j6i92ꦇ=b lu+*dLF-TDwA:9TVѢ#ׁ{M bdD8_ysWuA\^lm9T6T6^=҉/:4OV{Ư i Aԏ&2@u XFͶD9 sþad6q~zuJIE# dFرs|R Kg:_AU& l07%Kz}|\]vhP0 oFʏ"td_;KK l7>V*-,5 窛ݡ8Jwt ˎ򐉁9Cm:)^zfBρ/kvM`6,ǁC5<ze(+ aY$2ܨ t]3:EL2K}epw+z>1NAo9t V]?ҷ/4;v abba26p@ NEq8y-7XD1Z (3AR ڍv>|^$F$6L]3{ʥ܁ geF th"y!f*X}w '=YXvqۑ]8zx'cn`!ɖn (-~$>U7K*hWMJmt5 e rb)9X 'jBR*#v,^qxiEJؐfK8VEx,J l.r Ik$mIB֙UmCϹkdߊ$8 y4  :B ZBu ( NT7XW]U 0`|8b0 U3f4 J[v|C{K)0(ӑ׽M1q1o,/1384sIKx)Y&>9<p| ftזt |Hō(1.,n/ [~tjT^^ax8԰uOWuF'عmxj~gq2;i:mvhA&>c<с\.3e0dK5 WdND,k}F?YF[N%CFet#)5|?jy5U 3K8 4:8h1CN_Bg=U<9d{x<5F,t{L6sbe"u`3ņsnFWc"vSp9#) n–ϠRbtg|Wkx1ߦ,a{"e%ք\L=V*f9Q9hӡ@#e gbqE|6-ߏ*f)|I+'!f$Rwގѹ#_{fm]3BkVkr54dRgFulx!x<[^_|_Bg #Mv-d9 RpJ4 =q\=C]{|-1G cR0Xkx2W~X Y\xMЉ<(a,[}oib03zTC”c2"wrɏ@E+D(g#2?s;8kP퀑v8#C>!Cٗ x A~/$9fh}YKae*2c *i! ~< \3~K}yTIĖ7?73ͫ/)l qLOa3į+QŽq%(Ρ,Xܨh$Xo'oY:y`M7+w,Nݍ0nB7Iﻟ`xI5'$^{9ŻIB/TqH&MsIL|s0 34ʵDqWQaYCXrz_1>gkfQL$0_G'7XFpMXWq.t}{OlYC1ìW;ǵlN89JaR* &GʸkrÅTrTƔSrHt,,.+Qcj$*a/=S.h=p>8)n,CF ohቸĕ_۞$ ö09>ZRer$\2+MsjVP6Ռ"QGQB |ȽX;x/^\_?}_C @/lp\/:fH9Rh4=>Dof⻭\QJ>5YYp]qF1iI Ѧ9 LyeҒ I$~Ze<<6!$NHH7T$F"L% <`&'$S7r-5ic;K"QP+xK[mjI$,xRݓj2x D}A&b]b qh<hG A3DyME?z],bHL !wv$-(Lx=Q-aj֦:{Gл6>RCD9q3fRž4yD Wg{&۝q$5~7WE^V7HG_Qճ-beOo,t,JZKk-it=xtSuA4g c {O_Z+FD;ݒ+YMo]][mf;.SE|@E[2HhEH"wVd$ GIK1իu]{ĺT&x#Qa-U/peYyB^ȴ;pzSW>0D`;@0cYdSR#&ힰMJ->SoE| 0ۉ%mϏ~/G|2S7L-+EO32ENm2$-HcV%V4A8J]Cz?s?|pZ3:arxI/$p#K P·3 F8`&-!eDUE%tk><}/3o` V7nIENDB`kraft-1.1/styles/pics/kraftapp_logo_trans.png000066400000000000000000000054341450127457600215310ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs  tIME  1IiTXtCommentCreated with GIMPd.e IDATxk]UϹ{Ə9)*RA"HP_A%ቃ82䬛GGǂ%yI5:iwzKHaI Lp# " hD S۾HGWL- i72;XΫ&rZyw1ҷ~I -W 'k:)>E0ZEIn$}-u/˱;V#?زWI ,`F4M%37\3ܱxp)ͷs;KˍCĹX40'"|Ͻ)dد'\B"`>;%(F˽sM\ ;( ǀHg2Žg!=V{C3n 9$G`tߟ|"^eHTs?w^$qDʅ@:^3/ ~Ս`&À$!9җW~׬StPw$ p}(WP =q?yI4[wY!Fd^y$,|l8̽!sn8l/H~8y$GADNG281թooGO7sߐ xGK'l#JTW'j58%> {Z_=kΕfuC)~$ˤ {IO?^Fb y*+85! 'ϐwf_IjFq MtS\ C3&[5Yb^ d ң% Ucպ O PgNKF(G?h5,oXK궾3K,TS88^TYYoH1c$97 GK_sAvwY]AI!Pt87z.[rIy wHU=y'#Rœp7Adie79ʦ4*1kh&8MX%K'}c8;/J%'=瑒Tk+Ϊ$K^I+b)etY<@F[V!,| =SrPIl39w  Iu{0#pxȫHYr1w>Ǯ|{d=6-`C@D੺W}[$oN,' ,+Kѵ:3Pǹ?ew\=,䃼6{p{oH`/IV׉]SI>*՜ՙ%'@H) j?qb0" * \X{5 @:$id@9?W ww37FY(۫'EZf֓NlVqR*{)/+ƭ|֔$ 9H.uO㌯pзw<_m"#ymB( ^\M|U- u8 }{Ȝaٯfa01rw!UI]~-5#|υxS_5_APw;|G"3R\%jWaD (@#>?>g6}m ڧ)B?;ECH:|χ=O?߱U㧺3J1S}GN C5CMO=8oxՋKun ׵z)I?ҳ:_/~U8,\Sy=?[kLx9lk(E|ޕHZwk?ߴ he#^BÓ{5͟LoQ{ͮ`L @ &O'SZ1,@'@9w$]CP3kVIҟp#[ZťҬ @^<=_\`@^&wR^^ji+ɺKsѫ36^|0=^wx$p'=~w._?2H*$u]9 =ɋa(~-]恂~BR4?+ Tw=t}:A4ta0"P^UW]#xў\Ao xB.6Is=SZבjV iΆ9gpT碽 (X "NX+"Rc% cWzqo'h+( K,Nqvi+Hϵjd/ڡD􂼃T&TﵝӾ^5PR&H(P|o_>$ /Q;oG{_a pͨ:_u fW6 ϲuQB ɡba3.I0Nj-lfhtew/0I|FQ=L-4Lva`( /Ң`KӋgrLXkχt w`zLgX`!;q٥3+Ʈ#^ _Lwsm@`" a0]pWtߓA6ZP~<=<СS+UֱJ=htlfAˌN۔i HTg{mDU7;B ȩ{'ݣbA{;T{;}y+P?OF]TI=oO9{_<5OFY7[dU{]|vD|1O *W25PDZCPGNN Щh37Pk`޶;6DGE#J/eSO] yWP}X!mῈ6y^ٰ^Ǒ Prǹj}aVfP'᝵:9gN CvLi `޵V )N [sIPG5N`?.CEŤPMMps?@ĄfA$8m _8vVQp;{lIj.g( H9q*:l6qd "$>h˧xKO Hexܲ`s4rI %c|X TuI@U;PdLN_'2gTImOnL9q=Xt@jFԀ;G ;w+&`ߝGC'Fk5}e?/0[oB}&v #M?5ſ_!M`j$(F7? ~ǁ}- ŏٺ6"#}u*=Z-kc ׿3/n}s F EBK^>)SĹW9C^UୡFDW9 ڟء eZ]8VE n-81{Z~D;5q ׸}};eq|UB51,mQpzs Yw.ͯǏH}5/ \e63dؙ*Xf%7Z.m+`46FcvဍO@`:l`a3A'hOfU:xY~؇)8f9rDUjLɒXCL CtT,! hŎz08hJwc^״1D " I!W%%s*1d6H$1@:8 `  .P.Dlggg_(1ϴwJ0͟' fq,8Ƽ~]j6dlbϘ8vt(Pt%^5w-N_ɾ\و٦7Ta#KWJpCYû_bQ+Dd' k{-wOjKqsF5Ru.k]8> Lf?(ZD bq L ʂOF<#17m U` ^Ȃ4\l, SjEw`M̊R~F/U&P}` z_\'NΉ]v9"IDoX+m`T4tڠ`^0ӱ ~cI!dOR76T=9#& oɢ(a%bxSGo](RE!ٺ))cԺ^)l׍y4,!Y E7=a]#c?i|9?{k䍯c~305aJ,#O{!\FNe(* `ݠٟ%$|`h2Tf :A!Y15lkQ Pt>dz Ĵ " I/i Df3(:E9FJ!^L:KrΉ9ϘsdNc)-P]_zJ8pu@kʈ% dkI<- nGHNM :i'S ]hDlRI*jh E)ᇟտ}u-pz ]ϗ?IO<~i|Sg?x^mD~*~ccPT;Tx+AH HyGA~ J"g83蛢20.{î/bZpuCNjhumAftئ/}F>'쭷S"wcγqߍE D;j5(a*X N5Vsx dE7r^PPChL2rm_/IrmZ Z/Nk8fa¤J"b9%jd`cزY76`<>e~ W )>xɷ㯃V)/_w[-PbH1 Ħ(^Llj+OԷFf":As )k$?' O ޟM?@\n},_k%ܟϵ;WL *Ftޮm2''_J%Wv_2}pܪ 6^L!t+~TLkxDI)HZ Z8'pNZPpH"ې odP,N];qVmX-h7sǛN ٺ}ǁ _nZ2u+@&^&>z4 PLGrY( \);SP:m`gA}e(+\,RAPP,&h(rM,bmHg ?#1Wwή~Ɗ'~!pfZ9w}e ]vT"3b2"3Uw#G,%\bl;ZGд/𕕜.[#XDap8%Ic*DCƯyp܊7='!7S-} %8y3~om k`u?3G??^r(jf1_fe |xfǶ1fss ؕJ0ilVDsD8c l}+[,&:/E:cblw _cGmۖ$]t?H_+;C3_dhw:Ƚ Ve[f」-5I]ݺiM['n(KS!piP^^)r`xbrL!:[ HDJ zf{qH L cR(7BN7xS(XȋO4cEv]- ^ç^?xo~TWm!;0v m\ <V4VPԋT|['N l.ٲm;Cdk 0κ: $ԓ+lC)  02|„Tݯ7J[q2S^b;G1H㟮-iM$>5k:EGju$/!EVTǃWsm\H0$ ͸`w6̔< ;#J 6xQLҴ"p\vKuG2L;/R<趺:ެs4R$Yu`4 ~Lrj 'v /0:~$eIq1={W/θ۷xP0ϧt/#Dg|0^k/#| ^]}g'ܜ0( r Nb63?-M.m5B o6ObiO)c#<xtHswASZ"" "n O?“nNضf2FYM[1y~` z7f# Éeϩ 6n@v IDATpx1ߠ4]H;2V|<jna]V>[Snۼ1Jj%^`q_K>zD;`G`Ǫ`(qQ+DiJ+fNіs` @ZPGblaZ8]'l/qƪ6CcCֳ:ܐ9Y0N`tt!+n q6V!鄧O(pssGgy}7=@x 't(̔(IC`5+rsd aT@t $pmTXzkJA ݯ 6]mʉç³޼ٱ8/m'=zOn[<}r>zǏo no7nnp6cNKR{h+BK6r.>gdHk[weKDoseӽ3t5rG ?)(%RjfF"}Pr٢luYW^wBҶJ/t̍!yؤBW[n&u Og.Mo63l;4rujk̤ eX\!Q NXiՂwd7*Fz: <|s{'7k+</_g{Уoiͣ O'On-<9#>N÷+18=HB!|`JDEw\Vdis$bQjVl(%٧+@J  Q:~xIs1%4kܓ"pC\aaf6mQ!sfRC#n n}zƍeY_ݞ2OQYK:!Дl(^0=3}bN6bO><=ѭa٪񆛛 7N c`ia^Vߛ.|R5E=jB6mteJ4SsBl(@lYl',6 0ВdY*f9) C9JYWAS˜IZk(?ut/Yea0 軆qo"8RC;1C*-m"ch/.3(jA(l=5Ls4-k2 ˆJl79?L"%*ڞΥ-쵎6oj/dlct"f1p6nxwOvwg}ƤA86ܞN8N8n8nm03͋ċ8(ׯ9Q#F$C\G!!gR` yccQjǘ7Ž^~,)QN_^")ǻq'Q1p̱^oC)0|^hy~/h0) 5ʺRƾ!u;gSZǃV4 H@^ĉdx߷kjJH'] J+sBq3QPkQעUtvXZ]Bԩ<ƁYyױM($aF-7Ցvo\/=O%-nӎ-o6Pژ䠑3ѱNiSh*eшwrG&@LȌWj`"UĶeXp sVNX]r@c-ͽ-MNDȸA58֚k9/֧]Ӏg49msRn$=z^ S2?03cU*aRZTQ I3.SHn[ X,H2S:.uhb4Դ$/K/2i89nh_Qc{ڨT+nnD0▗"DQ,*m6{D߀Nt"Pku$j[Mr/iA٥,mF ;:WFO /u+v2\3Y(О|($u&C^b׭(2.^rlhuҋ $D8 |xAcIuW߶(L1%;*UqY{~D\@Lg]g=KeN^&Dݡ(\ [ohnr.ڗh7a VC[∜8~P3MqVb(A4=xiFsP)QI~_F4qyY^ْ;9t8x88/'ߦOpcJSgS3O]dԈh6p;dDU`YS(5B}YgȝYMM /+&AJ'dy|~oZhg-Ӭ_$pJə7Wt+|h*a[˪FKOc7Ed&}~s:M2= ^Ogrm8C !&r&nlȻ:3vfi~WSi4͐3?̩g2@ -Drzp^ w!`)`nV(L6ᖈrR86h#41_pxQc!r mOԚSWb%nLn` BE+M*xS@ёtV0Jem yE*NK!ʋSsY6>h+ͫ0"AH25:|Ѿ{^EEG3+9MwN@ q%9nsb)DNT*J( z0ŚO-= S _y4]սaTx `m[F.XaT ٫`UL\0,MгD JB}-aFUv٠bs.W~bRY]Ai Mg+gZ:| b6+aIۏ4aX$B. xmŖԔ mTZW.xP NLXXIe;y"8= կRE5&},7yZ`!Ip% ́)m4*m%xj#Iqsa }&3 t-:[ϴc4ޥPےd5k70\xu>T2fnA/^dD ǵ]+(#%k@7>p.IbӒdR}?mQB[R5+:9<=w9SY FvG1mW^KRvtӢjwfY%H^#R[N<\rH7OI0tw׮qpD XHy-x,Wb'N}'^:Vp8xx+L`&Z&F0Dq&WAk/#ܥ99N=0n5}psmtw8^6G0EG{k<ѥOxp$}!',e("vܥ% _`P4%ie WD1(5BDыYhTx.?<.7 צS{ɸG]T?kq̆#ڐ` 3'򘭲-'gӪ/" 86^fXI@9,#S Sދbqpu6|7 n7.hSj uIB+PBbA8٬М(I>,$ =m7X2-SE MJWWڀoZb&RLR@o\)m hM;fgUkeDx4LK ke.Ѧhyж+lT#b~`486PƠgaR)3m`&5ceK2zxrLqqt+-o)Fb64kH w.ad*%@,3#7JNBL 9 1yV-}_Y+SbTn_ETN4 $4R"5cv56HZٳYNuz _rXۜ 6o廿Kvn.L(Ki$XqMШQe4,Eӈ"G&]9LuGCۧi mS\שk5'ZmLatY14?^wZBm %1#+7 *? s$"!)'[3 A0#Otbt3U/+Ԇ/S]5}I$S/r]Mܞ7tZ \(QxudD*^gçZcEyQ!75M`蚎vƄ]&ާ`{JgjHZ?9k1\3l$eNRAI}iKۼWbe[e4TbTl#l(:+-ʤ"r0yUd%$W8!)| v!~p qiat(u-p#ğ):V=AniÊ0͓}nB\ToyuF&i \x-Bݛy#XRaauHm[Sgxv:b*4GʺeBo֢aQ^}bSXvϩGJYxvzjXp f6r!F(dCKlhTs Ni*Y`'Lar^Lv!(+"ʦ1hJڰ5P #?;)%uHSm@Ճ_ʽ!j.@(紨IfFb ,%nb2U@bռ<#1m5BZ+IԋteKs}ےj-% ے]F^.ޠWE]Bdjs4v-f Z]ї!!VO顪\]]0qwQ+z&D` GY:1鄩'}-Cvbopy)7 6lGn: 2#gZ: FX;لlZ"ъӀMrbA*KJf$e(U_k@dCb+ʼn0:h-C["|[4Ee +Õsp\#F.~ pwg,F=W:H3@͂Qjlx3Wĝ ]A8BimG0yFgK#fYDA A5G4.FFO)TIpgo:mvwzBT AD \UjcZ2W(f](CHǯ:Ry[isVk< S8]Zp3]Az`u.rmt";@kN2?(Azurh  +V`-^t RTW)E0i{y%7J@8՚C/\O0^xP\m[r:6'e2Ӱe%}\cĠu,Vz u1Ճg7%)AkLv0t7*$J6cF[xv'`+3Zwg#Jqv_vwAO)$~_g%lBZPRc+=Ƕpv*3ʼn{LkZȑ NKlum$Yz Z,HdETlá=ٳ,KJDK˪*`yܠ 8jo#l(mUj!֖Ttm^ psl6+YY< KQ00#pwtXci#K!>Pn:-PD,!֪̊uKmz n;k1QZ+woKph$msYՆʇ`d6)qU{k$uߍTpn8|UNmǼN`.: -\b֒z w^t= x/v`*;*t)_$"ֽ3-U0h"X]/[y4V@,[DșuiloO_C:ߪ{}GeN>3zm{K.a{BN΄Ǯ>tn ^cf,FkwۍFlZH=MPiN4fV&E" 6gdsqIJ"\f!.}UyX+3Cà+ՇѺ=֦V9 t F˓i]`5䐵 FU{jrjޖWudU'5*r&3ft2EZO%ƈ*&߳.ܺ ;wf $ڥ̱BH>8āV%/Xͦ:2ֶ*J|  T*SW6 Irt% I4K0M/Yi4 sf+Lɘ9/I/uK1`yTgk( %0=b>+8y5{w__f\ճVs~L˩LoXhCHNj D$k{<7kHH(M}+bR\^ 0DixR-2v0]A3H`L'>>2kq9DloM}$@ŸO10a S-< aCz"B[SgɁ[3Zꓫ `7bD QMXsCH#lzɴՠ =z+?s3 [!wBK)ɂ|q5b!((Y-Z%L#?5"S8ҟVVvzjmQ]XԼX(5k]1Z,'qRDt0iEf0ݼgC)ڹ#~a! kEHܰVy^S&Fsvn*Y"Wf 'N3lm3`FjSjosP%R] l +SSiC'P8-mCmo}RF/;k\?qi49- QwM:Y^PW)N8]GMÞk|a9JN )JGTt2jܧgA0| >AGhFOy(=i(s ?i4X֑]˞E[:IJcgصGG}*$=dpY:)IbEےv~;668TH1ӣ:+ _ej;JJ\s;v@[_{y$}1GtJeBW5g+]o a\պ4S`Q _/pk ^WP*-\̻eճHY,VNJl=^pb`d1 V"Zb;N e*]t m6cQXطh 5ϫj01=xEKTMOI( q|Jh:ծ?O%HWԢ MQ&9ኂ\MS3z@/_td‰ UPsOWz|u?I=\%ݏJ0mm M5PiE)2]wX5Q5zxK/a$r5|T@Xp'mnD'cֺ!N a[RT :YYdgfς_nUZ`yFݯe$CBX4ذq?Ysf4[̊0th4NTM ߨ~M~#lI #q Y`jqFl@#sBը5_Gb)j-Rg gլA J3ks<5%Es фQ)ۋ26dAT#"\ - ٌ{50|;Ch+F˨QM 1J'9jg^Wz+s4 |"2Pđ!S9\՚xzYjpc8i"ލ8s,銽[u [AuZv}%k?Rrx L/Тa,"|9٬ڮHczδ3GK=w98`/z$t RnKǰ|;^iq1?N5alA:+vncFR|zDƍft5 (EP\s4niX 36S=<7ɘS [I5do%KLU|*U/JtK/ "",Hfb1cC䨦eH]9 i埊˴v&ɮ b&:ON ./!sᕆOH:[EΝ>-A{>sh-Q Eb2ӖOO9 &73D(2v˫`6͐ܣe‹$.!PcB$Un3t{aԨ=p4&JMcR.9Xpط;aG)u؜m-ncʔ6i8H9M6$=7mÁcō>[1m39/TA^OFuo5=yWt*V.Tg^ 8MЋvOvjr^ Ej3+U훭pbnQHOE0F`OIs"*¼{݈7=Dl;yLl1YZ=I| 8 ^Qx)0</Ӗ2X6cۼΥ6D?Rl,ܮüej[W`Y e* >]up=#uRZ,ҩa447wE1$O mp[qV0iNiO4_< m /\5U0RO.V%so3 M3Ŕ¨8l7 9g.0d1P gEH% t[sQM6evlH1ExEb4 .`ʰ^B{Xk:땯׽*3贈kHbM-m}Ig8[hLG{H-e_WJg7Rp; &/97,E?32[q.NEHXV2Z!׿#lZ2Pl 0n6Tt9s},jv;7vX}lQml'i4b,ީF?i$mSU >&'hZB ;^@]1C)nܗ.s]vnnZET>Sx۶RkZ W\nRaEڄy)OḴ NZXÖeIh1eOtam//h92ړ|[.Z[mujfŸ'r]Ѷl 5r쓔>M%H!XsԎ QFm^,Zz Dc/$!e~I1x6<\ MIg2Z(u":an[`Pӡ['Y1)*) L5]EkCzQd&rijZ&x,,fi 5]ǬC˗`R=tӉAՅ$ef_d"XC&M 6qL34swtST˘>w}隓ڨ`@=p$ 3$[NjaBƻc^䶗TR4}q! 4uZJ)=0zXHwە[VmT6@Q\ NF zw(&ѹaPA e>4y;z;e E[bzޣKG۴5萞MKT!3UC JS*͝5[3]Rp2Qi/DVjBT/d >0*"(S"6geGCgÇFbTN]ee"bCDgjt+0o$@d-]̞WO `?7lXs$l2\Gsu'uVl[Y _2/) =NC!-JCӭAînbG'nZ[1RP"0_EŸe &)gݲ7zgQVp*n o~c1ʳs-{. by"4٩ ÏJ9{s֕G{ 㹝n٩4itJ<a+c`r˚*wp nA)kK#8Vk1J,+u6g )H$Ȁmejtk'<c!25TB ;TMDg0ܢDerc<,'yZgDo:kU 3Ha甌uw*.+ NlPȹ£6o.DsA$!nmɈf;0قjD2ܶŒF2>My!G?XCzdAI=T{"d70k84J?7_RՃYH3O U^٬tv% \S.2Ag6vX3l/@{oDz6ӫ6b)te, dfիa4J,O7y_-Sǐ)U\EgXi 癛A:N#EmNXl&Zg-Hv] rmٻqUe5Cv{7L^3(q]X"P;Wo_\%;̜E aѥْlm<(tQXo_>h^7Cf:iMy20Wt=*ՍOIg _܌$[ 6|/+Eny(yuZUJlJK%"RUEO/Zfմ7?]NW-XmKzme1Nn# 83U]k_;r@3l/|ӨkD˷gؼ@.J㻨H^YR59vn (yS$oN6pI6„{a6If^NOx)lLl v w0E Ve7ɥfU8g 9X@4rw;ٌy\'P`D<!%irP*ؽ{=+,FBͬVys1b5Dmw;Oj] tk`H(TiQ=zŷok w$?fOil  :HAx r%xLm?l, r7of11̔ :o2$]{GdB37)I-eSjI1][dq:Q|StӘL Ȓ"{*SYl^D{sM9[$r}uO$ o#ey&vd7F O?aW|Vcsy0#NIM>}JF]bzvDb+F3IBNIRQ m 7fd'>փ.a'ZxR+Xo/Qjeoriabxy iF z{/,\vuR^5$i󔞷 R_ƁULdsI B-`63ޔv`AmrK=0:jtks^@gЬd땯Eܾ\~q8&9eNjn(Q2- xfx#Hڍᩥ=͐rR@Lj3Sv:U 7b#2&G穲DZčMreEźNQeK]TV.chBk mɸm8~ ib5cE$_'77{/g x޼ 7QjdҏLZm䔶]Ľp;8rBʿ5Y;24@?:uS%PHW=ani^khHWNv4^V@j+6%ޒ4j.2׈su kLy "^0]@f~w;Y)]ޠf"c;Cs(o4mJ$`!7cѹc :|3C!O삈:lBx9exR;`4j v~iaHL"ś+i?m(/ɸH1J3oH+DЍ31 Lpr+˹8^Tze [HEMqFB6$ ϲy)`G$bP,Fܜ(a|LjXCFL )u}0ٶ )MأI!<Ŭ4$"1^s o^!ZƩi%`صP(:@jmjhdTٳGc7}5zdoLbP h# &#^(NY _܁ASGi8H*WDu e@ӛ[; ͢%š%%<% v"sDr4 P;wqkt0,/MƓple`Dt _Z!Q7ar RY_OLÄ*mׯ}/P4].i73S:uvtaEFۃ;t9 3Gzf?ŖLQ# qފE\հ)`Vʂ:~'aQu,["kTorU>y[#7#;=,ICH|)ɓafH,Ui*j9s!Ztc6"9Dr;Be*G&aK؆НR/wznj_Z+}q$[ Fń͏5B%4l—ivT:s׵w38^Ȋxz8S+Ok|6'9ٯC+bwo:zVwN\i>EeyO8\Jȍl%X&"%WjIa U0, Jkj Y)9ROg5URDLfDJlfSfJJ=L8%+F/P֎TajZelpX׈a)цsΥɉC3,A|zkH+Պ^-典"/Z}\A;0O7ƒ `$FMzY P)Hl[nEiK\#k0F?Il:/!ǽ;њR~u=l9X8 ;SNs.z,\o?mwN"8R--fqs+;J?hIm|HkFOkbњ8R7_!r ͊ظ)7 &'tE+m[1/ܢG܌⮎WD ]1Z~O:?[T=Z3C|6n꺈ٹ vEy d7} ],"U}:6G%4δowKM؞;EgmFZ")I8+& 6%['i.%IUoo.Dꯊ5h=-Nᦉ]bá8zQlcq`cD'pܔH ͪ0142SAȂiAJ*_ִ 8Uim&w6aq]W?4F\*lފwlk/^0 %G oJS׿ Vֆ<ᆘ 3NhI- 6=H)["q0Oo30Ȉd3zlt~*ffn.\>.ѕL ݝ3: B$'Xi-@k$y;cDFNJZ 6jrV dO)`PX޷E K'{53UL*;y+=6S|"_5M .~MxY4/?BKCpDw{kŽꄎ/&͢vGdCł,4YlJxn=Cw9B!Cxr5=wQ{Eì)#'h{1DXO;i[.qH.#Oϔ`YY(u_aVzx$+9n)ԭo k'an'$:s;I zzڶw h[[mVoMs2'+Ek ƳغJKX ߢ\ >r\oa.u Ӟq]74oqKȀڐ8nrk7wv_֘ÙfQZ8$%5(9#c,ZI4[[q8iUzUֳp] B6ͅ$J$KaZ>I'O(]ɱ;>-/t 0m.WuUM+\ؘݑKײ/eĔƷku?iTpq$#iYKI Ej4p،sB3LY5z+:^*uX$]D|+oq ;dKz+q&W-$f'1p2{!]֠ܤ:r|bk?uh_ @ i-lYRKٌЙ' 5{\Tbjc kI?P,97j wP>iN 07V2?ܬ^ Z=lBͧðs "a(^xM<\Ջ >)3K=ɋmM#>iX8/Q9geP$dxI6T}~&'ߢ_ P|2|w ĭjs_?:˱FAHԱv˔icdgQ"EN̹o Hy+!ev+̐丨`Dn`r6#$ퟱ&)GF|\JF}bh͈=ʂb8W]f^`_Rl,_S¥)hhrTqw dqVVeB7{|a٪zpC˖Nz^,.rigNRs^syr{vqO&fW 7uͥρ{e彞b:res+2U}FBm`} & c3.S؉|JuyD$.g(cg֪mbMWڀmO#Y℄ #z<(6vv2Dk͉+3;qT\붹wKt/GF0Xz:$KӶEl؆[:FI!ݶ w2|x=gȼ/korϺfZI*iNN;+K~V76. BeH'R "Yp;fXW Rr.r!nd'$t9kef3#T$}u$ M<8(7\kaFJ& )݈v&zu񘙾v:SWXy- 4^muU<ҰG}D'Z'w8ZV:|F+#(jA%TSp__!@&-:3+>i冻$|;Cjk7'"ZP9/y3XY V[9똑WUm) nI=ev f'Ǒy=Q6٣cXqzRy{9Zm<-odz_޷bq:HV$-@$/3p@V>Bȋф/$1]9q= Gc6}4򂗖I,,o&Bu 6FاOӢL _WX\l~ovR*_>~=iN7φUiWPzhgҹIqٌQvq|=׬ق)U0vc痌M*LWT.RqpRE;}93~!6E8v7t8g W>2X_PPV j%br%D[5sdә4""Ĉb߮%+I \4,)*ܒQ"ba=Q6mFr59txMVxݍ@ 8j IDAT1?cH7-{|!.1eq:DK?kQF#PJE+*yPn`^~B4@F-{NEiAR:KK7>B-W=pi3ܒJuO~9H>4VzM-]b*O{ZqNēWSi3AI-׾̛|_l1E\l{jѩr'M)0`F7ڷ+$C#1E|69(ʹϰ51]7x8ڀ,Vo>'+/m2mJMHwo>̦/LQ [PXD/y* 8o@ߒ<$aT ZsA, zqT!8' sȵ'k'1ŐCv 63i)8\%G.g(nSV" jA Ө[/(yޚbOdN,+QQ!s;EJ3zU6W@mI]q\Ȣ>y(CJWi ,$V?2,/ɘ Wƫ`29Kki 5P1z-jR1 ZSSؤҚ,::`y49ZAJ6ªFK==m LiAKG"عE0ݛcV9IPu4.27mKs7Qפ ПgtPPDAwӭx0Î $ļX|Ϙ/8Qewc Y,ߎH,M=ev)z@d6C9U&ITס0EԧMM;_jK=`ʔԯ4--Q$:i3U e9‚2wC38yJyH%dX;8wzIܳ4&"!sZ70L\`_Ǟ;1.\0.uy ,GʩtTϺpvYj`yGz(<ݧYuo[7vYu"fZTn3ؙf#tQjUM۶^@9#ÚisY\;VQRY'gJN~AI~,lN~w0sN`֤XdAEfynQ^\%$}smyvM㜙I)2OJfk=>w\IĻHN&)+#<~?TxkǑMxx|q<@Ԛ:U|&tq`Ea-`iA-h|$I':Yւ9Rcqghy1A3tk?!kU,Yo<;l<5zHa[C- ^pN4k=9BalB KE ^l"^By{ VJMcF"ؕ fɦ 1*hekMs)hZ$Ii?ÙMH 5/-QnZr!eU:.\1~e.aӿ%: myͧN]\ÅʏȌ//v"ԑ O1ZH F(dK%\m/wVTidXmG͹@e>jyRqS`Qٵլ(ͻuwDK8B|A,MnNIyq A-o8u<|| E␁~3sGs7!/!5d)^2J+qt47"׵‹_Tpbxl>+G!OLѡ<Xm͆‹䞖ͷrfWeSztui.nv a"/wn}4­|IJSYby_n[+<ĸ(ͅc ;\?<>/b p]5Ĭ3Ik )bLL&AJc,4ř,NnWQ@u=nË %.U5g'-\K(ce5`mЬє@ݦeUZ3ؓR u7ѐ)FqLpREm(jCv[&SYoxW[SxZ̹S0Lkmp9\f?V9 KR4+Ӻ&DKٽ :e m0oJLOX.^N5 a:u?;?{E#V\x|oW<kPgn;腥dHu(g41p/jwE!Jl?ݞb-&7-2ԘBbū5͛=N5-TI N!L' SqlX&"Raga~@/&٧Mrb=n6} v^׼{y|n-d,PZaR{,[)F{X[;t_S9CT) b I3ՙfswA5wuv; eD0_Aʺ&6pKGJR[%V*./_yHaW@M'wMQuY-yr扡i($:I. # /cL#z@6/D䚞_{.fcb`%>pkjۅ =x=!j٭s=AukT1Ù-WEY_. ͋TB? p:d܉ЦNGVz'qJrԴ U8ސ.xxx P~o<$5'+S:ф|jު4NY9/7j2M2Zl]o{ |?VAW(o}s9Q{7! `z|gȓ7Q/-<;c%trH;DNWe`Iݰ*5ByvHv\b1W2vuSI!4?¾]n]cq*"Q@ImyJ7A_ _bnmLw2y\aPRilW$Ӿ7$qB1_h~ 0瓳9a+³Sr<Ʀ c^ob8 *)–}B]=l'%3Gl['{z =A>79@Sx)u0;RWo݅q8lw̰qyIhm/k(rѽ|XRrZ7b!MH)ZSZS8 Nj6@ X3h+%ѺҾ})+,;(z +EFۜd)=ٵg'mo|L%gq`nciuiȑ$ؠ$WuT=Ż`8~k )fߒiwWI :4g #~)n_7-ߑ ܾgIU|kry\>}O*<7IT4'\De6 lt8lamĞt[B8D:/:ͬu#}B!2Ȇ/6 =ӵ-\`gf2(+SZ« 8lw"U ݢ5MR”S7SaIu]j-˳d]unncэ @8f[  #Bv L8 ~gk "Yn,=#V l^ËL\ވ\p(0 ߭vGH;q4(mgIt֊OsRHxfjv\ kZ1/̝C();;/ڽ/C<ҶKh÷2 x wHhA!j{,V39:#.)hڼ @!"I+[eoԼסc[Bu{EX7䶖Jo~-6l5aTYpn:5m:g]П (??Og8n~xG[7 Lh5$iIRwь;4vQDmʜ:uRI⓺,mQSEEй{c Л.WzV(#3ľEmT;÷kҡH'8+JSzAtz:Yv'3.abM{yq4{*2r=y=EsƼ1e(Ma?Dm[[m_0/<'=c[ϮFDjT8Z4»w1>i(tLy?u` F-k Yy$Z)ݵRD-̪rd{=BjtaȵIWE|Xh`޶SSul4- t>[x4߽זxL߂Sipgp <'›BC{vXt+1c<= 3(>NkMW Y`b9:eV4yuLpWL?<2>8 2!:¬xY-0|H71wOL!0||ŗ/Jwf̉SI8T 3Vo,)٫ZYhlPԵ4$^kROb`= 6IE N. -6D G&MCeYԒl{gxi)[ȸbvƊxDu9 8gelXn 3)'qm>WNL[Zؒg2Ns'˓,M-ƒXic@e< ވJIXLU4vՁfP)~76cFƷVDY+U_uVX[nsRԧ,ll9~2b%RkljۛCL4QB-IE+|V<:PEȈ|݀?Ȼ38zVocTY^x)2 VuU:员T!P7DVrئ0lm%XB1Av](ʙn. nԫÃwDg<. I ĢX1K\&|}: x&x*X~XZP=b7X,T*@Dka({+ڕ .<\ 2.?p5J8-\p[[Pc#6PA؋#ti"M.btnҩI Qzv B@qtJTLvP(Zfd#VWvD%t$5Ba2.SNu=kYk{HPeT CGt!c\0. f<,LXCDZpſHIϏO  _ A6`y yRJ)@I VB_Jx`{ٔ@Z)7RB ju`JGz jM ӓo3'>/]J $ػB29gyQw -z^i_wU ѐ|*CuW:ԡqt1VW%4&< ITV\=kVqy=޽'\&f_6IJf8 lZ.q tVk|1 Zqx8mP:Fl&W"!v mDCH\^{GV5F-֚$e4ZѬ&=,7˶CR_?}>:[5Kl*9HU>}iD[dדO~4P#ʞ>6}e[Mx vs\a^uj$Nmy*S0m,Dt=%}QnsluۭG+UN '5mŸ&˨']DV֩ݜBn*5Gtݠ/u5r#=V'g'CPe`+Ȗg$9h_@t&r*kP~*/vgr> fd\[;!0|UڰxcD߻"Zezl1wqնZ!nLo*mFt\8 *B`ĄGr MIDAT?ӯ-?^H|x)\b.c.O)jg)]&J$ľR3kk^CZ=?=N@)K¾ڐ!ާs6hl#u9ƕ[{s2Z!;="l]z疮Nɉ{-n# N#{~dd[%db`>}TrQyBHYQ1%~oQR[MCu811~ p%ݵaо 嵻+FG߼;U A]N8Mзo| /mD8O<8eD;/`:?hʛA\Qg۱Neރ{-"rs.3-"7)Pn:M{|+S a?i*#|1OIbeBS l s1b~[NV՛m@)B){J;!϶m31^~'^O;HY^eAm<9w'wos|#6l~>3O7nU^CmNJ[&w>#Z045ǸǮ6`bi3;uS \|3n7wV=uԹ9I7]_-^9#p98ķQEvY F_\s_W!\}$6~>;5{൯? LIENDB`kraft-1.1/styles/pics/sticky_note.png000066400000000000000000000263671450127457600200350ustar00rootroot00000000000000PNG  IHDR/E!bKGD pHYs  tIME 0xiTXtCommentCreated with GIMPd.e IDATx}yeWY;{PS*y"1B2 Q\Цmn h+6.1`;D"KEW TU*U7ws?>ýJ kzN{M"qUxj@Sf|LBb|cQ{^`F`_ysк h\dKupOps5bFG]nx.Р-<`^5^' 3 ?,8; 'G׀x.<%;"b{pi>{! h=8?`n?pW |{;~0vvęұǿ}߯ ܼOt_bo[a?p ;x7Aݿ$ 7n~T'/|4<||7^|˵xۻz'ᝑu+?/3 oCԋoo8pomxow':N@"?>td1ț!nR >. L@ r v*n5M>v .`ؙwapr1j eCGҗb_c/e7!{G=Z#{w`8Gk+ c'wܚfVkǮ'Kw/pذ v4,im0s[JZg kH=]_E2t9͇=.؍ sO?X{D~ 7,| HY_ȭrsnƋ~Un[o~}ⷿpo?G{ׇÛ-0_|g=g\+G>i\fthiڎ`˺FߙsFDH۲9$)hYdMİ1r-˹aas2l sh?ie*yp~,U"KvFj6 RrJ ڪa+S RîdF:K 9Y U8ZцRR %DD,kPА"b@߇4x$x&D.wV`2=u4U\w͓+.@2 =_5x {Zw|'^kƓ}S7~?7sOmzf .o4^䋭AwllFn4WY&60F7Lmê͝i5ưѝKsMq.wvȇ6KQ'$,ܙsgI1RM& ˓Vj]é1Jդ\r' Ucu̝Ebֺ4W3 QQ5jM9ډU-8%iL  P(#ǩ0 &{<އL;.. (B[- W{x +,37욉5{o~]-wb0=.91V\Y7 [c!΁f^fPI) j,L!i $("ZkBzmK}[`p^_=):-5yssuq>)~ǿSb8VuZ75Dn8>6;\#gz0rFnxVɴavμ_Hf6hKTfgR48c8((j BԿgU_'˦G89ī_<LPJ&aBIN'Ϫ };>sHIrQBۉw|bsFMGbp8'? W`:X6'{I?jyKiTٽh~lޏ@kE/Ns6o}@#}Pyחs _}tI -rg;ե]M RFn N?~<۳6%ӈ/*Q3ג;>rxK%BLK DсH;M2; 4*آ cF=?'\z=sgZ?}HlFr9|omC$eD:$E"KS]Gh{m|6,8>iqj:hVo#1h锨jCD\" +:7rvB`sVD[F_H5{< y3ۧ)hXIRk[HD%D99_5F|{EA+)!99ܒbb@ -Xiv©qlx@lhC%k3<L*۫k\"o94с "xoJ]'Glf0-#v^.q[ĶkQek>- ^.b}>ƿ!dTEfN: |4vhOSdq4"$k_v㒢dHQ9%9eSę-Q$IQ |Bx™M_tΒW@A{=o ^[ V' awxtpԑV 9k!h3M}6h v`}pn 4ՙC|"'y]X3K"D _@Sqk|[;`v}Ոv~?EEfaK :$֙)جDyr~{+Xa|Ja=v_N$pn` emę ܹs ~xT=@1xb d:gto @Ufa Z;7R$O nbtv|pb#kNsWxj9J?q;4 Rю#Ery͋U NV|)G> ]ß 7<Mr"ҧ\ d1Js`.'i*;w.Ca~ r&60v^FzM/aMku9.L鵣]}Ԏ𿩓7w\{^`u9Ω?0-^sE|?>3=m.ד͈۶8(,< D^d?pqX#&C= #Ab\'L' }x3 uH[rhַܰ.C IqHnkZ; ;<%9ߛ{28\CO}}[qV)Y66+Z]Ͱ+aZ冽/g > &y@]ز2Ho@6FQ{πNFn}p0YT>k|r-]Ro^y=k nBŖU|{~\=+|#kF!0t 2A0#/4m""ۃrh>uv0S:f>raDrϐoZhn|޷mA𰫎lΘG.+'r>~B8?}2|j];np8-6K<1lX{jKF&:m\=xB{g_eDWכ`!=6{ G#ێ{S K -"N"D}Z EK/7^ ײ8~LkIc蓐W݄b3{FA%@woSpPĒlgC6H[KtZރs>p#',bO\-2Y\l':Q|qe}V:\rkqtkzD┚yV6p$Xv NؖLav'bG8/g_^ֳڤ\܄˰߉?0:FXnzؽwoYq*ɰuuB$cc^ VpUκ#t92F]5ڿ<$Agqh4wccy?FeSm~5W;|tV2J==<WsPi[إfOfg%]w-vg/,.d.Q*l&hjN]]6@\9O`0C5b@prұ T’_W  bn/z9N=JG&S[cBM#)$!Qό%Eqs0z$\w;*&MZ . sKW{rG<&}~4xm\TU 2DlY:f4/f=dSȆмkQ=0&<.t\h4ˆ]Ñ.a%rM$ "f螜ƤhC{t iB4о^8j~)Ui$4N~Hs87ipQB#Yl47rNB4}},G=""bv|ATA?lApU,+q1YDlt4gl'?SFѫmBto<"b1t6SE!O閩$\wJ)JJ 9ܸf$&M>?5'ŶQGD"rH4IxUma2M,/13h&YJʇw[*Z& ]FDDH:nWlCF(*MLEI Z&IL+m?NpEB&F#"fV*3⋮7=Ɋh GD,RlXI;-|p/ X䱅.>-li2"bLa7C_~~ rTZ`1shQdosE]}H5Yo}YTZ{XI.z#B\ JH(&3ab0/oCb*PBX,GGD($5=\-Ozkಔ; ]4Q{GD̤4l..9TMbE\5V|Q ]b[9s Tɇb5YlƈSs pmj5~2%U4ՋN3h;Z6s3S[QeCMؾ(R1[> M2U3bwVW| AH1]1C"5(f!>5]{V{-n2PUrm1Kp4Mڳ0݌I.ŠUe@bjDLŠr4lrhWe1}[a?hc W(E1s6:rF۳i̛ b$Te+]RVy!esYA2P|GD2gc[nAjK-7V1""b|pi6rJ;3 z-V=jYRvs$X>|tSy@)춈_~p|({5Ƙj%&c.zDlB_pLp{\IP)E|ؘ"5:wU3o/8f,FDDY1Ʊ^.(eO $&DD̤n6ngwڊAusBWP>xDLjp8wF1𒡪wb?DDD̖|n{vL'CcX6['8؞wE9| U#"fưuleWH[×{G9@M#];Y_=9o[T7=ckFD̜dKi \vu[\֋mP-K::)&̤VE$i5=x|F)P4ƀU7l d>s`m}e6gܨ[yDlɱ4eR5dhSm!9\iwwTӅSfL Ӽsc="b&}p]G.YM!{v x=mB)6dʢ*!DM T{,fy"'? Ȋ)2(Dը#"fRgQixrym ?\-w&#A3;"bF);:# v⽿vfa3٪3c R埜r$ֺ ,$xDČ83\oO~ZYݿVD 1{>fJM%J+Ld2D="bn~i qp?2OkkdSDĬ*6. |n3 Pþ"h30[O0 z $&K#"f͹9Wo^G!1Fш51ȓApQ$7<ܬ KHh쎈EzS0wqѹo|;Ա('7)"40ԣ1>xYiX\ʇx4S-K$U1$Wę7>癛 ^Y_mRJ "bF 1n$ 6S NHU+VP!""bаn~;G7\UypAXYI. ⣍1{ yN- +G9ȖcB2< }pT3Fo 59e|r<۬˜ڮ&"RB#"f.P l&xHs)ׂ%Tz&ygecCX&]Mt*" G 쎈Y#=Sy{vp4]P0CAyD̢mEI,Z n O8}5s#鴤c>2Jة^1k&:&U;DgUeE2 }jDDĬ[Quqq>y3~XDXmĆQ\O}[vUE}0OKLrY]2?OTl"Kp3`͇*N~,W3!F7=fuyoLpkl጗I1>xDL6omfK(*PZ4 OIDATTXƒMĥy6d4޷ħy-NSE|SUT9{&[<*O} y 8?$]Wu 'oB@gk=Rǟn@Þz@z9&Oٖ'on}a\4D ~R`40 @(HUВp4HhhHhHw0Z`0Dү_q[7܊ FkhHuQ@u&ydb2Ș [jD fNכ$$k~_e!>H k&Gš[gME_Ô;RZ;ߛ[CJbpKq'<~+Mqoi{-j3R_ "$ HRjTR\P| g(*UP)އvP2\:M0$+c-<9õ˫5 v2P) B <*FQH*EaFUP<DS*l/|x{w܁'48t$)j)I6_HϢ IG A`2rLXon`NC^{ NubDu("# ?0I4}wz!^쥬aPt(waudDp4~N4E\ho\vcP"2q5~LH& RQ-`^L1qFT& re"+JvJ5vVRn]xz[o!nșE=?R 䣲׫{6G bD&"W HD V[\֗}76k O 0d :x1RZR9RK5' H*!0’t"jTVZGCDƺMPE{J⥧!2g־dLޚ`'EAP2Cz"` }C(31ƑÑ6㓾gT }"T@ RH;ƅ:rvoq#` 8]Ndڰ|SºFv" Ԝ˪>JaN5fzRNl}H-[ Ax{x1fJJubdjnZTlP!;юc#h2hfψ9pr*D,f'C&RΨ~s`lƘh-ͤLi/U )h)\ Cx$@@IbUsCxᓀ|j5 9>uVH9&4h*=ͪ<>(B/I-ae-SY}Dotmd2Y5\h_PjKPS 1qRos| 69DBZ~V-ڵY8zxjCN6=Jn:W܍ 1[|^VpX\aOFԷ ;.MOy׸i<ʓAM:+ G$su%v.pLIrCX`f0G:  kvH!ʆT8JTl5k(yk,C*9js):\5Tb\:+cL"T}&"K_ jEK֏ԨR6I=,mV|Lu|yݥI\;N\1s du'I SbT] iւM9Ab$J(OurN)$XaYM *`'U+֕̄Ԧ1|:QIb8'"M@lHEN [Лnh.+h+ʸ5DuŽͳTؠ)Aq_AX͝v_I#\B Mt$Awc&R/dU1,Uy Ԥ.\ǫYV1b(T 1˷ih>j}`t"i56kIq:/@XmDZF !@!uz IbG6A`7S$˝H.b֍1J Ї %fe|- q[#9&L54BcTq/oXK I^uhB`,QP_HM3FoK`m޵Zƈ2? 㢘˄[RLMr7X^rPub꧜ UDYAO%˫+dI9'ȹ;fuD $cV̄rgftyJ]XbdžBJ)2qf" ݵ]?B 5ȼ"I 4KJBS4O2 Nfc.26ZԱ)*)w : GB0B7daV&?Oz7yέԚ  MUK{@訐 [@U1ͧ|T~U94+8u0&RZe $\ZL H iR,殺I x0Md(;N}օ7 #include #include #include #include "testconfig.h" #include "kraftdb.h" #include "attribute.h" #include "dbids.h" void init_test_db() { const QString dbName("__test.db"); QDir sourceDir(TESTS_PATH); sourceDir.cdUp(); const QByteArray ba {sourceDir.absolutePath().toLatin1()}; qputenv("KRAFT_HOME", ba); QFile::remove(dbName); KraftDB::self()->dbConnect("QSQLITE", dbName, QString(), QString(), QString()); SqlCommandList sqls = KraftDB::self()->parseCommandFile("5_dbmigrate.sql"); QVERIFY(sqls.size() > 0); KraftDB::self()->processSqlCommands(sqls); sqls = KraftDB::self()->parseCommandFile("10_dbmigrate.sql"); KraftDB::self()->processSqlCommands(sqls); sqls = KraftDB::self()->parseCommandFile("11_dbmigrate.sql"); KraftDB::self()->processSqlCommands(sqls); } class T_Attributes : public QObject { Q_OBJECT private slots: void initTestCase() { init_test_db(); } void cleanupTestCase() { const QString dbName("__test.db"); QDir sourceDir(TESTS_PATH); sourceDir.cdUp(); Q_ASSERT(QFile::remove(dbName)); } void checkTablesExist() { const QStringList attribCols{"id", "hostObject", "hostId", "name", "valueIsList", "relationTable", "relationIDColumn", "relationStringColumn"}; QVERIFY(KraftDB::self()->checkTableExistsSqlite("attributes", attribCols)); const QStringList colsAttribValues{"id", "attributeId", "value"}; QVERIFY(KraftDB::self()->checkTableExistsSqlite("attributeValues", colsAttribValues)); } void simple1() { Attribute att = makeAtt("Test", "foo"); QVERIFY(att.name() == QStringLiteral("Test")); QVERIFY(att.value().toString() == QStringLiteral("foo")); } void copyAttribute() { Attribute att = makeAtt("Test", "foo"); Attribute att2 = att; QVERIFY(att2.name() == QStringLiteral("Test")); QVERIFY(att2.value().toString() == QStringLiteral("foo")); } void saveAndLoadAttribs() { const QString host {"testhost"}; AttributeMap map(host); Attribute att1 = makeAtt("Test", "foo"); Attribute att2 = makeAtt("Test2", "foobar"); map[att1.name()] = att1; map[att2.name()] = att2; dbID id(342); map.save(id); AttributeMap m2(host); m2.load(id); QVERIFY(m2.contains(att1.name())); QVERIFY(m2.contains(att2.name())); } void listValues() { const QString host {"listtest"}; AttributeMap map(host); { Attribute att1 = makeAtt("Test", "foo"); att1.setListValue(true); const QStringList li1 {"foo", "bar", "baz"}; att1.setValue(QVariant(li1)); map[att1.name()] = att1; } Attribute att2 = makeAtt("Test2", "foobar"); att2.setListValue(true); const QStringList li2 {"foo", "bar", "baz"}; att2.setValue(QVariant(li2)); map[att2.name()] = att2; // --- save dbID id(344); map.save(id); // --- and load again AttributeMap m2(host); m2.load(id); QVERIFY(m2.contains("Test")); QVERIFY(m2.contains(att2.name())); Attribute a3 = m2["Test2"]; const QStringList li = a3.value().toStringList(); QVERIFY(li.contains("foo")); QVERIFY(li.contains("bar")); QVERIFY(li.contains("baz")); } private: Attribute makeAtt(const QString& name, const QString& val) { Attribute att(name); att.setValue(val); att.setPersistant(true); att.setListValue(false); return att; } }; QTEST_MAIN(T_Attributes) #include "t_attributes.moc" kraft-1.1/tests/t_defaultprovider.cpp000066400000000000000000000112051450127457600200640ustar00rootroot00000000000000#include #include #include #include #include #include "defaultprovider.h" namespace { void createTestFile( const QString& testFile, const QString& content = QString()) { QString c {content}; if (c.isEmpty() ) { c = QLatin1String("This is a super fancy test file"); } QFile file(testFile); QVERIFY (file.open(QIODevice::WriteOnly)); { QTextStream stream(&file); stream << c << endl; } } } class T_Defaultprovider: public QObject { Q_OBJECT private: QString _systemDir; private slots: void initTestCase() { const QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); const QString home = QDir::homePath(); const QString appName = qAppName(); const QString testDir = QString("%1/.local/share/%2").arg(home).arg(appName); int indx = dirs.indexOf(testDir); QVERIFY(indx > -1); _systemDir = dirs.at(indx); QDir td(_systemDir + "/styles"); if (!td.exists()) td.mkpath(td.path()); QVERIFY(td.exists()); } void cleanupTestCase() { QDir td(_systemDir); QVERIFY(td.removeRecursively()); } void testLocateFileSytemPath() { QVERIFY(!_systemDir.isEmpty()); // KRAFT_HOME has to be empty for this check const QString kraftHome = QString::fromUtf8(qgetenv( "KRAFT_HOME" )); QVERIFY(kraftHome.isEmpty()); // first, check if it is installed in the system const QString fullTestFile = QString("%1/styles/docoverview.css").arg(_systemDir); createTestFile(fullTestFile); QVERIFY(QFile::exists(fullTestFile)); const QString foundFile = DefaultProvider::self()->locateFile("styles/docoverview.css"); QCOMPARE(foundFile, fullTestFile); const QString noExistFile = DefaultProvider::self()->locateFile("styles/nothere"); QVERIFY(noExistFile.isEmpty()); const QString noExistFile2 = DefaultProvider::self()->locateFile("nostyles/docoverview.css"); QVERIFY(noExistFile2.isEmpty()); } // This test sets the environment var KRAFT_HOME to a dir under the systemDir, // and checks if the filename is returned correctly. void testLocateWithKraftHome() { QVERIFY(!_systemDir.isEmpty()); const QString fullTestFile = QString("%1/krafthome/mydir/kraftfile").arg(_systemDir); QDir td(QString("%1/krafthome/mydir").arg(_systemDir)); if (!td.exists()) { td.mkpath(td.path()); } QVERIFY(td.exists()); createTestFile(fullTestFile); // KRAFT_HOME should be empty for this check const QString kraftHome = QString::fromUtf8(qgetenv( "KRAFT_HOME" )); QVERIFY(kraftHome.isEmpty()); QByteArray kh {_systemDir.toUtf8()}; kh.append("/krafthome"); qputenv("KRAFT_HOME", kh); const QString foundFile = DefaultProvider::self()->locateFile("mydir/kraftfile"); QCOMPARE(foundFile, fullTestFile); const QString noExistFile = DefaultProvider::self()->locateFile("mydir/nothere"); QVERIFY(noExistFile.isEmpty()); const QString noExistFile2 = DefaultProvider::self()->locateFile("nomydir/kraftfile"); QVERIFY(noExistFile2.isEmpty()); qunsetenv("KRAFT_HOME"); } // test relative to the app dir void testLocateRelative() { const QString appDir = QCoreApplication::applicationDirPath(); QDir::setCurrent(QCoreApplication::applicationDirPath()); // Is it possible to create a kraft-dir ? QFileInfo fi("../share"); if (!fi.exists()) { const QString mydir{"../share/kraft/mydir"}; QDir td(mydir); const QString abso = td.absolutePath(); QVERIFY(td.mkpath(abso)); const QString fullTestFile = QString("%1/kraftfile").arg(abso); createTestFile(fullTestFile); QFileInfo fi(fullTestFile); const QString foundFile = DefaultProvider::self()->locateFile("mydir/kraftfile"); QCOMPARE(foundFile, fi.canonicalFilePath()); const QString noExistFile = DefaultProvider::self()->locateFile("mydir/nothere"); QVERIFY(noExistFile.isEmpty()); const QString noExistFile2 = DefaultProvider::self()->locateFile("nomydir/kraftfile"); QVERIFY(noExistFile2.isEmpty()); QVERIFY(td.rmdir(mydir)); } else { qDebug() << "Skipped relative path test, directory share exists."; } } }; QTEST_MAIN(T_Defaultprovider) #include "t_defaultprovider.moc" kraft-1.1/tests/t_doctype.cpp000066400000000000000000000143221450127457600163370ustar00rootroot00000000000000#include #include #include #include #include "testconfig.h" #include "doctype.h" #include "kraftdb.h" #include "sql_states.h" void init_test_db() { const QString dbName("__test.db"); QDir sourceDir(TESTS_PATH); sourceDir.cdUp(); const QByteArray ba {sourceDir.absolutePath().toLatin1()}; qputenv("KRAFT_HOME", ba); QFile::remove(dbName); KraftDB::self()->dbConnect("QSQLITE", dbName, QString(), QString(), QString()); SqlCommandList sqls = KraftDB::self()->parseCommandFile("5_dbmigrate.sql"); QVERIFY(sqls.size() > 0); KraftDB::self()->processSqlCommands(sqls); // modify the initial attributes tables sqls = KraftDB::self()->parseCommandFile("10_dbmigrate.sql"); KraftDB::self()->processSqlCommands(sqls); // get the followers into the database sqls = KraftDB::self()->parseCommandFile("8_dbmigrate.sql"); KraftDB::self()->processSqlCommands(sqls); } class T_DocType : public QObject { Q_OBJECT private slots: void initTestCase() { init_test_db(); } void checkTablesExist() { const QStringList attribCols{"id", "hostObject", "hostId", "name", "valueIsList", "relationTable", "relationIDColumn", "relationStringColumn"}; QVERIFY(KraftDB::self()->checkTableExistsSqlite("attributes", attribCols)); const QStringList attribColsDt{"docTypeID", "name"}; QVERIFY(KraftDB::self()->checkTableExistsSqlite("DocTypes", attribColsDt)); const QStringList colsAttribValues{"id", "attributeId", "value"}; QVERIFY(KraftDB::self()->checkTableExistsSqlite("attributeValues", colsAttribValues)); } void checkAll() { QStringList allDts = DocType::allLocalised(); for( const QString& s : allDts ) { qDebug() << "** " << s; } QVERIFY(allDts.count() > 2); _docTypeName = allDts.at(1); } void loadADt() { qDebug() << "Loading doctype" << _docTypeName; DocType dt(_docTypeName); QVERIFY( dt.name() == _docTypeName); QVERIFY( dt.name() == QLatin1Literal("Angebot")); QVERIFY( dt.allowAlternative()); QVERIFY( dt.allowDemand()); } void checkFollowers() { DocType dt(_docTypeName); QStringList f = dt.follower(); QVERIFY(f.contains("Rechnung")); } void createNewDoctype() { QStringList f; f.append("Angebot"); f.append("Rechnung"); DocType dt( "Test" ); dt.setAttribute("myattrib", "Kraft"); dt.setMergeIdent("2"); dt.save(); int num = dt.setAllFollowers(f); QVERIFY(2 == num ); } void readNewDoctype() { DocType dt("Test"); QVERIFY(dt.mergeIdent() == "2"); QVERIFY(dt.name() == "Test"); QVERIFY(! dt.allowAlternative()); QStringList li = dt.follower(); QVERIFY( li.size() == 2 ); QVERIFY( li.contains("Angebot")); QVERIFY( li.indexOf("Angebot") == 0 ); QVERIFY( li.indexOf("Rechnung") == 1 ); } void addAFollower() { DocType dt("Test"); QStringList li = dt.follower(); QVERIFY(li.size() == 2); li.append("Offer"); int num = dt.setAllFollowers(li); qDebug() << "oo " << num; QVERIFY(1 == num); QVERIFY( li.contains("Angebot")); QVERIFY( li.contains("Rechnung")); QVERIFY( li.contains("Offer")); } void checkVariableReplacement() { DocType dt("Test"); dt.setIdentTemplate("FOO-%y-%w-%d-%i"); QString re = dt.generateDocumentIdent(QDate(2020, 01,23), "addressUID", 122, 0); QCOMPARE(re, QStringLiteral("FOO-2020-4-23-122")); dt.setIdentTemplate("FOO-%y-%ww-%d-%i"); re = dt.generateDocumentIdent(QDate(2020, 01,23), "addressUID", 122, 0); QCOMPARE(re, QStringLiteral("FOO-2020-04-23-122")); // the id can change dt.setIdentTemplate("FOO-%y-%ww-%d-%iiiii"); re = dt.generateDocumentIdent(QDate(2020, 01,23), "addressUID", 122, 0); QCOMPARE(re, QStringLiteral("FOO-2020-04-23-00122")); // the id can change dt.setIdentTemplate("FOO-%y-%ww-%d-%iiii"); re = dt.generateDocumentIdent(QDate(2020, 01,23), "addressUID", 122, 0); QCOMPARE(re, QStringLiteral("FOO-2020-04-23-0122")); // the id can change dt.setIdentTemplate("FOO-%y-%ww-%d-%iii"); re = dt.generateDocumentIdent(QDate(2020, 01,23), "addressUID", 122, 0); QCOMPARE(re, QStringLiteral("FOO-2020-04-23-122")); // the id can change dt.setIdentTemplate("FOO-%y-%ww-%d-%ii"); re = dt.generateDocumentIdent(QDate(2020, 01,23), "addressUID", 122, 0); QCOMPARE(re, QStringLiteral("FOO-2020-04-23-122")); // the id can change } void checkDayCntIncrement() { DocType dt("Test"); const QDate d1(2022, 01, 23); const QDate d2(2022, 01, 25); int cnt = dt.nextDayCounter(d1); QCOMPARE(cnt, 1); cnt = dt.nextDayCounter(d1); QCOMPARE(cnt, 2); cnt = dt.nextDayCounter(d1); QCOMPARE(cnt, 3); // - switch to next date cnt = dt.nextDayCounter(d2); QCOMPARE(cnt, 1); cnt = dt.nextDayCounter(d2); QCOMPARE(cnt, 2); // - back to d1 cnt = dt.nextDayCounter(d1); QCOMPARE(cnt, 1); } void checkDateCounter() { DocType dt("Test"); // Attention: This test assumes that all verifies run on the same day. dt.setIdentTemplate("FOO-%n"); QString re = dt.generateDocumentIdent(QDate(2020, 01,23), "addressUID", 122, 2); QCOMPARE(re, "FOO-2"); // Test the padding functionality dt.setIdentTemplate("FOO-%nn"); re = dt.generateDocumentIdent(QDate(2020, 01,23), "addressUID", 122, 3); QCOMPARE(re, "FOO-03"); dt.setIdentTemplate("FOO-%nnn"); re = dt.generateDocumentIdent(QDate(2020, 01,23), "addressUID", 122, 3); QCOMPARE(re, "FOO-003"); dt.setIdentTemplate("FOO-%nnnn"); re = dt.generateDocumentIdent(QDate(2020, 01,23), "addressUID", 122, 6); QCOMPARE(re, "FOO-0006"); } private: QString _docTypeName; }; QTEST_MAIN(T_DocType) #include "t_doctype.moc" kraft-1.1/tests/t_format.cpp000066400000000000000000000017611450127457600161630ustar00rootroot00000000000000#include #include #include "format.h" class T_Format : public QObject { Q_OBJECT private slots: void initTestCase() { } void t1() { double s = 1.0; const QString sstr = Format::localeDoubleToString(s, QLocale::c()); QCOMPARE(sstr, QStringLiteral("1")); double s1 = 1.2; const QString sstr1 = Format::localeDoubleToString(s1, QLocale::c()); QCOMPARE(sstr1, QStringLiteral("1.2")); double s2 = 1.43; const QString sstr2 = Format::localeDoubleToString(s2, QLocale::c()); QCOMPARE(sstr2, QStringLiteral("1.43")); double s3 = 1.334543; const QString sstr3 = Format::localeDoubleToString(s3, QLocale::c()); QCOMPARE(sstr3, QStringLiteral("1.335")); double s4 = 1.50; const QString sstr4 = Format::localeDoubleToString(s4, QLocale::c()); QCOMPARE(sstr4, QStringLiteral("1.5")); } private: }; QTEST_MAIN(T_Format) #include "t_format.moc" kraft-1.1/tests/t_kraftdoc.cpp000066400000000000000000000207571450127457600164760ustar00rootroot00000000000000#include #include #include #include #include "testconfig.h" #include "kraftdb.h" #include "kraftdoc.h" #include "attribute.h" #include "docposition.h" #include "dbids.h" void init_test_db() { const QString dbName("__test.db"); QDir sourceDir(TESTS_PATH); sourceDir.cdUp(); const QByteArray ba {sourceDir.absolutePath().toLatin1()}; qputenv("KRAFT_HOME", ba); QFile::remove(dbName); KraftDB::self()->dbConnect("QSQLITE", dbName, QString(), QString(), QString()); // create the tagTemplate table which is required by DocPositionBase::hasTag SqlCommandList sqls = KraftDB::self()->parseCommandFile("10_dbmigrate.sql"); QVERIFY(sqls.size() > 0); KraftDB::self()->processSqlCommands(sqls); #if 0 sqls = KraftDB::self()->parseCommandFile("10_dbmigrate.sql"); KraftDB::self()->processSqlCommands(sqls); sqls = KraftDB::self()->parseCommandFile("11_dbmigrate.sql"); KraftDB::self()->processSqlCommands(sqls); #endif } namespace { DocPositionList buildPosList() { DocPositionList positions; // Attention: only use tags here that exist in the database, as // defined in the 10_migrate.sql DocPosition *dp1 = new DocPosition; dp1->setAmount(2.0); dp1->setUnitPrice(Geld(6.50)); dp1->setText("Position1"); dp1->setTag("Work"); positions.append(dp1); DocPosition *dp2 = new DocPosition; dp2->setAmount(4.0); dp2->setUnitPrice(Geld(12.50)); dp2->setText("Position2"); dp2->setTag("Work"); positions.append(dp2); DocPosition *dp3 = new DocPosition; dp3->setAmount(4.0); dp3->setUnitPrice(Geld(1.50)); dp3->setText("Position3"); dp3->setTag("Material"); positions.append(dp3); return positions; } } class T_KraftDoc: public QObject { Q_OBJECT private slots: void initTestCase() { init_test_db(); } void cleanupTestCase() { const QString dbName("__test.db"); QDir sourceDir(TESTS_PATH); sourceDir.cdUp(); Q_ASSERT(QFile::remove(dbName)); } void checkTablesExist() { const QStringList attribCols {"sortkey", "name", "description", "color"}; QVERIFY(KraftDB::self()->checkTableExistsSqlite("tagTemplates", attribCols)); } void sumPerTag() { KraftDoc *kraftdoc = &kDoc; DocPositionList positions = buildPosList(); double fullTax = 19.0; double redTax = 7.0; const QString tmpl{"This is a template test with NETTO_SUM_PER_TAG(Work)"}; const QString expanded = kraftdoc->resolveMacros(tmpl, positions, _date, fullTax, redTax); qDebug() << "Expanded text is" << expanded; QString shouldBe{tmpl}; // 0xA0 is a non splitable space, no idea how to hardcode it. shouldBe.replace("NETTO_SUM_PER_TAG(Work)", "63,00" + QChar(0xA0) + "€"); QCOMPARE(expanded, shouldBe); } void sumPerTagBrutto() { KraftDoc *kraftdoc = &kDoc; DocPositionList positions = buildPosList(); double fullTax = 19.0; double redTax = 7.0; const QString tmpl{"This is a template test with NETTO_SUM_PER_TAG(Work) and BRUTTO_SUM_PER_TAG(Work) and VAT_SUM_PER_TAG(Work)"}; const QString expanded = kraftdoc->resolveMacros(tmpl, positions, _date, fullTax, redTax); qDebug() << "Expanded text is" << expanded; QString shouldBe{tmpl}; // 0xA0 is a non splitable space, no idea how to hardcode it. shouldBe.replace("NETTO_SUM_PER_TAG(Work)", "63,00" + QChar(0xA0) + "€"); shouldBe.replace("BRUTTO_SUM_PER_TAG(Work)", "74,97" + QChar(0xA0) + "€"); shouldBe.replace("VAT_SUM_PER_TAG(Work)", "11,97" + QChar(0xA0) + "€"); QCOMPARE(expanded, shouldBe); } void sumPerTagBruttoNull() { KraftDoc *kraftdoc = &kDoc; DocPositionList positions = buildPosList(); double fullTax = 19.0; double redTax = 7.0; const QString tmpl{"This is a template test with NETTO_SUM_PER_TAG(NoWork) and BRUTTO_SUM_PER_TAG(NoWork) and VAT_SUM_PER_TAG(NoWork)"}; const QString expanded = kraftdoc->resolveMacros(tmpl, positions, _date, fullTax, redTax); qDebug() << "Expanded text is" << expanded; QString shouldBe{tmpl}; // 0xA0 is a non splitable space, no idea how to hardcode it. shouldBe.replace("NETTO_SUM_PER_TAG(NoWork)", "0,00" + QChar(0xA0) + "€"); shouldBe.replace("BRUTTO_SUM_PER_TAG(NoWork)", "0,00" + QChar(0xA0) + "€"); shouldBe.replace("VAT_SUM_PER_TAG(NoWork)", "0,00" + QChar(0xA0) + "€"); QCOMPARE(expanded, shouldBe); } // Verify that the sum is zero for a pos list where no pos has that tag void sumPerTagNoMatch() { KraftDoc *kraftdoc = &kDoc; DocPositionList positions = buildPosList(); double fullTax = 19.0; double redTax = 7.0; const QString tmpl{"This is a template test with NETTO_SUM_PER_TAG(Plants)"}; const QString expanded = kraftdoc->resolveMacros(tmpl, positions, _date, fullTax, redTax); QString shouldBe{tmpl}; // 0xA0 is a non splitable space, no idea how to hardcode it. shouldBe.replace("NETTO_SUM_PER_TAG(Plants)", "0,00" + QChar(0xA0) + "€"); QCOMPARE(expanded, shouldBe); } void ifHasTag() { KraftDoc *kraftdoc = &kDoc; DocPositionList positions = buildPosList(); double fullTax = 19.0; double redTax = 7.0; const QString tmpl{"This template IF_ANY_HAS_TAG(Work) has the tag Work END_HAS_TAG"}; const QString expanded = kraftdoc->resolveMacros(tmpl, positions, _date, fullTax, redTax); QString shouldBe{"This template has the tag Work"}; // 0xA0 is a non splitable space, no idea how to hardcode it. QCOMPARE(expanded, shouldBe); } void ifHasTagNoEnd() { KraftDoc *kraftdoc = &kDoc; DocPositionList positions = buildPosList(); double fullTax = 19.0; double redTax = 7.0; const QString tmpl{"This template IF_ANY_HAS_TAG(Work) has the tag Work without an end"}; const QString expanded = kraftdoc->resolveMacros(tmpl, positions, _date, fullTax, redTax); QString shouldBe{"This template has the tag Work without an end"}; // 0xA0 is a non splitable space, no idea how to hardcode it. QCOMPARE(expanded, shouldBe); } void ifHasTagDoesNotHaveTheTag() { KraftDoc *kraftdoc = &kDoc; DocPositionList positions = buildPosList(); double fullTax = 19.0; double redTax = 7.0; const QString tmpl{"This template IF_ANY_HAS_TAG(Plants) has the tag Work END_HAS_TAG"}; const QString expanded = kraftdoc->resolveMacros(tmpl, positions, _date, fullTax, redTax); QString shouldBe{"This template"}; // 0xA0 is a non splitable space, no idea how to hardcode it. QCOMPARE(expanded, shouldBe); } void amountOfTag() { KraftDoc *kraftdoc = &kDoc; DocPositionList positions = buildPosList(); double fullTax = 19.0; double redTax = 7.0; const QString tmpl{"This template has ITEM_COUNT_WITH_TAG(Work) work items"}; const QString expanded = kraftdoc->resolveMacros(tmpl, positions, _date, fullTax, redTax); QString shouldBe{"This template has 2 work items"}; // 0xA0 is a non splitable space, no idea how to hardcode it. QCOMPARE(expanded, shouldBe); } void dateAddDay() { KraftDoc *kraftdoc = &kDoc; DocPositionList positions = buildPosList(); QDate d{2020, 1, 24}; double fullTax = 19.0; double redTax = 7.0; QString tmpl{"This is 12 days later than 24.01.2020: DATE_ADD_DAYS(12)"}; QString expanded = kraftdoc->resolveMacros(tmpl, positions, d, fullTax, redTax); QString shouldBe{"This is 12 days later than 24.01.2020: 05.02.2020"}; QCOMPARE(expanded, shouldBe); tmpl = "This is 0 days later than 24.01.2020: DATE_ADD_DAYS(0)"; expanded = kraftdoc->resolveMacros(tmpl, positions, d, fullTax, redTax); shouldBe = "This is 0 days later than 24.01.2020: 24.01.2020"; QCOMPARE(expanded, shouldBe); tmpl = "This is -5 days later than 24.01.2020: DATE_ADD_DAYS(-5)"; expanded = kraftdoc->resolveMacros(tmpl, positions, d, fullTax, redTax); shouldBe = "This is -5 days later than 24.01.2020: 19.01.2020"; QCOMPARE(expanded, shouldBe); } private: KraftDoc kDoc; QDate _date; }; QTEST_MAIN(T_KraftDoc) #include "t_kraftdoc.moc" kraft-1.1/tests/t_metaparser.cpp000066400000000000000000000032441450127457600170340ustar00rootroot00000000000000#include #include #include "metaxmlparser.h" class T_MetaParser : public QObject { Q_OBJECT private slots: void initTestCase() { } void goodParser() { QByteArray xml = "\ \ \ Progress Payment Invoice\ default\ en\ \ PartialInvoice\ true\ \ \ RedRider\ true\ \ Final Invoice\ Invoice\ \ \ "; QBuffer buf( &xml); MetaXMLParser parser; QVERIFY(parser.parse(&buf)); QList list = parser.metaDocTypeAddList(); QVERIFY(list.size() == 1 ); MetaDocTypeAdd tadd = list.first(); QCOMPARE(tadd.name(), QLatin1String("Progress Payment Invoice") ); QCOMPARE(tadd.numbercycle(), QLatin1String("default")); QCOMPARE(tadd.lang(), QLatin1String("en")); QVERIFY(tadd._attribs.size() == 2); QVariant rr(tadd._attribs.value("RedRider")); QVERIFY(rr.toBool()); QVERIFY(tadd._follower.size() == 2); QCOMPARE(tadd._follower.at(0), QLatin1String("Final Invoice")); QCOMPARE(tadd._follower.at(1), QLatin1String("Invoice")); } private: }; QTEST_MAIN(T_MetaParser) #include "t_metaparser.moc" kraft-1.1/tests/t_stringutil.cpp000066400000000000000000000032751450127457600171010ustar00rootroot00000000000000#include #include "testconfig.h" #include "stringutil.h" class T_Stringutil : public QObject { Q_OBJECT private slots: void simple1() { QString tmpl{"Foo %nn baz"}; QMap rep; rep.insert("%nn", "bar"); QString re = StringUtil::replaceTagsInString(tmpl, rep); QCOMPARE(re, QStringLiteral("Foo bar baz")); } void keyLenVariant() { QString tmpl{"Foo %nn %nnn baz"}; QMap rep; rep.insert("%nn", "bar"); rep.insert("%nnn", "bar2"); QString re = StringUtil::replaceTagsInString(tmpl, rep); QCOMPARE(re, QStringLiteral("Foo bar bar2 baz")); } void multipleKey() { QString tmpl{"Foo %nn %nnn %nn baz"}; QMap rep; rep.insert("%nn", "bar"); rep.insert("%nnn", "bar2"); QString re = StringUtil::replaceTagsInString(tmpl, rep); QCOMPARE(re, QStringLiteral("Foo bar bar2 bar baz")); } void multipleKey2() { QString tmpl{"Foo %nn %nnn %nn %dd baz"}; QMap rep; rep.insert("%nn", "bar"); rep.insert("%nnn", "bar2"); rep.insert("%dd", "numbers"); QString re = StringUtil::replaceTagsInString(tmpl, rep); QCOMPARE(re, QStringLiteral("Foo bar bar2 bar numbers baz")); } void percentVal() { QString tmpl{"Foo %nn %nnn"}; QMap rep; rep.insert("%nn", "bar %"); rep.insert("%nnn", "bar2"); QString re = StringUtil::replaceTagsInString(tmpl, rep); QCOMPARE(re, QStringLiteral("Foo bar % bar2")); } }; QTEST_MAIN(T_Stringutil) #include "t_stringutil.moc" kraft-1.1/tests/t_unitman.cpp000066400000000000000000000037221450127457600163450ustar00rootroot00000000000000#include #include #include #include #include #include "testconfig.h" #include "kraftdb.h" #include "sql_states.h" #include "unitmanager.h" #include "einheit.h" void init_test_db() { const QString dbName("__test.db"); QFile::remove(dbName); KraftDB::self()->dbConnect("QSQLITE", dbName, QString(), QString(), QString()); QDir sourceDir(TESTS_PATH); sourceDir.cdUp(); const QByteArray ba {sourceDir.absolutePath().toLatin1()}; qputenv("KRAFT_HOME", ba); SqlCommandList sqls = KraftDB::self()->parseCommandFile("create_schema.sql"); KraftDB::self()->processSqlCommands(sqls); sqls = KraftDB::self()->parseCommandFile("fill_schema_de.sql"); KraftDB::self()->processSqlCommands(sqls); // This adds a migration from file 24_dbmigrate.sql to the units table. Unfortunately the // migration file can not be used directly here, because it is only found in a setup where // KRAFT_HOME is defined or the 24_dbmigrate.sql is installed in the system. // For simplification we do that manually here. sqls.clear(); sqls.append(SqlCommand("ALTER TABLE units ADD COLUMN ec20 VARCHAR(10);", "", false)); sqls.append(SqlCommand("UPDATE units set ec20 = \"MTR\" WHERE unitShort = \"m\";", "", false)); KraftDB::self()->processSqlCommands(sqls); } class T_UnitMan : public QObject { Q_OBJECT private slots: void initTestCase() { init_test_db(); } void checkUnitsLoaded() { QStringList units = UnitManager::self()->allUnits(); QVERIFY(units.count() > 0); qDebug() << "ALL Units:" << units; } void checkPauschUnit() { Einheit e = UnitManager::self()->getPauschUnit(); QCOMPARE(e.einheitSingular(), QStringLiteral("pausch.")); } void checkECE20() { auto u = UnitManager::self()->getECE20("m"); QCOMPARE(u, "MTR"); } }; QTEST_MAIN(T_UnitMan) #include "t_unitman.moc" kraft-1.1/tests/testconfig.h.in000066400000000000000000000000451450127457600165610ustar00rootroot00000000000000 #define TESTS_PATH "@TESTS_PATH@" kraft-1.1/tools/000077500000000000000000000000001450127457600136355ustar00rootroot00000000000000kraft-1.1/tools/CMakeLists.txt000066400000000000000000000014731450127457600164020ustar00rootroot00000000000000 set(findcontact_NAME findcontact) set(FINDCONTACT_SRC findcontact.cpp ../src/addressprovider.cpp ../src/addressprovider_akonadi.cpp) set(AUTOMOC ON) # # For now there is only the Akonadi based address backend, and thus # the findcontact tool is only built if akonadi is there. # If there are other backends, this must be FIXED. if(${AKO_PREFIX}Akonadi_FOUND) add_executable(${findcontact_NAME} ${FINDCONTACT_SRC}) target_link_libraries( ${findcontact_NAME} Qt5::Core Qt5::Widgets KF5::Contacts ${AKO_PREFIX}::AkonadiCore ${AKO_PREFIX}::AkonadiContact ) ########### install files ############### install(TARGETS ${findcontact_NAME} ${INSTALL_TARGETS_DEFAULT_ARGS}) endif() install(FILES erml2pdf.py watermarkpdf.py DESTINATION ${DATA_INSTALL_DIR}/kraft/tools ) kraft-1.1/tools/erml2pdf000077500000000000000000000002551450127457600153000ustar00rootroot00000000000000#!/bin/bash # (c) Klaas Freitag , 2010 # Start script for the python erml2pdf # to see error output, remove the 2>... part # python $0.py $* 2>/dev/null #kraft-1.1/tools/erml2pdf.py000066400000000000000000001145351450127457600157330ustar00rootroot00000000000000#!/usr/bin/python3 # -*- coding: utf-8 -*- # # erml2pdf - An RML to PDF converter with extended features # Copyright (C) 2003, Fabien Pinckaers, UCL, FSA # Contributors # Richard Waid # Klaas Freitag # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA import copy import io import sys import xml.dom.minidom import subprocess import shlex import tempfile import getopt import re # StringIO is not longer separate in python3, but in io try: from StringIO import StringIO except ImportError: from io import StringIO import reportlab from reportlab.pdfgen import canvas from reportlab import platypus from reportlab.lib import colors from reportlab.platypus.flowables import KeepTogether from six import text_type from PyPDF2 import PdfFileWriter, PdfFileReader # # Change this to UTF-8 if you plan tu use Reportlab's UTF-8 support # # encoding = 'latin1' # use utf8 for default encoding = 'UTF-8' # # from previous file util.py, imported for simplicity: class utils(object): @staticmethod def text_get(node): rc = '' for node in node.childNodes: if node.nodeType == node.TEXT_NODE: rc = rc + node.data return rc @staticmethod def unit_get(size): units = [ (re.compile('^(-?[0-9\.]+)\s*in$'), reportlab.lib.units.inch), (re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm), (re.compile('^(-?[0-9\.]+)\s*mm$'), reportlab.lib.units.mm), (re.compile('^(-?[0-9\.]+)\s*$'), 1) ] for unit in units: res = unit[0].search(size, 0) if res: return unit[1]*float(res.group(1)) return False @staticmethod def tuple_int_get(node, attr_name, default=None): if not node.hasAttribute(attr_name): return default res = [int(x) for x in node.getAttribute(attr_name).split(',')] return res @staticmethod def bool_get(value): return (str(value)=="1") or (value.lower()=='yes') @staticmethod def attr_get(node, attrs, dict={}): res = {} for name in attrs: if node.hasAttribute(name): res[name] = utils.unit_get(node.getAttribute(name)) for key in dict: if node.hasAttribute(key): if dict[key]=='str': res[key] = str(node.getAttribute(key)) elif dict[key]=='bool': res[key] = utils.bool_get(node.getAttribute(key)) elif dict[key]=='int': res[key] = int(node.getAttribute(key)) return res # from previous file color.py, imported for simplicity: allcols = colors.getAllNamedColors() class color(object): @staticmethod def get(col_str): allcols = colors.getAllNamedColors() regex_t = re.compile('\(([0-9\.]*),([0-9\.]*),([0-9\.]*)\)') regex_h = re.compile('#([0-9a-zA-Z][0-9a-zA-Z])([0-9a-zA-Z][0-9a-zA-Z])([0-9a-zA-Z][0-9a-zA-Z])') if col_str in allcols.keys(): return allcols[col_str] res = regex_t.search(col_str, 0) if res: return (float(res.group(1)),float(res.group(2)),float(res.group(3))) res = regex_h.search(col_str, 0) if res: return tuple([ float(int(res.group(i),16))/255 for i in range(1,4)]) return colors.red # # original trml2pdf starts here: # def _child_get(node, childs): clds = [] for n in node.childNodes: if (n.nodeType == n.ELEMENT_NODE) and (n.localName == childs): clds.append(n) return clds class _rml_styles(object): def __init__(self, nodes): self.styles = {} self.names = {} self.table_styles = {} self.list_styles = {} for node in nodes: for style in node.getElementsByTagName('blockTableStyle'): self.table_styles[ style.getAttribute('id')] = self._table_style_get(style) for style in node.getElementsByTagName('listStyle'): self.list_styles[ style.getAttribute('name')] = self._list_style_get(style) for style in node.getElementsByTagName('paraStyle'): self.styles[ style.getAttribute('name')] = self._para_style_get(style) for variable in node.getElementsByTagName('initialize'): for name in variable.getElementsByTagName('name'): self.names[name.getAttribute('id')] = name.getAttribute( 'value') def _para_style_update(self, style, node): for attr in ['textColor', 'backColor', 'bulletColor']: if node.hasAttribute(attr): style.__dict__[attr] = color.get(node.getAttribute(attr)) for attr in ['fontName', 'bulletFontName', 'bulletText']: if node.hasAttribute(attr): style.__dict__[attr] = node.getAttribute(attr) for attr in ['fontSize', 'leftIndent', 'rightIndent', 'spaceBefore', 'spaceAfter', 'firstLineIndent', 'bulletIndent', 'bulletFontSize', 'leading']: if node.hasAttribute(attr): if attr == 'fontSize' and not node.hasAttribute('leading'): style.__dict__['leading'] = utils.unit_get( node.getAttribute(attr)) * 1.2 style.__dict__[attr] = utils.unit_get(node.getAttribute(attr)) if node.hasAttribute('alignment'): align = { 'right': reportlab.lib.enums.TA_RIGHT, 'center': reportlab.lib.enums.TA_CENTER, 'justify': reportlab.lib.enums.TA_JUSTIFY } style.alignment = align.get( node.getAttribute('alignment').lower(), reportlab.lib.enums.TA_LEFT) return style def _list_style_update(self, style, node): for attr in ['bulletColor']: if node.hasAttribute(attr): style.__dict__[attr] = color.get(node.getAttribute(attr)) for attr in ['bulletType', 'bulletFontName', 'bulletDetent', 'bulletDir', 'bulletFormat', 'start']: if node.hasAttribute(attr): style.__dict__[attr] = node.getAttribute(attr) for attr in ['leftIndent', 'rightIndent', 'bulletFontSize', 'bulletOffsetY']: if node.hasAttribute(attr): style.__dict__[attr] = utils.unit_get(node.getAttribute(attr)) if node.hasAttribute('bulletAlign'): align = { 'right': reportlab.lib.enums.TA_RIGHT, 'center': reportlab.lib.enums.TA_CENTER, 'justify': reportlab.lib.enums.TA_JUSTIFY } style.alignment = align.get( node.getAttribute('alignment').lower(), reportlab.lib.enums.TA_LEFT) return style def _table_style_get(self, style_node): styles = [] for node in style_node.childNodes: if node.nodeType == node.ELEMENT_NODE: start = utils.tuple_int_get(node, 'start', (0, 0)) stop = utils.tuple_int_get(node, 'stop', (-1, -1)) if node.localName == 'blockValign': styles.append( ('VALIGN', start, stop, str(node.getAttribute('value')))) elif node.localName == 'blockFont': styles.append( ('FONT', start, stop, str(node.getAttribute('name')))) elif node.localName == 'blockSpan': styles.append(('SPAN', start, stop)) elif node.localName == 'blockTextColor': styles.append( ('TEXTCOLOR', start, stop, color.get(str(node.getAttribute('colorName'))))) elif node.localName == 'blockLeading': styles.append( ('LEADING', start, stop, utils.unit_get(node.getAttribute('length')))) elif node.localName == 'blockAlignment': styles.append( ('ALIGNMENT', start, stop, str(node.getAttribute('value')))) elif node.localName == 'blockLeftPadding': styles.append( ('LEFTPADDING', start, stop, utils.unit_get(node.getAttribute('length')))) elif node.localName == 'blockRightPadding': styles.append( ('RIGHTPADDING', start, stop, utils.unit_get(node.getAttribute('length')))) elif node.localName == 'blockTopPadding': styles.append( ('TOPPADDING', start, stop, utils.unit_get(node.getAttribute('length')))) elif node.localName == 'blockBottomPadding': styles.append( ('BOTTOMPADDING', start, stop, utils.unit_get(node.getAttribute('length')))) elif node.localName == 'blockBackground': styles.append( ('BACKGROUND', start, stop, color.get(node.getAttribute('colorName')))) if node.hasAttribute('size'): styles.append( ('FONTSIZE', start, stop, utils.unit_get(node.getAttribute('size')))) elif node.localName == 'lineStyle': kind = node.getAttribute('kind') kind_list = ['GRID', 'BOX', 'OUTLINE', 'INNERGRID', 'LINEBELOW', 'LINEABOVE', 'LINEBEFORE', 'LINEAFTER'] assert kind in kind_list thick = 1 if node.hasAttribute('thickness'): thick = float(node.getAttribute('thickness')) styles.append( (kind, start, stop, thick, color.get(node.getAttribute('colorName')))) return platypus.tables.TableStyle(styles) def _list_style_get(self, node): style = reportlab.lib.styles.ListStyle('Default') if node.hasAttribute("parent"): parent = node.getAttribute("parent") parentStyle = self.styles.get(parent) if not parentStyle: raise Exception("parent style = '%s' not found" % parent) style.__dict__.update(parentStyle.__dict__) style.alignment = parentStyle.alignment self._list_style_update(style, node) return style def _para_style_get(self, node): styles = reportlab.lib.styles.getSampleStyleSheet() style = copy.deepcopy(styles["Normal"]) if node.hasAttribute("parent"): parent = node.getAttribute("parent") parentStyle = self.styles.get(parent) if not parentStyle: raise Exception("parent style = '%s' not found" % parent) style.__dict__.update(parentStyle.__dict__) style.alignment = parentStyle.alignment self._para_style_update(style, node) return style def para_style_get(self, node): style = False if node.hasAttribute('style'): if node.getAttribute('style') in self.styles: style = copy.deepcopy(self.styles[node.getAttribute('style')]) else: sys.stderr.write( 'Warning: style not found, %s - setting default!\n' % (node.getAttribute('style'),)) if not style: styles = reportlab.lib.styles.getSampleStyleSheet() style = copy.deepcopy(styles['Normal']) return self._para_style_update(style, node) class _rml_doc(object): def __init__(self, data): self.dom = xml.dom.minidom.parseString(data) self.filename = self.dom.documentElement.getAttribute('filename') def docinit(self, els): from reportlab.lib.fonts import addMapping from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont for node in els: for font in node.getElementsByTagName('registerFont'): name = font.getAttribute('fontName').encode('ascii') fname = font.getAttribute('fontFile').encode('ascii') pdfmetrics.registerFont(TTFont(name, fname)) addMapping(name, 0, 0, name) # normal addMapping(name, 0, 1, name) # italic addMapping(name, 1, 0, name) # bold addMapping(name, 1, 1, name) # italic and bold def render(self, out): el = self.dom.documentElement.getElementsByTagName('docinit') if el: self.docinit(el) el = self.dom.documentElement.getElementsByTagName('stylesheet') self.styles = _rml_styles(el) el = self.dom.documentElement.getElementsByTagName('template') if len(el): pt_obj = _rml_template(out, el[0], self) pt_obj.render( self.dom.documentElement.getElementsByTagName('story')[0]) else: self.canvas = canvas.Canvas(out) pd = self.dom.documentElement.getElementsByTagName( 'pageDrawing')[0] pd_obj = _rml_canvas(self.canvas, None, self) pd_obj.render(pd) self.canvas.showPage() self.canvas.save() class _rml_canvas(object): def __init__(self, canvas, doc_tmpl=None, doc=None): self.canvas = canvas self.styles = doc.styles self.doc_tmpl = doc_tmpl self.doc = doc def _textual(self, node): rc = '' for n in node.childNodes: if n.nodeType == n.ELEMENT_NODE: if n.localName == 'pageNumber': countingFrom = utils.tuple_int_get(n, 'countingFrom', default=[0])[0] rc += str(self.canvas.getPageNumber() + countingFrom) elif (n.nodeType == node.CDATA_SECTION_NODE): rc += n.data elif (n.nodeType == node.TEXT_NODE): rc += n.data return rc.encode(encoding) def _drawString(self, node): self.canvas.drawString( text=self._textual(node), **utils.attr_get(node, ['x', 'y'])) def _drawCenteredString(self, node): self.canvas.drawCentredString( text=self._textual(node), **utils.attr_get(node, ['x', 'y'])) def _drawRightString(self, node): self.canvas.drawRightString( text=self._textual(node), **utils.attr_get(node, ['x', 'y'])) def _rect(self, node): if node.hasAttribute('round'): self.canvas.roundRect(radius=utils.unit_get(node.getAttribute( 'round')), **utils.attr_get(node, ['x', 'y', 'width', 'height'], {'fill': 'bool', 'stroke': 'bool'})) else: self.canvas.rect( **utils.attr_get(node, ['x', 'y', 'width', 'height'], {'fill': 'bool', 'stroke': 'bool'})) def _ellipse(self, node): x1 = utils.unit_get(node.getAttribute('x')) x2 = utils.unit_get(node.getAttribute('width')) y1 = utils.unit_get(node.getAttribute('y')) y2 = utils.unit_get(node.getAttribute('height')) self.canvas.ellipse( x1, y1, x2, y2, **utils.attr_get(node, [], {'fill': 'bool', 'stroke': 'bool'})) def _curves(self, node): line_str = utils.text_get(node).split() while len(line_str) > 7: self.canvas.bezier(*[utils.unit_get(l) for l in line_str[0:8]]) line_str = line_str[8:] def _lines(self, node): line_str = utils.text_get(node).split() lines = [] while len(line_str) > 3: lines.append([utils.unit_get(l) for l in line_str[0:4]]) line_str = line_str[4:] self.canvas.lines(lines) def _grid(self, node): xlist = [utils.unit_get(s) for s in node.getAttribute('xs').split(',')] ylist = [utils.unit_get(s) for s in node.getAttribute('ys').split(',')] self.canvas.grid(xlist, ylist) def _translate(self, node): dx = 0 dy = 0 if node.hasAttribute('dx'): dx = utils.unit_get(node.getAttribute('dx')) if node.hasAttribute('dy'): dy = utils.unit_get(node.getAttribute('dy')) self.canvas.translate(dx, dy) def _circle(self, node): self.canvas.circle(x_cen=utils.unit_get(node.getAttribute('x')), y_cen=utils.unit_get(node.getAttribute( 'y')), r=utils.unit_get(node.getAttribute('radius')), **utils.attr_get(node, [], {'fill': 'bool', 'stroke': 'bool'})) def _place(self, node): flows = _rml_flowable(self.doc).render(node) infos = utils.attr_get(node, ['x', 'y', 'width', 'height']) infos['y'] += infos['height'] for flow in flows: w, h = flow.wrap(infos['width'], infos['height']) if w <= infos['width'] and h <= infos['height']: infos['y'] -= h flow.drawOn(self.canvas, infos['x'], infos['y']) infos['height'] -= h else: raise ValueError("Not enough space") def _line_mode(self, node): ljoin = {'round': 1, 'mitered': 0, 'bevelled': 2} lcap = {'default': 0, 'round': 1, 'square': 2} if node.hasAttribute('width'): self.canvas.setLineWidth( utils.unit_get(node.getAttribute('width'))) if node.hasAttribute('join'): self.canvas.setLineJoin(ljoin[node.getAttribute('join')]) if node.hasAttribute('cap'): self.canvas.setLineCap(lcap[node.getAttribute('cap')]) if node.hasAttribute('miterLimit'): self.canvas.setDash( utils.unit_get(node.getAttribute('miterLimit'))) if node.hasAttribute('dash'): dashes = node.getAttribute('dash').split(',') for x in range(len(dashes)): dashes[x] = utils.unit_get(dashes[x]) self.canvas.setDash(node.getAttribute('dash').split(',')) def _image(self, node): from six.moves import urllib from reportlab.lib.utils import ImageReader u = urllib.request.urlopen("file:" + str(node.getAttribute('file'))) s = io.BytesIO() s.write(u.read()) s.seek(0) img = ImageReader(s) (sx, sy) = img.getSize() args = {} for tag in ('width', 'height', 'x', 'y'): if node.hasAttribute(tag): # if not utils.unit_get(node.getAttribute(tag)): # continue args[tag] = utils.unit_get(node.getAttribute(tag)) if node.hasAttribute("preserveAspectRatio"): args["preserveAspectRatio"] = True if ('width' in args) and ('height' not in args): args['height'] = sy * args['width'] / sx elif ('height' in args) and ('width' not in args): args['width'] = sx * args['height'] / sy elif ('width' in args) and ('height' in args) and (not args.get("preserveAspectRatio", False)): if (float(args['width']) / args['height']) > (float(sx) > sy): args['width'] = sx * args['height'] / sy else: args['height'] = sy * args['width'] / sx self.canvas.drawImage(img, **args) def _barcode(self, node): from reportlab.graphics.barcode import code128, qr createargs = {} drawargs = {} code_type = node.getAttribute('code') for tag in ('x', 'y'): if node.hasAttribute(tag): drawargs[tag] = utils.unit_get(node.getAttribute(tag)) if code_type == 'Code128': for tag in ('barWidth', 'barHeight'): if node.hasAttribute(tag): createargs[tag] = utils.unit_get(node.getAttribute(tag)) barcode = code128.Code128(self._textual(node), **createargs) elif code_type == "QR": for tag in ('width', 'height'): if node.hasAttribute(tag): createargs[tag] = utils.unit_get(node.getAttribute(tag)) barcode = qr.QrCode(node.getAttribute('value'), **createargs) barcode.drawOn(self.canvas, **drawargs) def _path(self, node): self.path = self.canvas.beginPath() self.path.moveTo(**utils.attr_get(node, ['x', 'y'])) for n in node.childNodes: if n.nodeType == node.ELEMENT_NODE: if n.localName == 'moveto': vals = utils.text_get(n).split() self.path.moveTo( utils.unit_get(vals[0]), utils.unit_get(vals[1])) elif n.localName == 'curvesto': vals = utils.text_get(n).split() while len(vals) > 5: pos = [] while len(pos) < 6: pos.append(utils.unit_get(vals.pop(0))) self.path.curveTo(*pos) elif (n.nodeType == node.TEXT_NODE): # Not sure if I must merge all TEXT_NODE ? data = n.data.split() while len(data) > 1: x = utils.unit_get(data.pop(0)) y = utils.unit_get(data.pop(0)) self.path.lineTo(x, y) if (not node.hasAttribute('close')) or utils.bool_get(node.getAttribute('close')): self.path.close() self.canvas.drawPath( self.path, **utils.attr_get(node, [], {'fill': 'bool', 'stroke': 'bool'})) def render(self, node): tags = { 'drawCentredString': self._drawCenteredString, 'drawCenteredString': self._drawCenteredString, 'drawRightString': self._drawRightString, 'drawString': self._drawString, 'rect': self._rect, 'ellipse': self._ellipse, 'lines': self._lines, 'grid': self._grid, 'curves': self._curves, 'fill': lambda node: self.canvas.setFillColor(color.get(node.getAttribute('color'))), 'stroke': lambda node: self.canvas.setStrokeColor(color.get(node.getAttribute('color'))), 'setFont': lambda node: self.canvas.setFont(node.getAttribute('name'), utils.unit_get(node.getAttribute('size'))), 'place': self._place, 'circle': self._circle, 'lineMode': self._line_mode, 'path': self._path, 'rotate': lambda node: self.canvas.rotate(float(node.getAttribute('degrees'))), 'translate': self._translate, 'image': self._image, 'barCode': self._barcode, } for nd in node.childNodes: if nd.nodeType == nd.ELEMENT_NODE: for tag in tags: if nd.localName == tag: tags[tag](nd) break class _rml_draw(object): def __init__(self, node, styles): self.node = node self.styles = styles self.canvas = None def render(self, canvas, doc): canvas.saveState() cnv = _rml_canvas(canvas, doc, self.styles) cnv.render(self.node) canvas.restoreState() class _rml_flowable(object): def __init__(self, doc): self.doc = doc self.styles = doc.styles def _textual(self, node): rc = '' for n in node.childNodes: if n.nodeType == node.ELEMENT_NODE: if n.localName == 'getName': newNode = self.doc.dom.createTextNode( self.styles.names.get(n.getAttribute('id'), 'Unknown name')) node.insertBefore(newNode, n) node.removeChild(n) if n.localName == 'pageNumber': rc += '' # TODO: change this ! else: self._textual(n) rc += n.toxml() elif (n.nodeType == node.CDATA_SECTION_NODE): rc += n.data elif (n.nodeType == node.TEXT_NODE): rc += n.toxml() return text_type(rc) def _list(self, node): if node.hasAttribute('style'): list_style = self.styles.list_styles[node.getAttribute('style')] else: list_style = platypus.flowables.ListStyle('Default') list_items = [] for li in _child_get(node, 'li'): flow = [] for n in li.childNodes: if n.nodeType == node.ELEMENT_NODE: flow.append(self._flowable(n)) if not flow: if li.hasAttribute('style'): li_style = self.styles.styles[ li.getAttribute('style')] else: li_style = reportlab.lib.styles.getSampleStyleSheet()['Normal'] flow = platypus.paragraph.Paragraph(self._textual(li), li_style) list_item = platypus.ListItem(flow) list_items.append(list_item) return platypus.ListFlowable(list_items, style=list_style, start=list_style.__dict__.get('start')) def _table(self, node): length = 0 colwidths = None rowheights = None data = [] for tr in _child_get(node, 'tr'): data2 = [] for td in _child_get(tr, 'td'): flow = [] for n in td.childNodes: if n.nodeType == node.ELEMENT_NODE: flow.append(self._flowable(n)) if not len(flow): flow = self._textual(td) data2.append(flow) if len(data2) > length: length = len(data2) for ab in data: while len(ab) < length: ab.append('') while len(data2) < length: data2.append('') data.append(data2) if node.hasAttribute('colWidths'): assert length == len(node.getAttribute('colWidths').split(',')) colwidths = [ utils.unit_get(f.strip()) for f in node.getAttribute('colWidths').split(',')] if node.hasAttribute('rowHeights'): rowheights = [ utils.unit_get(f.strip()) for f in node.getAttribute('rowHeights').split(',')] table = platypus.Table(data=data, colWidths=colwidths, rowHeights=rowheights, **( utils.attr_get(node, ['splitByRow'], {'repeatRows': 'int', 'repeatCols': 'int'}))) if node.hasAttribute('style'): table.setStyle( self.styles.table_styles[node.getAttribute('style')]) return table def _illustration(self, node): class Illustration(platypus.flowables.Flowable): def __init__(self, node, styles): self.node = node self.styles = styles self.width = utils.unit_get(node.getAttribute('width')) self.height = utils.unit_get(node.getAttribute('height')) def wrap(self, *args): return (self.width, self.height) def draw(self): canvas = self.canv drw = _rml_draw(self.node, self.styles) drw.render(self.canv, None) return Illustration(node, self.styles) def _flowable(self, node): if node.localName == 'para': style = self.styles.para_style_get(node) return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText': 'str'}))) elif node.localName == 'name': self.styles.names[ node.getAttribute('id')] = node.getAttribute('value') return None elif node.localName == 'xpre': style = self.styles.para_style_get(node) return platypus.XPreformatted(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText': 'str', 'dedent': 'int', 'frags': 'int'}))) elif node.localName == 'pre': style = self.styles.para_style_get(node) return platypus.Preformatted(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText': 'str', 'dedent': 'int'}))) elif node.localName == 'illustration': return self._illustration(node) elif node.localName == 'blockTable': return self._table(node) # return KeepTogether(self._table(node)) elif node.localName == 'title': styles = reportlab.lib.styles.getSampleStyleSheet() style = styles['Title'] return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText': 'str'}))) elif node.localName == 'h1': styles = reportlab.lib.styles.getSampleStyleSheet() style = styles['Heading1'] return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText': 'str'}))) elif node.localName == 'h2': styles = reportlab.lib.styles.getSampleStyleSheet() style = styles['Heading2'] return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText': 'str'}))) elif node.localName == 'h3': styles = reportlab.lib.styles.getSampleStyleSheet() style = styles['Heading3'] return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText': 'str'}))) elif node.localName == 'image': return platypus.Image(node.getAttribute('file'), mask=(250, 255, 250, 255, 250, 255), **(utils.attr_get(node, ['width', 'height', 'preserveAspectRatio', 'anchor']))) elif node.localName == 'spacer': if node.hasAttribute('width'): width = utils.unit_get(node.getAttribute('width')) else: width = utils.unit_get('1cm') length = utils.unit_get(node.getAttribute('length')) return platypus.Spacer(width=width, height=length) elif node.localName == 'barCode': return code39.Extended39(self._textual(node)) elif node.localName == 'pageBreak': return platypus.PageBreak() elif node.localName == 'condPageBreak': return platypus.CondPageBreak(**(utils.attr_get(node, ['height']))) elif node.localName == 'setNextTemplate': return platypus.NextPageTemplate(str(node.getAttribute('name'))) elif node.localName == 'nextFrame': return platypus.FrameBreak() # return platypus.CondPageBreak(1000) # TODO: change the 1000 ! elif node.localName == 'ul': return self._list(node) elif node.localName == 'keepInFrame': substory = self.render(node) kwargs = { "maxWidth": 0, "maxHeight": 0, "content": substory, } mode = node.getAttribute("onOverflow") if mode: kwargs["mode"] = mode name = node.getAttribute("id") if name: kwargs["name"] = name kwargs.update( utils.attr_get(node, ['maxWidth','maxHeight', 'mergeSpace'], {'maxWidth': 'int','maxHeight': 'int'})) return platypus.KeepInFrame(**kwargs) else: sys.stderr.write( 'Warning: flowable not yet implemented: %s !\n' % (node.localName,)) return None def render(self, node_story): story = [] node = node_story.firstChild while node: if node.nodeType == node.ELEMENT_NODE: flow = self._flowable(node) if flow: story.append(flow) node = node.nextSibling return story class _rml_template(object): def __init__(self, out, node, doc): if not node.hasAttribute('pageSize'): pageSize = (utils.unit_get('21cm'), utils.unit_get('29.7cm')) else: ps = [x.strip() for x in node.getAttribute('pageSize').replace(')', '').replace( '(', '').split(',')] pageSize = (utils.unit_get(ps[0]), utils.unit_get(ps[1])) cm = reportlab.lib.units.cm self.doc_tmpl = platypus.BaseDocTemplate(out, pagesize=pageSize, **utils.attr_get(node, ['leftMargin', 'rightMargin', 'topMargin', 'bottomMargin'], { 'allowSplitting': 'int', 'showBoundary': 'bool', 'title': 'str', 'author': 'str', 'rotation': 'int'})) self.page_templates = [] self.styles = doc.styles self.doc = doc pts = node.getElementsByTagName('pageTemplate') for pt in pts: frames = [] for frame_el in pt.getElementsByTagName('frame'): frame = platypus.Frame( **(utils.attr_get(frame_el, ['x1', 'y1', 'width', 'height', 'leftPadding', 'rightPadding', 'bottomPadding', 'topPadding'], {'id': 'text', 'showBoundary': 'bool'}))) frames.append(frame) gr = pt.getElementsByTagName('pageGraphics') if len(gr): drw = _rml_draw(gr[0], self.doc) self.page_templates.append(platypus.PageTemplate( frames=frames, onPage=drw.render, **utils.attr_get(pt, [], {'id': 'str'}))) else: self.page_templates.append( platypus.PageTemplate(frames=frames, **utils.attr_get(pt, [], {'id': 'str'}))) self.doc_tmpl.addPageTemplates(self.page_templates) def render(self, node_story): r = _rml_flowable(self.doc) fis = r.render(node_story) self.doc_tmpl.build(fis) class Mark: "Enum Values for the watermark style: No watermark, first page, all pages." NOTHING = "0" FIRST_PAGE = "1" ALL_PAGES = "2" class PdfWatermark: "A class that converts a rml file to pdf" def __init__( self, outFile = None ): self.outputFile = outFile def watermark( self, pdfStr, watermarkFile, spec ): # Read the watermark- and document pdf file watermark = PdfFileReader(watermarkFile) watermark_page = watermark.getPage(0) pdfStr.seek(0) inputPdf = PdfFileReader( pdfStr ) outputPdf = PdfFileWriter() # flag for the first page of the source file firstPage = True # Loop over source document pages and merge with the first page of the watermark # file. for page in range(inputPdf.getNumPages()): pdf_page = inputPdf.getPage(page) if (spec == Mark.FIRST_PAGE and firstPage) or spec == Mark.ALL_PAGES: # deep copy the watermark page here, otherwise the watermark page # gets merged over and over because p would only be a reference pdf_page.mergePage(watermark_page) outputPdf.addPage( pdf_page ) firstPage = False else: outputPdf.addPage(pdf_page) if self.outputFile: with open(self.outputFile, 'wb') as fh: outputPdf.write(fh) return self.outputFile else: bytesIO = io.BytesIO(); outputPdf.write(bytesIO) return bytesIO.getvalue() def parseString(data): r = _rml_doc(data.strip()) fp = io.BytesIO() r.render(fp) return fp.getvalue() def erml2pdf_help(): print( 'Usage: erml2pdf [options] input.rml > output.pdf') print( '') print( 'Tool to render a file of the xml based markup language RML to PDF') print( 'with option to merge another PDF file as watermark.') print( '') print( 'Options:') print( '-o, --output output file, instead of standard out') print( '-m, --watermark-mode set the watermark mode with ') print( ' 0 = no watermark (default)') print( ' 1 = watermark on first page') print( ' 2 = watermark on all pages') print( ' Note: a watermark file must be specified for 1, 2') print( '-w, --watermark-file watermark file, the first page is used.') print( '') sys.exit(0) if __name__=="__main__": try: opts, args = getopt.getopt(sys.argv[1:], "ho:w:m:", ["help", "output=", "watermark-file=", "watermark-mode="]) except(getopt.GetoptError, err): # print help information and exit: print( str(err)) # will print something like "option -a not recognized" erml2pdf_help() sys.exit(2) output = None watermarkFile = None watermarkMode = Mark.NOTHING for o, a in opts: if o in ("-h", "--help"): erml2pdf_help() sys.exit() elif o in ("-o", "--output"): output = a elif o in ("-w", "--watermark-file"): watermarkFile = a elif o in ("-m", "--watermark-mode"): watermarkMode = a else: assert False, "unhandled option" # if len(args) == 0: # a input file needs to be there erml2pdf_help() else: # print ("Args:" + args[0]) infile = args[0] # create the PDF with the help of reportlab content = open(infile, 'r').read() pdf = parseString( content ) # apply the watermark if required # print "############ Watermark-Mode: " + watermarkMode if watermarkMode != Mark.NOTHING: wm = PdfWatermark() pdfStringFile = io.BytesIO() pdfStringFile.write( pdf ) pdf = wm.watermark( pdfStringFile, watermarkFile, watermarkMode ) # handle output option, either file or stdout if output: outfile = open(output, 'wb') outfile.write( pdf ) outfile.close() else: if sys.version_info[0] < 3: sys.stdout.write(pdf) else: sys.stdout.buffer.write(pdf) kraft-1.1/tools/findcontact.cpp000066400000000000000000000163511450127457600166430ustar00rootroot00000000000000/* * Copyright (C) 2014 by Klaas Freitag * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include #include #include "addressprovider.h" #include class FindContact : public QObject { Q_OBJECT signals: void quitLoop(); public slots: void slotAddresseeFound( const QString&, const KContacts::Addressee& contact ) { dumpContact(contact, _options._outputType); emit quitLoop(); } void run() { if( parseOptions() ) { search(); } else { help(); emit quitLoop(); } } public: typedef enum { VCard, Pretty, Template } OutputType; struct CmdOptions { QString uid; QString outputfile; OutputType _outputType; QString outTemplate; }; // Constructor, called to initialize object FindContact( const QStringList& args ) : QObject(), _args(args) { _addressProvider.reset( new AddressProvider(this) ); connect( _addressProvider.data(), SIGNAL(lookupResult(QString,KContacts::Addressee)), this, SLOT(slotAddresseeFound(QString, KContacts::Addressee))); } void help() { std::cout << std::endl; std::cout << " findcontact - search for contact data." << std::endl; std::cout << " Usage: findcontact [-o filename] uid" << std::endl; std::cout << std::endl; std::cout << " -o : dump output to filename" << std::endl; std::cout << " -c: Output format VCard." << std::endl; std::cout << " -t